SurfaceTexture
è una combinazione di una superficie e di una texture OpenGL ES (GLES) . Le istanze SurfaceTexture
vengono utilizzate per fornire superfici da restituire alle texture GLES.
SurfaceTexture
contiene un'istanza di BufferQueue
di cui le app sono il consumatore. Il callback onFrameAvailable()
notifica alle app quando il produttore mette in coda un nuovo buffer. Quindi, le app chiamano updateTexImage()
, che rilascia il buffer precedentemente trattenuto, acquisisce il nuovo buffer dalla coda ed effettua chiamate EGL per rendere il buffer disponibile a GLES come texture esterna.
Texture GLES esterne
Le texture GLES esterne ( GL_TEXTURE_EXTERNAL_OES
) differiscono dalle texture GLES tradizionali ( GL_TEXTURE_2D
) nei seguenti modi:
- Le texture esterne eseguono il rendering dei poligoni con texture direttamente dai dati ricevuti da
BufferQueue
. - I renderer di texture esterni sono configurati in modo diverso rispetto ai renderer di texture GLES tradizionali.
- Le texture esterne non possono eseguire tutte le tradizionali attività delle texture GLES.
Il vantaggio principale delle texture esterne è la loro capacità di eseguire il rendering direttamente dai dati BufferQueue
. Le istanze SurfaceTexture
impostano i flag di utilizzo del consumatore su GRALLOC_USAGE_HW_TEXTURE
quando crea istanze BufferQueue
per texture esterne per garantire che i dati nel buffer siano riconoscibili da GLES.
Poiché le istanze SurfaceTexture
interagiscono con un contesto EGL, un'app può chiamare i relativi metodi solo mentre il contesto EGL che possiede la texture è corrente nel thread chiamante. Per ulteriori informazioni vedere la documentazione della classe SurfaceTexture
.
Timestamp e trasformazioni
Le istanze SurfaceTexture
includono il metodo getTimeStamp()
, che recupera un timestamp, e il metodo getTransformMatrix()
, che recupera una matrice di trasformazione. La chiamata updateTexImage()
imposta sia il timestamp che la matrice di trasformazione. Ogni buffer passato BufferQueue
include parametri di trasformazione e un timestamp.
I parametri di trasformazione sono utili per l'efficienza. In alcuni casi, i dati di origine potrebbero avere un orientamento errato per il consumatore. Invece di ruotare i dati prima di inviarli al consumatore, invia i dati nel loro orientamento con una trasformazione che li corregge. La matrice di trasformazione può essere unita ad altre trasformazioni quando vengono utilizzati i dati, riducendo al minimo il sovraccarico.
Il timestamp è utile per le origini buffer che dipendono dal tempo. Ad esempio, quando setPreviewTexture()
collega l'interfaccia del produttore all'output della fotocamera, i fotogrammi della fotocamera possono essere utilizzati per creare un video. Ogni fotogramma deve avere un timestamp della presentazione da quando è stato acquisito il fotogramma, non da quando l'app ha ricevuto il fotogramma. Il codice della fotocamera imposta il timestamp fornito con il buffer, risultando in una serie di timestamp più coerente.
Caso di studio: la cattura continua di Grafika
L'acquisizione continua di Grafika prevede la registrazione di fotogrammi dalla fotocamera di un dispositivo e la visualizzazione di tali fotogrammi sullo schermo. Per registrare i fotogrammi, crea una superficie con il metodo createInputSurface()
della classe MediaCodec e passa la superficie alla fotocamera. Per visualizzare i fotogrammi, crea un'istanza di SurfaceView
e passa la superficie a setPreviewDisplay()
. Tieni presente che registrare i fotogrammi e visualizzarli contemporaneamente è un processo più complicato.
L'attività di acquisizione continua visualizza il video dalla telecamera mentre il video viene registrato. In questo caso, il video codificato viene scritto in un buffer circolare in memoria che può essere salvato su disco in qualsiasi momento.
Questo flusso coinvolge tre code di buffer:
-
App
: l'app utilizza un'istanzaSurfaceTexture
per ricevere fotogrammi dalla fotocamera, convertendoli in una texture GLES esterna. -
SurfaceFlinger
: l'app dichiara un'istanzaSurfaceView
per visualizzare i frame. -
MediaServer
: configura un codificatoreMediaCodec
con una superficie di input per creare il video.
Nella figura seguente, le frecce indicano la propagazione dei dati dalla telecamera. Le istanze BufferQueue
sono a colori (i produttori sono verde acqua, i consumatori sono verdi).
Il video H.264 codificato va in un buffer circolare nella RAM nel processo dell'app. Quando un utente preme il pulsante di acquisizione, la classe MediaMuxer
scrive il video codificato in un file MP4 su disco.
Tutte le istanze BufferQueue
vengono gestite con un singolo contesto EGL nell'app mentre le operazioni GLES vengono eseguite sul thread dell'interfaccia utente. La gestione dei dati codificati (gestione di un buffer circolare e scrittura su disco) viene eseguita su un thread separato.
SurfaceView
, il callback surfaceCreated()
crea le istanze EGLContext
e EGLSurface
per il display e il codificatore video. Quando arriva un nuovo frame, SurfaceTexture
esegue quattro attività:- Acquisisce il frame.
- Rende la cornice disponibile come texture GLES.
- Renderizza il frame con i comandi GLES.
- Inoltra la trasformazione e il timestamp per ogni istanza di
EGLSurface
.
Il thread del codificatore quindi estrae l'output codificato da MediaCodec
e lo memorizza.
Riproduzione video sicura delle texture
Android supporta la post-elaborazione GPU dei contenuti video protetti. Ciò consente alle app di utilizzare la GPU per effetti video complessi e non lineari (come le deformazioni), mappando i contenuti video protetti su trame da utilizzare in scene grafiche generali (ad esempio, utilizzando GLES) e realtà virtuale (VR).
Il supporto è abilitato utilizzando le due estensioni seguenti:
- Estensione EGL : (
EGL_EXT_protected_content
) Abilita la creazione di contesti e superfici GL protetti, che possono entrambi operare su contenuto protetto. - Estensione GLES — (
GL_EXT_protected_textures
) Abilita l'etichettatura delle texture come protette in modo che possano essere utilizzate come allegati texture framebuffer.
Android consente a SurfaceTexture
e ACodec ( libstagefright.so
) di inviare contenuto protetto anche se la superficie della finestra non viene accodata a SurfaceFlinger
e fornisce una superficie video protetta da utilizzare in un contesto protetto. Questo viene fatto impostando il bit consumer protetto ( GRALLOC_USAGE_PROTECTED
) su superfici create in un contesto protetto (verificato da ACodec).
La riproduzione video sicura delle texture pone le basi per una solida implementazione DRM nell'ambiente OpenGL ES. Senza una forte implementazione DRM, come Widevine Level 1, molti fornitori di contenuti non consentono il rendering dei loro contenuti di alto valore nell'ambiente OpenGL ES, impedendo importanti casi d'uso VR come la visione di contenuti protetti da DRM in VR.
AOSP include il codice framework per la riproduzione sicura di video di texture. Il supporto dei driver spetta agli OEM. Gli implementatori del dispositivo devono implementare le estensioni EGL_EXT_protected_content
e GL_EXT_protected_textures extensions
. Quando usi la tua libreria di codec (per sostituire libstagefright
), nota le modifiche in /frameworks/av/media/libstagefright/SurfaceUtils.cpp
che consentono ai buffer contrassegnati con GRALLOC_USAGE_PROTECTED
di essere inviati a ANativeWindow
(anche se ANativeWindow
non si accoda direttamente al compositore di finestre) purché i bit di utilizzo del consumatore contengano GRALLOC_USAGE_PROTECTED
. Per la documentazione dettagliata sull'implementazione delle estensioni, fare riferimento ai registri Khronos ( EGL_EXT_protected_content
e GL_EXT_protected_textures
).