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ânciaSurfaceTexture
para receber quadros da câmera, convertendo-os em uma textura GLES externa. -
SurfaceFlinger
— O aplicativo declara uma instânciaSurfaceView
para exibir os quadros. -
MediaServer
— Configure um codificadorMediaCodec
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).
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.
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:- Adquire o quadro.
- Disponibiliza a moldura como uma textura GLES.
- Renderiza o quadro com comandos GLES.
- 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).
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
).