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 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 para o GLES como uma textura externa.
Texturas GLES externas
As texturas GLES externas (GL_TEXTURE_EXTERNAL_OES
) diferem das texturas GLES padrão (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 padrão.
- Texturas externas não podem realizar todas as atividades padrão de textura do GLES.
O principal benefício das texturas externas é a capacidade de renderizar diretamente
dados do 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 e verificam se os dados no buffer são reconhecíveis pelo GLES.
Como as instâncias SurfaceTexture
interagem com um contexto EGL, um app só pode chamar os métodos dele enquanto o contexto EGL proprietário da 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 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 transmitido por BufferQueue
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 na orientação original 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 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 ele foi capturado, e não de quando o app o recebeu. 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 do Grafika envolve a gravação de frames da câmera de um dispositivo e a exibição deles 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 e mostrar frames 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 a seguir, as setas indicam a propagação de dados da câmera. As instâncias BufferQueue
são mostradas com indicadores visuais que distinguem produtores (azul-petróleo) de consumidores (verde).

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 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 UI. O
processamento de dados codificados (gerenciamento de um buffer circular e gravação em disco) é
feito em uma linha de execução separada.
Ao usar a classe 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, o
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
.
Em seguida, a linha de execução do codificador extrai a saída codificada de MediaCodec
e a armazena na memória.
Reprodução segura de vídeos com textura
O Android oferece suporte ao pós-processamento de GPU de conteúdo de vídeo protegido. Isso permite que os apps usem a GPU para efeitos de vídeo complexos e não lineares (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 (RV).

Figura 2. Reprodução segura de vídeos com 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 plataformas 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 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 superfícies criadas em um contexto protegido (verificado pelo ACodec).
A reprodução segura de vídeo de textura estabelece a base para uma implementação forte de gerenciamento de direitos digitais (DRM) no ambiente OpenGL ES. Sem uma implementação forte de DRM, como o Widevine Nível 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 Android Open Source Project (AOSP) inclui código de framework para reprodução segura de vídeo com textura. O suporte a drivers depende dos OEMs. Os implementadores de dispositivos precisam
implementar as extensões EGL_EXT_protected_content
e
GL_EXT_protected_textures
. 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 coloque em fila diretamente para o compositor de janela), desde que os bits de uso do consumidor contenham GRALLOC_USAGE_PROTECTED
. Para documentação detalhada sobre
a implementação das extensões, consulte os registros do Khronos (
EGL_EXT_protected_content
) e (
GL_EXT_protected_textures
).