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