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 der Konsument sind. Der onFrameAvailable()
-Rückruf benachrichtigt Apps, wenn der Produzent einen neuen Puffer in die Warteschlange stellt. Anschließend rufen Apps updateTexImage()
auf, das den zuvor gehaltenen Puffer freigibt, den neuen Puffer aus der Warteschlange abruft und EGL- Aufrufe durchführt, um den Puffer GLES als externe Textur zur Verfügung zu stellen.
Externe GLES-Texturen
Externe GLES-Texturen ( GL_TEXTURE_EXTERNAL_OES
) unterscheiden sich von herkömmlichen GLES-Texturen ( GL_TEXTURE_2D
) auf folgende Weise:
- Externe Texturen rendern texturierte Polygone direkt aus den von
BufferQueue
empfangenen Daten. - Externe Textur-Renderer werden anders konfiguriert als herkömmliche GLES-Textur-Renderer.
- Externe Texturen können nicht alle herkömmlichen GLES-Texturaktivitäten ausführen.
Der Hauptvorteil externer Texturen ist ihre Fähigkeit, direkt aus BufferQueue
-Daten zu rendern. SurfaceTexture
Instanzen setzen die Consumer-Nutzungsflags auf GRALLOC_USAGE_HW_TEXTURE
, wenn BufferQueue
Instanzen für externe Texturen erstellt werden, um sicherzustellen, dass die Daten im Puffer für GLES erkennbar sind.
Da SurfaceTexture
Instanzen mit einem EGL-Kontext interagieren, kann eine App ihre Methoden nur aufrufen, während der EGL-Kontext, der die Textur besitzt, im aufrufenden Thread aktuell ist. Weitere Informationen finden Sie in der Dokumentation der SurfaceTexture
Klasse.
Zeitstempel und Transformationen
SurfaceTexture
Instanzen umfassen die Methode getTimeStamp()
, die einen Zeitstempel abruft, und die Methode getTransformMatrix()
, die eine Transformationsmatrix abruft. Der Aufruf von updateTexImage()
legt sowohl den Zeitstempel als auch die Transformationsmatrix fest. Jeder Puffer, den BufferQueue
übergibt, enthält Transformationsparameter und einen Zeitstempel.
Transformationsparameter sind für die Effizienz nützlich. In manchen Fällen sind die Quelldaten für den Verbraucher möglicherweise falsch ausgerichtet. Anstatt die Daten vor dem Senden an den Verbraucher zu rotieren, senden Sie die Daten in ihrer Ausrichtung mit einer Transformation, die sie korrigiert. Die Transformationsmatrix kann bei Verwendung der Daten mit anderen Transformationen zusammengeführt werden, wodurch der Overhead minimiert wird.
Der Zeitstempel ist für Pufferquellen nützlich, die zeitabhängig sind. Wenn beispielsweise setPreviewTexture()
die Producer-Schnittstelle mit dem Ausgang der Kamera verbindet, können Frames von der Kamera zum Erstellen eines Videos verwendet werden. Jeder Frame muss über einen Präsentationszeitstempel ab dem Zeitpunkt der Aufnahme des Frames verfügen, nicht ab dem Zeitpunkt, an dem 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: Grafikas kontinuierliche Erfassung
Bei der kontinuierlichen Erfassung durch Grafika werden Bilder von der Kamera eines Geräts aufgezeichnet und auf dem Bildschirm angezeigt. Um Frames aufzuzeichnen, erstellen Sie eine Oberfläche mit der Methode createInputSurface()
der MediaCodec- Klasse 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()
. Beachten Sie, dass das Aufzeichnen von Frames und deren gleichzeitige Anzeige ein aufwändigerer Prozess ist.
Die Aktivität „Kontinuierliche Aufnahme“ zeigt das Video von der Kamera an, während das Video aufgezeichnet wird. In diesem Fall wird das codierte Video in einen Ringpuffer im Speicher 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 sie in eine externe GLES-Textur umzuwandeln. -
SurfaceFlinger
– Die App deklariert eineSurfaceView
Instanz zum Anzeigen der Frames. -
MediaServer
– Konfigurieren Sie einenMediaCodec
Encoder mit einer Eingabeoberfläche, um das Video zu erstellen.
In der Abbildung unten zeigen die Pfeile die Datenausbreitung von der Kamera an. BufferQueue
Instanzen sind farbig (Produzenten sind blaugrün, Verbraucher sind grün).
Kodiertes H.264-Video wird im App-Prozess in einen Ringpuffer im RAM verschoben. Wenn ein Benutzer die Aufnahmetaste drückt, schreibt die MediaMuxer
Klasse das codierte Video in eine MP4-Datei auf der Festplatte.
Alle BufferQueue
Instanzen werden mit einem einzigen EGL-Kontext in der App verarbeitet, während die GLES-Vorgänge im UI-Thread ausgeführt werden. Die Verarbeitung codierter Daten (Verwaltung eines Ringpuffers und Schreiben auf die Festplatte) erfolgt in einem separaten Thread.
SurfaceView
Klasse erstellt der surfaceCreated()
-Rückruf die EGLContext
und EGLSurface
Instanzen für die Anzeige und den Video-Encoder. Wenn ein neuer Frame eintrifft, führt SurfaceTexture
vier Aktivitäten aus:- Erwirbt den Rahmen.
- Stellt den Rahmen als GLES-Textur zur Verfügung.
- Rendert den Frame mit GLES-Befehlen.
- Leitet die Transformation und den Zeitstempel für jede Instanz von
EGLSurface
weiter.
Der Encoder-Thread ruft dann die codierte Ausgabe von MediaCodec
ab und speichert sie im Speicher.
Sichere Wiedergabe von Texturvideos
Android unterstützt die GPU-Nachbearbeitung geschützter Videoinhalte. Dadurch können Apps die GPU für komplexe, nichtlineare Videoeffekte (z. B. Warps) nutzen und geschützte Videoinhalte auf Texturen abbilden, um sie in allgemeinen Grafikszenen (z. B. mit GLES) und in der virtuellen Realität (VR) zu verwenden.
Der Support wird über die folgenden zwei Erweiterungen aktiviert:
- EGL-Erweiterung – (
EGL_EXT_protected_content
) Ermöglicht die Erstellung geschützter GL-Kontexte und -Oberflächen, die beide mit geschützten Inhalten arbeiten können. - GLES-Erweiterung – (
GL_EXT_protected_textures
) Ermöglicht das Markieren von Texturen als geschützt, sodass sie als Framebuffer-Texturanhänge verwendet werden können.
Android ermöglicht SurfaceTexture
und ACodec ( libstagefright.so
), geschützte Inhalte zu senden, auch wenn die Oberfläche des Fensters nicht in der Warteschlange von SurfaceFlinger
steht, und stellt eine geschützte Videooberfläche zur Verwendung in einem geschützten Kontext bereit. Dies erfolgt durch Setzen des geschützten Verbraucherbits ( GRALLOC_USAGE_PROTECTED
) auf Oberflächen, die in einem geschützten Kontext erstellt wurden (von ACodec überprüft).
Die sichere Wiedergabe von Texturvideos bildet die Grundlage für eine starke DRM-Implementierung in der OpenGL ES-Umgebung. Ohne eine starke DRM-Implementierung wie Widevine Level 1 gestatten viele Inhaltsanbieter das Rendern ihrer hochwertigen Inhalte in der OpenGL ES-Umgebung nicht, wodurch wichtige VR-Anwendungsfälle wie das Ansehen von DRM-geschützten Inhalten in VR verhindert werden.
AOSP enthält Framework-Code für die sichere Wiedergabe von Texturvideos. Die Treiberunterstützung liegt bei den OEMs. Geräteimplementierer müssen die Erweiterungen EGL_EXT_protected_content
und GL_EXT_protected_textures extensions
implementieren. Wenn Sie Ihre eigene Codec-Bibliothek verwenden (als Ersatz für libstagefright
), 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 Warteschlange gestellt wird). Window Composer), solange die Verbrauchernutzungsbits GRALLOC_USAGE_PROTECTED
enthalten. Eine ausführliche Dokumentation zur Implementierung der Erweiterungen finden Sie in den Khronos-Registrierungen ( EGL_EXT_protected_content
und GL_EXT_protected_textures
).