SurfaceTexture ist eine Kombination aus einer Oberfläche und einer OpenGL ES (GLES)-Textur.
SurfaceTexture-Instanzen werden verwendet, um Oberflächen bereitzustellen, die in GLES-Texturen ausgegeben werden.
SurfaceTexture enthält eine Instanz von BufferQueue, für die Apps die Verbraucher sind. Der onFrameAvailable()-Callback benachrichtigt Apps, wenn der Producer einen neuen Puffer in die Warteschlange stellt. Anschließend rufen Apps updateTexImage() auf. Dadurch wird der zuvor gehaltene Puffer freigegeben, der neue Puffer aus der Warteschlange abgerufen und EGL-Aufrufe ausgeführt, um den Puffer für GLES als externe Textur verfügbar zu machen.
Externe GLES-Texturen
Externe GLES-Texturen (GL_TEXTURE_EXTERNAL_OES) unterscheiden sich in den folgenden Punkten von Standard-GLES-Texturen (GL_TEXTURE_2D):
- Externe Texturen rendern strukturierte Polygone direkt aus Daten, die von
BufferQueueempfangen werden. - Externe Texture-Renderer werden anders konfiguriert als Standard-GLES-Texture-Renderer.
- Mit externen Texturen können nicht alle standardmäßigen GLES-Texturaktivitäten ausgeführt werden.
Der Hauptvorteil externer Texturen besteht darin, dass sie direkt aus BufferQueue-Daten gerendert werden können. SurfaceTexture-Instanzen legen die Flags für die Verbrauchernutzung auf GRALLOC_USAGE_HW_TEXTURE fest, wenn sie BufferQueue-Instanzen für externe Texturen erstellen, um zu prüfen, ob die Daten im Puffer von GLES erkannt werden.
Da SurfaceTexture-Instanzen mit einem EGL-Kontext interagieren, kann eine App ihre Methoden nur aufrufen, wenn der EGL-Kontext, zu dem die Textur gehört, im aufrufenden Thread aktuell ist. Weitere Informationen finden Sie in der Dokumentation zur Klasse
SurfaceTexture.
Zeitstempel und Transformationen
SurfaceTexture-Instanzen enthalten die Methode getTimeStamp(), mit der ein Zeitstempel abgerufen wird, und die Methode getTransformMatrix(), mit der eine Transformationsmatrix abgerufen wird. Durch Aufrufen von updateTexImage() werden sowohl der Zeitstempel als auch die Transformationsmatrix festgelegt. Jeder Puffer, der von BufferQueue übergeben wird, enthält Transformationsparameter und einen Zeitstempel.
Transformationsparameter sind für die Effizienz nützlich. In einigen Fällen sind die Quelldaten möglicherweise nicht richtig ausgerichtet. Senden Sie die Daten in ihrer Ausrichtung mit einer Transformation, die sie korrigiert, anstatt sie vor dem Senden an den Consumer zu drehen. Die Transformationsmatrix kann mit anderen Transformationen zusammengeführt werden, wenn die Daten verwendet werden. So wird der Aufwand minimiert.
Der Zeitstempel ist nützlich für Pufferquellen, die zeitabhängig sind. Wenn setPreviewTexture() beispielsweise die Producer-Schnittstelle mit der Ausgabe der Kamera verbindet, können Frames von der Kamera verwendet werden, um ein Video zu erstellen. Jeder Frame muss einen Präsentationszeitstempel enthalten, der angibt, wann der Frame aufgenommen wurde, nicht wann die App den Frame empfangen hat. Der Kameracode legt den mit dem Puffer bereitgestellten Zeitstempel fest, was zu einer konsistenteren Reihe von Zeitstempeln führt.
Fallstudie: Kontinuierliche Erfassung von Grafika
Kontinuierliche Aufnahme von Grafika: Dabei werden Frames von der Kamera eines Geräts aufgenommen und auf dem Bildschirm angezeigt. Wenn Sie Frames aufzeichnen möchten, erstellen Sie eine Oberfläche mit der Methode createInputSurface() der Klasse
MediaCodec und übergeben Sie die Oberfläche an die Kamera. Um Frames anzuzeigen, erstellen Sie eine Instanz von SurfaceView und übergeben Sie die Oberfläche an setPreviewDisplay().
Das Aufzeichnen und gleichzeitige Anzeigen von Frames ist ein komplexerer Prozess.
Bei der Aktivität Lückenlose Aufnahme wird das Video der Kamera während der Aufnahme angezeigt. In diesem Fall wird das codierte Video in einen Ringpuffer im Arbeitsspeicher geschrieben, der jederzeit auf der Festplatte gespeichert werden kann.
Dieser Ablauf umfasst drei Pufferwarteschlangen:
App: Die App verwendet eineSurfaceTexture-Instanz, um Frames von der Kamera zu empfangen und in eine externe GLES-Textur zu konvertieren.SurfaceFlinger: Die App deklariert eineSurfaceView-Instanz, um die Frames anzuzeigen.MediaServer– Konfigurieren Sie einenMediaCodec-Encoder mit einer Eingabeoberfläche, um das Video zu erstellen.
In der folgenden Abbildung geben die Pfeile die Datenübertragung von der Kamera an. Es werden BufferQueue-Instanzen mit visuellen Indikatoren angezeigt, die Ersteller (blaugrün) von Nutzern (grün) unterscheiden.
Abbildung 1: Kontinuierliche Aufnahmeaktivität von Grafika
Das codierte H.264-Video wird in einem zirkulären Puffer im RAM im App-Prozess gespeichert.
Wenn ein Nutzer auf die Aufnahmeschaltfläche drückt, schreibt die Klasse MediaMuxer das codierte Video in eine MP4-Datei auf der Festplatte.
Alle BufferQueue-Instanzen werden in der App mit einem einzigen EGL-Kontext verarbeitet, während die GLES-Vorgänge im UI-Thread ausgeführt werden. Die Verarbeitung codierter Daten (Verwaltung eines zirkulären Puffers und Schreiben auf die Festplatte) erfolgt in einem separaten Thread.
Bei Verwendung der SurfaceView-Klasse werden mit dem surfaceCreated()-Callback die EGLContext- und EGLSurface-Instanzen für die Anzeige und den Video-Encoder erstellt. Wenn ein neuer Frame eingeht, führt SurfaceTexture vier Aktionen aus:
- Ruft den Frame ab.
- Macht den Frame als GLES-Textur verfügbar.
- Rendert den Frame mit GLES-Befehlen.
- Leitet die Transformation und den Zeitstempel für jede Instanz von
EGLSurfaceweiter.
Der Encoder-Thread ruft dann die codierte Ausgabe aus MediaCodec ab und speichert sie im Arbeitsspeicher.
Sichere Wiedergabe von Texturvideos
Android unterstützt die GPU-Nachbearbeitung von geschützten Videoinhalten. So können Apps die GPU für komplexe, nicht lineare Videoeffekte (z. B. Warping), das Zuordnen von geschützten Videoinhalten zu Texturen für die Verwendung in allgemeinen Grafikszenen (z. B. mit GLES) und Virtual Reality (VR) nutzen.
Abbildung 2: Sichere Wiedergabe von Texturvideos
Die Unterstützung wird durch die folgenden beiden Erweiterungen aktiviert:
- EGL-Erweiterung – (
EGL_EXT_protected_content) Ermöglicht die Erstellung von geschützten GL-Kontexten und -Oberflächen, die beide mit geschützten Inhalten arbeiten können. - GLES-Erweiterung – (
GL_EXT_protected_textures) Ermöglicht das Taggen von Texturen als geschützt, damit sie als Framebuffer-Textur-Attachments verwendet werden können.
Unter Android können SurfaceTexture und ACodec(libstagefright.so) geschützte Inhalte senden, auch wenn die Oberfläche des Fensters nicht in die Warteschlange von SurfaceFlinger eingereiht wird. Außerdem wird eine geschützte Videooberfläche für die Verwendung in einem geschützten Kontext bereitgestellt. Dazu wird das Bit für geschützte Verbraucher (GRALLOC_USAGE_PROTECTED) auf Oberflächen gesetzt, die in einem geschützten Kontext erstellt wurden (von ACodec überprüft).
Die sichere Wiedergabe von Texturvideos bildet die Grundlage für eine starke Implementierung der digitalen Rechteverwaltung (Digital Rights Management, DRM) in der OpenGL ES-Umgebung. Ohne eine starke DRM-Implementierung wie Widevine Level 1 erlauben viele Contentanbieter nicht das Rendern ihrer hochwertigen Inhalte in der OpenGL ES-Umgebung. Dadurch werden wichtige VR-Anwendungsfälle wie das Ansehen von DRM-geschützten Inhalten in VR verhindert.
Das Open-Source-Projekt für Android (AOSP) enthält Framework-Code für die sichere Wiedergabe von Texturvideos. Der Treibersupport liegt in der Verantwortung der OEMs. Gerätehersteller müssen die Erweiterungen EGL_EXT_protected_content und GL_EXT_protected_textures implementieren. Wenn Sie Ihre eigene Codec-Bibliothek verwenden (um libstagefright zu ersetzen), beachten Sie die Änderungen in /frameworks/av/media/libstagefright/SurfaceUtils.cpp, die es ermöglichen, mit GRALLOC_USAGE_PROTECTED markierte Puffer an ANativeWindow zu senden (auch wenn ANativeWindow nicht direkt in die Fensterkomposition eingereiht wird), solange die Consumer-Nutzungsbits GRALLOC_USAGE_PROTECTED enthalten. Eine detaillierte Dokumentation zur Implementierung der Erweiterungen finden Sie in den Khronos-Registrierungen (
EGL_EXT_protected_content) und (
GL_EXT_protected_textures).