Textura de superficie

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 instancia SurfaceTexture para recibir fotogramas de la cámara y convertirlos en una textura GLES externa.
  • SurfaceFlinger : la aplicación declara una instancia SurfaceView para mostrar los marcos.
  • MediaServer : configure un codificador MediaCodec 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).

Actividad de captura continua de Grafika.

Figura 1. Actividad de captura continua de Grafika.

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.

Cuando se utiliza la clase 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:
  1. Adquiere el marco.
  2. Hace que el marco esté disponible como textura GLES.
  3. Representa el marco con comandos GLES.
  4. 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).

Reproducción de vídeo de textura segura

Figura 2. Reproducción de vídeo de textura segura

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 ).