Oberflächentextur

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 eine SurfaceTexture Instanz, um Frames von der Kamera zu empfangen und sie in eine externe GLES-Textur umzuwandeln.
  • SurfaceFlinger – Die App deklariert eine SurfaceView Instanz zum Anzeigen der Frames.
  • MediaServer – Konfigurieren Sie einen MediaCodec 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).

Kontinuierliche Erfassungsaktivität von Grafika

Abbildung 1. Kontinuierliche Erfassungsaktivität von Grafika

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.

Bei Verwendung der 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:
  1. Erwirbt den Rahmen.
  2. Stellt den Rahmen als GLES-Textur zur Verfügung.
  3. Rendert den Frame mit GLES-Befehlen.
  4. 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.

Sichere Wiedergabe von Texturvideos

Abbildung 2. Sichere Texturvideowiedergabe

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 ).