SurfaceTexture

SurfaceTexture es una combinación de una superficie y una textura de OpenGL ES (GLES). Las instancias de SurfaceTexture se usan para proporcionar superficies que generan texturas de GLES.

SurfaceTexture contiene una instancia de BufferQueue para la que las apps son el consumidor. La devolución de llamada de onFrameAvailable() notifica a las apps cuando el productor pone en cola un búfer nuevo. Luego, las apps llaman a updateTexImage(), que libera el búfer que se había mantenido, adquiere el nuevo búfer de la cola y realiza llamadas a 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 estándar (GL_TEXTURE_2D) de las siguientes maneras:

  • Las texturas externas renderizan 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 estándar.
  • Las texturas externas no pueden realizar todas las actividades estándar de texturas de GLES.

El principal beneficio de las texturas externas es su capacidad de renderizar directamente desde datos de BufferQueue. Las instancias de SurfaceTexture establecen las marcas de uso del consumidor en GRALLOC_USAGE_HW_TEXTURE cuando crean instancias de BufferQueue para texturas externas, con el objetivo de verificar que GLES pueda reconocer los datos del búfer.

Debido a que las instancias de SurfaceTexture interactúan con un contexto de EGL, una app solo puede llamar a sus métodos mientras el contexto de EGL que posee la textura sea actual en el subproceso de llamada. Para obtener más información, consulta 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. Cuando se llama a updateTexImage(), se establecen 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íalos en su orientación con una transformación que los corrija. La matriz de transformación se puede combinar con otras transformaciones cuando se usan los datos, lo que minimiza la sobrecarga.

La marca de tiempo es útil para las fuentes de búfer que dependen del tiempo. Por ejemplo, cuando setPreviewTexture() conecta la interfaz del productor a la salida de la cámara, se pueden usar los fotogramas de la cámara para crear un video. Cada fotograma debe tener una marca de tiempo de presentación del momento en que se capturó, no del momento en que la app lo recibió. El código de la cámara establece la marca de tiempo proporcionada con el búfer, lo que genera una serie más coherente de marcas de tiempo.

Caso de éxito: Captura continua de Grafika

La captura continua de Grafika implica grabar fotogramas desde la cámara de un dispositivo y mostrarlos en la pantalla. Para grabar fotogramas, crea una superficie con el método createInputSurface() de la clase MediaCodec y pasa la superficie a la cámara. Para mostrar fotogramas, crea una instancia de SurfaceView y pasa la superficie a setPreviewDisplay(). Ten en cuenta que grabar fotogramas y mostrarlos al mismo tiempo es un proceso más complejo.

La actividad de captura continua muestra el video de la cámara mientras se graba. 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 incluye tres colas de búfer:

  • App: La app usa una instancia de SurfaceTexture para recibir fotogramas de la cámara y convertirlos en una textura GLES externa.
  • SurfaceFlinger: La app declara una instancia de SurfaceView para mostrar los fotogramas.
  • MediaServer: Configura un codificador MediaCodec 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. Se muestran instancias de BufferQueue, con indicadores visuales que distinguen a los productores (azul verdoso) de los consumidores (verde).

Actividad de captura continua de Grafika

Figura 1: Actividad de captura continua de Grafika

El video H.264 codificado se dirige a un búfer circular en la RAM en el proceso de la app. 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 de BufferQueue se controlan con un solo contexto de EGL en la app, mientras que las operaciones de GLES se realizan en el subproceso de IU. El procesamiento de los datos codificados (administración de un búfer circular y escritura en el disco) se realiza en un subproceso independiente.

Cuando se usa la clase SurfaceView, la devolución de llamada surfaceCreated() crea las instancias EGLContext y EGLSurface para la pantalla y el codificador de video. Cuando llega un nuevo fotograma, SurfaceTexture realiza cuatro actividades:

  1. Adquiere el fotograma.
  2. Hace que el fotograma esté disponible como una textura de GLES.
  3. Renderiza el fotograma con comandos de GLES.
  4. Reenvía la transformación y la marca de tiempo para cada instancia de EGLSurface.

Luego, el subproceso del codificador extrae el resultado codificado de MediaCodec y lo almacena en la memoria.

Reproducción segura de videos de texturas

Android admite el posprocesamiento de GPU del contenido de video protegido. Esto permite que las apps usen la GPU para efectos de video complejos y no lineales (como deformaciones), asignar contenido de video protegido a texturas para usar en escenas de gráficos generales (por ejemplo, con GLES) y realidad virtual (RV).

Reproducción de video con texturas segura

Figura 2: Reproducción segura de videos de texturas

La compatibilidad se habilita con las siguientes dos extensiones:

  • Extensión de EGL: (EGL_EXT_protected_content) Permite la creación de contextos y superficies de GL protegidos, que pueden operar en contenido protegido.
  • Extensión de GLES: (GL_EXT_protected_textures) Permite etiquetar texturas como protegidas para que se puedan usar como archivos adjuntos de texturas de búfer de fotogramas.

Android permite que SurfaceTexture y ACodec (libstagefright.so) envíen contenido protegido incluso si la superficie de la ventana no se pone en cola en SurfaceFlinger y proporciona una superficie de video protegida para usarla en un contexto protegido. Para ello, se configura el bit de consumidor protegido (GRALLOC_USAGE_PROTECTED) en las superficies creadas en un contexto protegido (verificado por ACodec).

La reproducción de video de texturas segura sienta las bases para una sólida implementación de la administración de derechos digitales (DRM) en el entorno de OpenGL ES. Sin una implementación sólida de DRM, como Widevine Level 1, muchos proveedores de contenido no permiten la renderización de su contenido valioso en el entorno de OpenGL ES, lo que impide casos de uso importantes de RV, como mirar contenido protegido por DRM en RV.

El Proyecto de código abierto de Android (AOSP) incluye código de framework para la reproducción segura de video con 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. Cuando uses tu propia biblioteca de códecs (para reemplazar libstagefright), ten 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 pone en cola directamente al compositor de ventanas), siempre y cuando los bits de uso del consumidor contengan GRALLOC_USAGE_PROTECTED. Para obtener documentación detallada sobre la implementación de las extensiones, consulta los registros de Khronos ( EGL_EXT_protected_content) y ( GL_EXT_protected_textures).