Textura da superfície

SurfaceTexture é uma combinação de uma superfície e uma textura OpenGL ES (GLES) . As instâncias SurfaceTexture são usadas para fornecer superfícies que geram texturas GLES.

SurfaceTexture contém uma instância de BufferQueue para a qual os aplicativos são o consumidor. O retorno de chamada onFrameAvailable() notifica os aplicativos quando o produtor enfileira um novo buffer. Em seguida, os aplicativos chamam updateTexImage() , que libera o buffer retido anteriormente, adquire o novo buffer da fila e faz chamadas EGL para disponibilizar o buffer para GLES como uma textura externa.

Texturas GLES externas

Texturas GLES externas ( GL_TEXTURE_EXTERNAL_OES ) diferem das texturas GLES tradicionais ( GL_TEXTURE_2D ) das seguintes maneiras:

  • Texturas externas renderizam polígonos texturizados diretamente dos dados recebidos do BufferQueue .
  • Os renderizadores de textura externa são configurados de forma diferente dos renderizadores de textura GLES tradicionais.
  • Texturas externas não podem realizar todas as atividades de textura GLES tradicionais.

O principal benefício das texturas externas é sua capacidade de renderizar diretamente dos dados do BufferQueue . As instâncias SurfaceTexture definem os sinalizadores de uso do consumidor como GRALLOC_USAGE_HW_TEXTURE ao criar instâncias BufferQueue para texturas externas para garantir que os dados no buffer sejam reconhecíveis pelo GLES.

Como as instâncias SurfaceTexture interagem com um contexto EGL, um aplicativo só pode chamar seus métodos enquanto o contexto EGL que possui a textura estiver atual no encadeamento de chamada. Para obter mais informações, consulte a documentação da classe SurfaceTexture .

Timestamps e transformações

As instâncias de SurfaceTexture incluem o método getTimeStamp() , que recupera um registro de data e hora, e o getTransformMatrix() , que recupera uma matriz de transformação. Chamar updateTexImage() configura o timestamp e a matriz de transformação. Cada buffer que o BufferQueue passa inclui parâmetros de transformação e um carimbo de data/hora.

Os parâmetros de transformação são úteis para a eficiência. Em alguns casos, os dados de origem podem estar na orientação incorreta para o consumidor. Em vez de girar os dados antes de enviá-los ao consumidor, envie os dados em sua orientação com uma transformação que os corrija. A matriz de transformação pode ser mesclada com outras transformações quando os dados são usados, minimizando a sobrecarga.

O carimbo de data/hora é útil para origens de buffer que dependem do tempo. Por exemplo, quando setPreviewTexture() conecta a interface do produtor à saída da câmera, os quadros da câmera podem ser usados ​​para criar um vídeo. Cada quadro precisa ter um carimbo de data/hora de apresentação de quando o quadro foi capturado, não de quando o aplicativo recebeu o quadro. O código da câmera define o timestamp fornecido com o buffer, resultando em uma série mais consistente de timestamps.

Estudo de caso: captura contínua da Grafika

A captura contínua do Grafika envolve a gravação de quadros da câmera de um dispositivo e a exibição desses quadros na tela. Para gravar quadros, crie uma superfície com o createInputSurface() da classe MediaCodec e passe a superfície para a câmera. Para exibir quadros, crie uma instância de SurfaceView e passe a superfície para setPreviewDisplay() . Observe que gravar quadros e exibi-los ao mesmo tempo é um processo mais complexo.

A atividade de captura contínua exibe o vídeo da câmera enquanto o vídeo está sendo gravado. Nesse caso, o vídeo codificado é gravado em um buffer circular na memória que pode ser salvo em disco a qualquer momento.

Esse fluxo envolve três filas de buffer:

  • App — O aplicativo usa uma instância SurfaceTexture para receber quadros da câmera, convertendo-os em uma textura GLES externa.
  • SurfaceFlinger — O aplicativo declara uma instância SurfaceView para exibir os quadros.
  • MediaServer — Configure um codificador MediaCodec com uma superfície de entrada para criar o vídeo.

Na figura abaixo, as setas indicam a propagação de dados da câmera. As instâncias do BufferQueue são coloridas (os produtores são verde-azulado, os consumidores são verdes).

Atividade de captura contínua Grafika

Figura 1. Atividade de captura contínua da Grafika

O vídeo H.264 codificado vai para um buffer circular na RAM no processo do aplicativo. Quando um usuário pressiona o botão de captura, a classe MediaMuxer grava o vídeo codificado em um arquivo MP4 no disco.

Todas as instâncias BufferQueue são tratadas com um único contexto EGL no aplicativo enquanto as operações GLES são executadas no encadeamento da interface do usuário. O manuseio de dados codificados (gerenciando um buffer circular e gravando-o em disco) é feito em um thread separado.

Ao usar a classe SurfaceView , o retorno de chamada surfaceCreated() cria as instâncias EGLContext e EGLSurface para a exibição e o codificador de vídeo. Quando um novo quadro chega, o SurfaceTexture realiza quatro atividades:
  1. Adquire o quadro.
  2. Disponibiliza a moldura como uma textura GLES.
  3. Renderiza o quadro com comandos GLES.
  4. Encaminha a transformação e o carimbo de data/hora para cada instância de EGLSurface .

O encadeamento do codificador então extrai a saída codificada do MediaCodec e a armazena na memória.

Reprodução de vídeo de textura segura

O Android suporta pós-processamento de GPU de conteúdo de vídeo protegido. Isso permite que os aplicativos usem a GPU para efeitos de vídeo não lineares complexos (como distorções), mapeando conteúdo de vídeo protegido em texturas para uso em cenas gráficas gerais (por exemplo, usando GLES) e realidade virtual (VR).

Reprodução de vídeo de textura segura

Figura 2. Reprodução de vídeo de textura segura

O suporte é ativado usando as duas extensões a seguir:

  • Extensão EGL — ( EGL_EXT_protected_content ) Permite a criação de contextos e superfícies GL protegidos, que podem operar em conteúdo protegido.
  • Extensão GLES — ( GL_EXT_protected_textures ) Permite marcar texturas como protegidas para que possam ser usadas como anexos de textura de buffer de quadro.

O Android permite que SurfaceTexture e ACodec ( libstagefright.so ) enviem conteúdo protegido mesmo se a superfície da janela não enfileirar para SurfaceFlinger e fornece uma superfície de vídeo protegida para uso em um contexto protegido. Isso é feito definindo o bit consumidor protegido ( GRALLOC_USAGE_PROTECTED ) em superfícies criadas em um contexto protegido (verificado pelo ACodec).

A reprodução de vídeo de textura segura estabelece a base para uma forte implementação de DRM no ambiente OpenGL ES. Sem uma forte implementação de DRM, como Widevine Nível 1, muitos provedores de conteúdo não permitem a renderização de seu conteúdo de alto valor no ambiente OpenGL ES, impedindo casos de uso importantes de RV, como assistir a conteúdo protegido por DRM em RV.

AOSP inclui código de estrutura para reprodução de vídeo de textura segura. O suporte ao driver depende dos OEMs. Os implementadores de dispositivos devem implementar as extensões EGL_EXT_protected_content e GL_EXT_protected_textures extensions . Ao usar sua própria biblioteca de codecs (para substituir libstagefright ), observe as alterações em /frameworks/av/media/libstagefright/SurfaceUtils.cpp que permitem que buffers marcados com GRALLOC_USAGE_PROTECTED sejam enviados para ANativeWindow (mesmo se ANativeWindow não enfileirar diretamente para o compositor de janela) desde que os bits de uso do consumidor contenham GRALLOC_USAGE_PROTECTED . Para obter documentação detalhada sobre a implementação das extensões, consulte os registros Khronos ( EGL_EXT_protected_content e GL_EXT_protected_textures ).