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 se envían a las 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 nuevo búfer. Luego, las apps llaman a updateTexImage(), que libera el búfer retenido anteriormente, adquiere el búfer nuevo 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 tradicionales (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 tradicionales.
  • Las texturas externas no pueden realizar todas las actividades de textura tradicionales de GLES.

El beneficio principal de las texturas externas es su capacidad para renderizar directamente desde los datos de BufferQueue. Las instancias de SurfaceTexture configuran las marcas de uso del consumidor en GRALLOC_USAGE_HW_TEXTURE cuando crean instancias de BufferQueue para texturas externas para garantizar que GLES reconozca 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 es 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. Llamar a updateTexImage() establece la marca de tiempo y 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 mejorar 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 desde el momento en que se capturó, no desde el 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 de marcas de tiempo más coherentes.

Caso de éxito: Captura continua de Grafika

La captura continua de Grafika implica grabar fotogramas de la cámara de un dispositivo y mostrarlos en pantalla. Para grabar fotogramas, crea una superficie con el método createInputSurface() de la clase MediaCodec y pásala a la cámara. Para mostrar marcos, 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 a medida que 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. Las instancias de BufferQueue son de color (los productores son verde azulado y los consumidores son verdes).

Actividad de captura continua de Grafika

Figura 1: Actividad de captura continua de Grafika

El video H.264 codificado se envía a un búfer circular en la RAM del 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 la IU. El manejo de los datos codificados (administrar un búfer circular y escribirlo 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 marco, SurfaceTexture realiza cuatro actividades:
  1. Adquiere el fotograma.
  2. Pone el marco a disposición como una textura GLES.
  3. Renderiza la trama con comandos 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 de video de textura segura

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

Reproducción de video de texturas segura

Figura 2: Reproducción de video de textura segura

La compatibilidad se habilita con las siguientes dos extensiones:

  • Extensión de EGL: (EGL_EXT_protected_content) Habilita 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 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 en SurfaceFlinger y proporciona una superficie de video protegida para usar en un contexto protegido. Para ello, se configura el bit de consumidor protegido (GRALLOC_USAGE_PROTECTED) en las plataformas creadas en un contexto protegido (verificado por ACodec).

La reproducción de video de textura segura sienta las bases para una implementación sólida de la DRM en el entorno de OpenGL ES. Sin una implementación sólida de la DRM, como Widevine Nivel 1, muchos proveedores de contenido no permiten la renderización de su contenido de alto valor en el entorno de OpenGL ES, lo que impide casos de uso importantes de la realidad virtual, como mirar contenido protegido por DRM en VR.

AOSP incluye código de framework para la reproducción de video de textura segura. La compatibilidad con los controladores depende de los OEM. Los implementadores de dispositivos deben implementar EGL_EXT_protected_content y GL_EXT_protected_textures extensions. Cuando uses tu propia biblioteca de codecs (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 se pone en cola directamente en el 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).