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 consumidores. 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 ao GLES como uma textura externa.

Texturas externas do GLES

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 de BufferQueue .
  • Os renderizadores de textura externos são configurados de maneira diferente dos renderizadores de textura GLES tradicionais.
  • As texturas externas não podem realizar todas as atividades tradicionais de textura do GLES.

O principal benefício das texturas externas é a capacidade de renderizar diretamente dos dados BufferQueue . As instâncias SurfaceTexture definem os sinalizadores de uso do consumidor como GRALLOC_USAGE_HW_TEXTURE quando criam 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 thread de chamada. Para obter mais informações, consulte a documentação da classe SurfaceTexture .

Carimbos de data e hora e transformações

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

Os parâmetros de transformação são úteis para 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 fontes 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, e não de quando o aplicativo o recebeu. O código da câmera define o carimbo de data/hora fornecido com o buffer, resultando em uma série de carimbos de data/hora mais consistente.

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 método 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 complicado.

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

Este 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 dos dados da câmera. As instâncias BufferQueue são coloridas (os produtores são verde-azulados, 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 thread de UI. A manipulação de dados codificados (gerenciamento de um buffer circular e gravação em disco) é feita em um thread separado.

Ao usar a classe SurfaceView , o retorno de chamada surfaceCreated() cria as instâncias EGLContext e EGLSurface para o display e o codificador de vídeo. Quando um novo quadro chega, SurfaceTexture executa quatro atividades:
  1. Adquire a moldura.
  2. Disponibiliza o quadro 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 thread do codificador extrai a saída codificada do MediaCodec e a armazena na memória.

Reprodução segura de vídeo de textura

O Android oferece suporte ao 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 complexos e não lineares (como warps), 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 segura de vídeo de textura

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

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

O Android permite que SurfaceTexture e ACodec ( libstagefright.so ) enviem conteúdo protegido mesmo se a superfície da janela não estiver na fila SurfaceFlinger e forneça 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 segura de vídeo de textura estabelece a base para uma forte implementação de DRM no ambiente OpenGL ES. Sem uma forte implementação de DRM, como o 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, evitando casos de uso importantes de VR, como assistir conteúdo protegido por DRM em VR.

AOSP inclui código de estrutura para reprodução segura de vídeo de textura. O suporte do 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 que ANativeWindow não faça fila 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 ).