SurfaceTexture
è una combinazione di una superficie e una texture OpenGL ES (GLES).
Le istanze SurfaceTexture
vengono utilizzate per fornire superfici che generano output
per le texture GLES.
SurfaceTexture
contiene un'istanza di BufferQueue
per cui le app sono il consumatore. Il callback onFrameAvailable()
notifica alle app quando il produttore mette in coda un nuovo buffer. Poi, le app chiamano
updateTexImage()
, che rilascia il buffer precedentemente mantenuto,
acquisisce il nuovo buffer dalla coda ed effettua chiamate EGL per
rendere il buffer disponibile per GLES come texture esterna.
Texture GLES esterne
Le texture GLES esterne (GL_TEXTURE_EXTERNAL_OES
) differiscono dalle
texture GLES standard (GL_TEXTURE_2D
) nei seguenti modi:
- Le texture esterne eseguono il rendering di 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 standard.
- Le texture esterne non possono eseguire tutte le attività standard 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 dei consumatori su GRALLOC_USAGE_HW_TEXTURE
quando
creano istanze BufferQueue
per le texture esterne per verificare che
i dati nel buffer siano riconoscibili da GLES.
Poiché le istanze di SurfaceTexture
interagiscono con un contesto EGL,
un'app può chiamare i relativi metodi solo se il contesto EGL proprietario della texture
è attuale sul thread chiamante. Per saperne di più, consulta 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 sia la matrice
di trasformazione. Ogni buffer che BufferQueue
passa 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, inviali nel loro orientamento con una trasformazione che lo corregga. La matrice di trasformazione può essere unita ad altre trasformazioni quando vengono utilizzati i dati, riducendo al minimo l'overhead.
Il timestamp è utile per le origini buffer che dipendono dal tempo. Ad esempio, quando setPreviewTexture()
collega l'interfaccia del produttore all'output della videocamera, i frame della videocamera possono essere utilizzati per creare un video. Ogni frame deve avere un timestamp di presentazione del momento in cui è stato acquisito, non del momento in cui l'app lo ha ricevuto. Il codice della videocamera imposta
il timestamp fornito con il buffer, ottenendo una serie più coerente
di timestamp.
Case study: acquisizione continua di Grafika
L'acquisizione continua di Grafika prevede la registrazione di frame dalla
fotocamera di un dispositivo e la visualizzazione di questi frame sullo schermo. Per registrare i frame,
crea una superficie con il metodo createInputSurface()
della classe MediaCodec
e passala alla videocamera. Per visualizzare i frame, crea un'istanza di
SurfaceView
e passa la superficie a setPreviewDisplay()
.
Tieni presente che registrare i fotogrammi e visualizzarli contemporaneamente è un processo più complesso.
L'attività acquisizione continua mostra il video della videocamera durante la registrazione. 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 prevede tre code buffer:
App
: l'app utilizza un'istanzaSurfaceTexture
per ricevere i frame dalla videocamera, 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
videocamera. Vengono mostrate BufferQueue
istanze, con indicatori visivi
che distinguono i produttori (verde acqua) dai consumatori (verde).

Figura 1. Attività di acquisizione continua di Grafika
Il video codificato in H.264 viene inserito 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 sul disco.
Tutte le istanze BufferQueue
vengono gestite con un unico contesto EGL
nell'app, mentre le operazioni GLES vengono eseguite sul thread UI. La
gestione dei dati codificati (gestione di un buffer circolare e scrittura su disco) viene
eseguita su un thread separato.
Quando utilizzi la classe 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 il frame disponibile come texture GLES.
- Esegue il rendering del frame con i comandi GLES.
- Inoltra la trasformazione e il timestamp per ogni istanza di
EGLSurface
.
Il thread dell'encoder estrae quindi l'output codificato da MediaCodec
e lo memorizza.
Riproduzione video con texture sicura
Android supporta la post-elaborazione della GPU dei contenuti video protetti. In questo modo, le app possono utilizzare la GPU per effetti video complessi e non lineari (ad esempio, distorsioni), mappare contenuti video protetti su texture da utilizzare in scene grafiche generali (ad esempio, utilizzando GLES) e nella realtà virtuale.

Figura 2. Riproduzione video con texture sicura
Il supporto è abilitato utilizzando le due estensioni seguenti:
- Estensione EGL: (
EGL_EXT_protected_content
) consente la creazione di contesti e superfici GL protetti, che possono entrambi operare su contenuti protetti. - Estensione GLES: (
GL_EXT_protected_textures
) Consente di taggare le texture come protette in modo che possano essere utilizzate come allegati delle texture del framebuffer.
Android consente a SurfaceTexture
e ACodec
(libstagefright.so
) di inviare contenuti protetti anche se la superficie
della finestra non viene messa in coda a SurfaceFlinger
e fornisce una superficie
video protetta da utilizzare in un contesto protetto. Ciò avviene impostando il
bit di consumatore protetto (GRALLOC_USAGE_PROTECTED
) sulle piattaforme
create in un contesto protetto (verificato da ACodec).
La riproduzione sicura dei video con texture pone le basi per una solida implementazione del Digital Rights Management (DRM) nell'ambiente OpenGL ES. Senza una solida implementazione di DRM, come Widevine Livello 1, molti fornitori di contenuti non consentono il rendering dei loro contenuti di alto valore nell'ambiente OpenGL ES, impedendo importanti casi d'uso della VR, come la visione di contenuti protetti da DRM in VR.
Android Open Source Project (AOSP) include il codice del framework per la riproduzione sicura
di video con texture. Il supporto dei driver dipende dagli OEM. Gli implementatori di dispositivi devono
implementare le estensioni EGL_EXT_protected_content
e
GL_EXT_protected_textures
. Quando utilizzi la tua libreria di codec (per sostituire libstagefright
), tieni presente le modifiche apportate a
/frameworks/av/media/libstagefright/SurfaceUtils.cpp
che consentono
l'invio dei buffer contrassegnati con GRALLOC_USAGE_PROTECTED
a
ANativeWindow
(anche se ANativeWindow
non accoda
direttamente al compositore di finestre) purché i bit di utilizzo del consumer contengano
GRALLOC_USAGE_PROTECTED
. Per la documentazione dettagliata sull'implementazione delle estensioni, consulta i registri Khronos (
EGL_EXT_protected_content
) e (
GL_EXT_protected_textures
).