SurfaceTexture
es una combinación de una superficie y una textura OpenGL ES (GLES) . Las instancias de SurfaceTexture
se utilizan para proporcionar superficies que generan texturas GLES.
SurfaceTexture
contiene una instancia de BufferQueue
para la cual las 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 previamente, 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
) difieren de las texturas GLES tradicionales ( GL_TEXTURE_2D
) de las siguientes maneras:
- Las texturas externas representan polígonos texturizados directamente a partir de los datos recibidos de
BufferQueue
. - Los renderizadores de texturas externos se configuran de manera diferente a los renderizadores de texturas GLES tradicionales.
- Las texturas externas no pueden realizar todas las actividades de textura GLES tradicionales.
El principal beneficio de las texturas externas es su capacidad para renderizar directamente desde los datos de BufferQueue
. Las instancias SurfaceTexture
establecen las marcas de uso del consumidor en GRALLOC_USAGE_HW_TEXTURE
cuando crea instancias de BufferQueue
para texturas externas para garantizar que GLES reconozca los datos en el búfer.
Debido a que las instancias de SurfaceTexture
interactúan con un contexto EGL, una aplicación solo puede llamar a sus métodos mientras el contexto EGL que posee la textura está activo en el subproceso de llamada. Para obtener más información, consulte la documentación de la clase SurfaceTexture
.
Marcas de tiempo y transformaciones
Las instancias de 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 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íe los datos 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, lo que minimiza la sobrecarga.
La marca de tiempo es útil para orígenes de búfer que dependen del tiempo. Por ejemplo, cuando setPreviewTexture()
conecta la interfaz del productor a la salida de la cámara, los fotogramas de la cámara se pueden usar para crear un video. Cada cuadro debe tener una marca de tiempo de presentación de cuando se capturó el cuadro, no de cuando la aplicación recibió el cuadro. 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 coherente.
Caso de estudio: Captura continua de Grafika
La captura continua de Grafika implica grabar fotogramas de la cámara de un dispositivo y mostrar esos fotogramas 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 cuadros y mostrarlos al mismo tiempo es un proceso más complicado.
La actividad de captura continua muestra el video de la cámara a medida que se graba el video. En este caso, el video 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 instancia deSurfaceTexture
para recibir fotogramas de la cámara y convertirlos en una textura GLES externa. -
SurfaceFlinger
: la aplicación declara una instancia deSurfaceView
para mostrar los marcos. -
MediaServer
: configure un codificadorMediaCodec
con una superficie de entrada para crear el video.
En la siguiente figura, las flechas indican la propagación de datos desde la cámara. Las instancias de BufferQueue
están en color (los productores son verde azulado, los consumidores son verdes).
El video H.264 codificado va a un búfer circular en la RAM en 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 solo contexto EGL en la aplicación, mientras que 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 de surfaceCreated()
crea las instancias EGLContext
y EGLSurface
para la pantalla y el codificador de video. Cuando llega un nuevo marco, SurfaceTexture
realiza cuatro actividades:- Adquiere el marco.
- Hace que el marco esté disponible como una textura GLES.
- Renderiza 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 de video de textura segura
Android admite el procesamiento posterior de GPU de contenido de video protegido. Esto permite que las aplicaciones usen la GPU para efectos de video complejos y no lineales (como deformaciones), asignando contenido de video protegido a texturas para usar en escenas gráficas generales (por ejemplo, usando GLES) y realidad virtual (VR).
El soporte está habilitado usando las siguientes dos extensiones:
- Extensión EGL : (
EGL_EXT_protected_content
) Permite la creación de contextos y superficies de 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 habilita SurfaceTexture
y ACodec ( libstagefright.so
) para enviar 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 video con 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 Level 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 VR, como ver contenido protegido por DRM en VR.
AOSP incluye código de marco para la reproducción segura de video de textura. El soporte del controlador 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 búferes marcados con GRALLOC_USAGE_PROTECTED
se envíen a ANativeWindow
(incluso si ANativeWindow
no se pone en cola directamente al window composer) 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
).