SurfaceTexture
es una combinación de una superficie y una textura OpenGL ES (GLES) . Las instancias SurfaceTexture
se utilizan para proporcionar superficies que generan texturas GLES.
SurfaceTexture
contiene una instancia de BufferQueue
cuyas aplicaciones son el consumidor. La devolución de llamada onFrameAvailable()
notifica a las aplicaciones cuando el productor pone en cola un nuevo búfer. Luego, las aplicaciones llaman a updateTexImage()
, que libera el búfer retenido anteriormente, adquiere el nuevo búfer de la cola y realiza llamadas EGL para que el búfer esté disponible para GLES como una textura externa.
Texturas GLES externas
Las texturas GLES externas ( GL_TEXTURE_EXTERNAL_OES
) se diferencian de las texturas GLES tradicionales ( GL_TEXTURE_2D
) de las siguientes maneras:
- Las texturas externas representan polígonos texturizados directamente a partir de datos recibidos de
BufferQueue
. - Los renderizadores de texturas externos están configurados de manera diferente a los renderizadores de texturas GLES tradicionales.
- Las texturas externas no pueden realizar todas las actividades de texturas tradicionales de GLES.
El principal beneficio de las texturas externas es su capacidad de renderizar directamente a partir de datos BufferQueue
. Las instancias SurfaceTexture
establecen los indicadores de uso del consumidor en GRALLOC_USAGE_HW_TEXTURE
cuando crea instancias BufferQueue
para texturas externas para garantizar que GLES reconozca los datos en el búfer.
Debido a que las instancias SurfaceTexture
interactúan con un contexto EGL, una aplicación solo puede llamar a sus métodos mientras el contexto EGL propietario de la textura esté actual en el subproceso que realiza la llamada. Para obtener más información, consulte la documentación de la clase SurfaceTexture
.
Marcas de tiempo y transformaciones
Las instancias SurfaceTexture
incluyen el método getTimeStamp()
, que recupera una marca de tiempo, y el método getTransformMatrix()
, que recupera una matriz de transformación. Llamar a updateTexImage()
establece tanto la marca de tiempo como la matriz de transformación. Cada búfer que pasa BufferQueue
incluye parámetros de transformación y una marca de tiempo.
Los parámetros de transformación son útiles para la eficiencia. En algunos casos, los datos de origen pueden tener una orientación incorrecta para el consumidor. En lugar de rotar los datos antes de enviarlos al consumidor, envíelos en su orientación con una transformación que los corrija. La matriz de transformación se puede fusionar con otras transformaciones cuando se utilizan los datos, minimizando la sobrecarga.
La marca de tiempo es útil para fuentes de búfer que dependen del tiempo. Por ejemplo, cuando setPreviewTexture()
conecta la interfaz del productor a la salida de la cámara, los cuadros de la cámara se pueden usar para crear un video. Cada fotograma debe tener una marca de tiempo de presentación desde el momento en que se capturó el fotograma, no desde el momento en que la aplicación lo recibió. El código de la cámara establece la marca de tiempo proporcionada con el búfer, lo que da como resultado una serie de marcas de tiempo más consistente.
Estudio de caso: captura continua de Grafika
La captura continua de Grafika implica grabar fotogramas de la cámara de un dispositivo y mostrarlos en la pantalla. Para grabar fotogramas, cree una superficie con el método createInputSurface()
de la clase MediaCodec y pase la superficie a la cámara. Para mostrar marcos, cree una instancia de SurfaceView
y pase la superficie a setPreviewDisplay()
. Tenga en cuenta que grabar fotogramas y mostrarlos al mismo tiempo es un proceso más complicado.
La actividad de captura continua muestra el vídeo de la cámara a medida que se graba el vídeo. En este caso, el vídeo codificado se escribe en un búfer circular en la memoria que se puede guardar en el disco en cualquier momento.
Este flujo implica tres colas de búfer:
-
App
: la aplicación utiliza una instanciaSurfaceTexture
para recibir fotogramas de la cámara y convertirlos en una textura GLES externa. -
SurfaceFlinger
: la aplicación declara una instanciaSurfaceView
para mostrar los marcos. -
MediaServer
: configure un codificadorMediaCodec
con una superficie de entrada para crear el vídeo.
En la siguiente figura, las flechas indican la propagación de datos desde la cámara. Las instancias BufferQueue
están en color (los productores son verde azulado, los consumidores son verdes).
El video codificado H.264 va a un búfer circular en la RAM durante el proceso de la aplicación. Cuando un usuario presiona el botón de captura, la clase MediaMuxer
escribe el video codificado en un archivo MP4 en el disco.
Todas las instancias BufferQueue
se manejan con un único contexto EGL en la aplicación mientras las operaciones GLES se realizan en el subproceso de la interfaz de usuario. El manejo de datos codificados (administrar un búfer circular y escribirlo en el disco) se realiza en un hilo separado.
SurfaceView
, la devolución de llamada surfaceCreated()
crea las instancias EGLContext
y EGLSurface
para la pantalla y el codificador de vídeo. Cuando llega un nuevo cuadro, SurfaceTexture
realiza cuatro actividades:- Adquiere el marco.
- Hace que el marco esté disponible como textura GLES.
- Representa el marco con comandos GLES.
- Reenvía la transformación y la marca de tiempo para cada instancia de
EGLSurface
.
Luego, el hilo del codificador extrae la salida codificada de MediaCodec
y la guarda en la memoria.
Reproducción segura de vídeo de textura
Android admite el posprocesamiento por GPU de contenido de vídeo protegido. Esto permite que las aplicaciones utilicen la GPU para efectos de vídeo complejos y no lineales (como deformaciones), mapeo de contenido de vídeo protegido en texturas para su uso en escenas gráficas generales (por ejemplo, usando GLES) y realidad virtual (VR).
El soporte se habilita mediante las siguientes dos extensiones:
- Extensión EGL : (
EGL_EXT_protected_content
) Permite la creación de contextos y superficies GL protegidos, que pueden operar en contenido protegido. - Extensión GLES : (
GL_EXT_protected_textures
) Permite etiquetar texturas como protegidas para que puedan usarse como archivos adjuntos de textura de framebuffer.
Android permite que SurfaceTexture
y ACodec ( libstagefright.so
) envíen contenido protegido incluso si la superficie de la ventana no se pone en cola para SurfaceFlinger
y proporciona una superficie de video protegida para usar dentro de un contexto protegido. Esto se hace configurando el bit de consumidor protegido ( GRALLOC_USAGE_PROTECTED
) en superficies creadas en un contexto protegido (verificado por ACodec).
La reproducción segura de vídeo de textura sienta las bases para una sólida implementación de DRM en el entorno OpenGL ES. Sin una implementación sólida de DRM, como Widevine Nivel 1, muchos proveedores de contenido no permiten la representación de su contenido de alto valor en el entorno OpenGL ES, lo que impide casos de uso importantes de la realidad virtual, como ver contenido protegido con DRM en realidad virtual.
AOSP incluye código marco para la reproducción segura de videos de texturas. La compatibilidad con los controladores depende de los OEM. Los implementadores de dispositivos deben implementar las extensiones EGL_EXT_protected_content
y GL_EXT_protected_textures extensions
. Cuando utilice su propia biblioteca de códecs (para reemplazar libstagefright
), tenga en cuenta los cambios en /frameworks/av/media/libstagefright/SurfaceUtils.cpp
que permiten que los buffers marcados con GRALLOC_USAGE_PROTECTED
se envíen a ANativeWindow
(incluso si ANativeWindow
no se pone en cola directamente al compositor de ventanas) siempre que los bits de uso del consumidor contengan GRALLOC_USAGE_PROTECTED
. Para obtener documentación detallada sobre la implementación de las extensiones, consulte los registros de Khronos ( EGL_EXT_protected_content
y GL_EXT_protected_textures
).