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 são enviadas para texturas
GLES.
SurfaceTexture
contém uma instância de BufferQueue
para a qual
os apps são o consumidor. O callback onFrameAvailable()
notifica os apps quando o produtor enfileira um novo buffer. Em seguida, os apps chamam
updateTexImage()
, que libera o buffer mantido anteriormente,
adquire o novo buffer da fila e faz chamadas EGL para disponibilizar o buffer ao GLES como uma textura externa.
Texturas GLES externas
As texturas GLES externas (GL_TEXTURE_EXTERNAL_OES
) diferem
das texturas GLES tradicionais (GL_TEXTURE_2D
) das seguintes
maneiras:
- As 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.
- Texturas externas não podem realizar todas as atividades tradicionais de textura do GLES.
O principal benefício das texturas externas é
a capacidade de renderização diretamente a partir de dados BufferQueue
. As instâncias SurfaceTexture
definem as flags 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 de SurfaceTexture
interagem com um contexto EGL, um app só pode chamar
os métodos enquanto o contexto EGL que possui a textura estiver atual na
linha de execução de chamada. Para mais informações, consulte a documentação da classe SurfaceTexture
.
Carimbos de data/hora e transformações
As instâncias de 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. A chamada de updateTexImage()
define o carimbo de data/hora e a matriz de transformação. Cada buffer que
BufferQueue
transmite 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 na 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 dependentes do tempo. Por
exemplo, quando setPreviewTexture()
conecta
a interface do produtor à saída da câmera, os frames da câmera podem
ser usados para criar um vídeo. Cada frame precisa ter um carimbo de data/hora
de apresentação do momento em que o frame foi capturado, e não do momento em que o app recebeu o
frame. O código da câmera define o carimbo de data/hora fornecido com o buffer,
resultando em uma série mais consistente de carimbos de data/hora.
Estudo de caso: captura contínua da Grafika
A captura contínua da Grafika envolve gravar frames
da câmera de um dispositivo e exibir esses frames na tela.
Para gravar frames, crie uma superfície com o
método createInputSurface()
da classe
MediaCodec e transmita a superfície para a câmera. Para
mostrar frames, crie uma instância de SurfaceView
e transmita a superfície para
setPreviewDisplay()
. Gravar frames e exibi-los
ao mesmo tempo é um processo mais complexo.
A atividade de captura contínua mostra o vídeo da câmera enquanto ele está sendo gravado. Nesse caso, o vídeo codificado é gravado em um buffer circular na memória que pode ser salvo no disco a qualquer momento.
Esse fluxo envolve três filas de buffer:
App
: o app usa uma instânciaSurfaceTexture
para receber frames da câmera, convertendo-os em uma textura GLES externa.SurfaceFlinger
: o app declara uma instânciaSurfaceView
para mostrar os frames.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 de BufferQueue
são coloridas (os produtores são azul-esverdeado, e os consumidores são verdes).

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 app.
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 de BufferQueue
são processadas com um único contexto EGL no
app, enquanto as operações GLES são realizadas na linha de execução da interface. O processamento de
dados codificados (gerenciamento de um buffer circular e gravação em disco) é feito
em uma linha de execução separada.
SurfaceView
, o callback surfaceCreated()
cria
as instâncias EGLContext
e EGLSurface
para a tela e o codificador
de vídeo. Quando um novo frame chega, SurfaceTexture
realiza quatro atividades:
- Adquire o frame.
- Disponibiliza o frame como uma textura GLES.
- Renderiza o frame com comandos GLES.
- Encaminha a transformação e o carimbo de data/hora para cada instância de
EGLSurface
.
A linha de execução do codificador extrai a saída codificada de MediaCodec
e a armazena
na memória.
Reprodução de vídeo de textura segura
O Android oferece suporte ao pós-processamento de conteúdo de vídeo protegido por GPU. Isso permite que os apps usem a GPU para efeitos de vídeo complexos e não lineares (como deformações), mapeando conteúdo de vídeo protegido para texturas para uso em cenas gráficas gerais (por exemplo, usando GLES) e realidade virtual (RV).

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 plataformas GL protegidos, que podem operar em conteúdo protegido. - Extensão GLES:
(
GL_EXT_protected_textures
) permite a inclusão de tags em texturas como protegidas para que elas possam ser usadas como anexos de textura de framebuffer.
O Android permite que SurfaceTexture
e ACodec
(libstagefright.so
) enviem conteúdo protegido, mesmo que
a superfície da janela não seja enfileirada para SurfaceFlinger
e forneça uma superfície de vídeo protegida para uso em um contexto protegido. Isso
é feito definindo o bit de consumidor protegido
(GRALLOC_USAGE_PROTECTED
) em plataformas criadas em um contexto
protegido (verificado pelo ACodec).
A reprodução segura de vídeos de textura estabelece a base para uma implementação robusta de DRM no ambiente OpenGL ES. Sem uma implementação forte de DRM, como o Widevine Level 1, muitos provedores de conteúdo não permitem a renderização do conteúdo de alto valor no ambiente OpenGL ES, impedindo casos de uso importantes de RV, como assistir conteúdo protegido por DRM em RV.
O AOSP inclui o código do framework para reprodução segura de vídeos de textura. O suporte
a drivers é de responsabilidade dos OEMs. Os implementadores de dispositivos precisam implementar
EGL_EXT_protected_content
e
GL_EXT_protected_textures extensions
. Ao usar sua própria biblioteca de
codec (para substituir libstagefright
), observe as mudanças 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 seja enfileirado diretamente no
compilador de janelas, desde que os bits de uso do consumidor contenham
GRALLOC_USAGE_PROTECTED
. Para conferir uma documentação detalhada sobre a implementação
das extensões, consulte os registros do Khronos
(EGL_EXT_protected_content
e
GL_EXT_protected_textures
).