Menor câmera aérea para abordagem de CPU para GPU no android

Meu aplicativo precisa fazer algum processamento em quadros de câmera ao vivo na CPU, antes de renderizá-los na GPU. Também há outras coisas sendo renderizadas na GPU, que dependem dos resultados do processamento da CPU; portanto, é importante manter tudo sincronizado para não renderizar o próprio quadro na GPU até que os resultados do processamento da CPU para esse quadro também estejam disponíveis.

A questão é qual é a abordagem mais baixa para isso no Android?

O processamento da CPU, no meu caso, só precisa de uma imagem em escala de cinza; portanto, é ideal um formato YUV em que o avião Y esteja embalado (e tende a ser uma boa combinação com o formato nativo dos dispositivos da câmera). NV12, NV21 ou YUV totalmente plano forneceriam acesso ideal de baixo custo adicional à escala de cinzentos, de modo que seria preferido no lado da CPU.

Na API da câmera original, o setPreviewCallbackWithBuffer () era a única maneira sensata de obter dados na CPU para processamento. Como o plano Y estava separado, era ideal para o processamento da CPU. A disponibilização desse quadro para o OpenGL para renderização de forma reduzida foi o aspecto mais desafiador. No final, escrevi uma rotina de conversão de cores NEON para gerar RGB565 e apenas use glTexSubImage2d para disponibilizá-lo na GPU. Isso foi implementado pela primeira vez no período de tempo do Nexus 1, em que até uma chamada glTexSubImage2d de 320x240 levou 50ms de tempo de CPU (drivers ruins tentando fazer swizzling de textura, presumo - isso foi melhorado significativamente em uma atualização do sistema posteriormente).

Naquele dia, analisei coisas como as extensões eglImage, mas elas não parecem estar disponíveis ou bem documentadas o suficiente para aplicativos de usuários. Dei uma olhada nas classes internas do GraphicsBuffer para Android, mas, idealmente, quero permanecer no mundo das APIs públicas suportadas.

A API android.hardware.camera2 prometeu poder anexar um ImageReader e um SurfaceTexture a uma sessão de captura. Infelizmente, não consigo encontrar nenhuma maneira de garantir o pipeline seqüencial correto aqui - adiar a atualização de updateTexImage () até que a CPU seja processada é fácil, mas se outro quadro chegar durante esse processamento, o updateTexImage () passará direto para o último quadro, Armação. Também parece que, com várias saídas, haverá cópias independentes dos quadros em cada uma das filas que, idealmente, eu gostaria de evitar.

Idealmente, é isso que eu gostaria:

O driver da câmera preenche um pouco de memória com o último quadroCPU obtém ponteiro para os dados na memória, pode ler dados Y sem fazer uma cópiaCPU processa dados e define um sinalizador no meu código quando o quadro está prontoAo começar a renderizar um quadro, verifique se um novo quadro está prontoChame alguma API para vincular a mesma memória que uma textura GLQuando um quadro mais novo estiver pronto, libere o buffer que mantém o quadro anterior novamente no pool

Não vejo uma maneira de fazer exatamente esse estilo de cópia zero com API pública no Android, mas qual é o mais próximo possível de obter?

Uma coisa louca que tentei parece funcionar, mas não está documentada: A API NDative do ANativeWindow pode aceitar o formato NV12 de dados, mesmo que a constante de formato apropriada não seja uma das listadas nos cabeçalhos públicos. Isso permite que um SurfaceTexture seja preenchido com dados NV12 por memcpy () para evitar a conversão de cores no lado da CPU e qualquer oscilação que ocorra no lado do driver no glTexImage2d. Essa ainda é uma cópia extra dos dados, embora pareça desnecessária e, uma vez que não está documentada, pode não funcionar em todos os dispositivos. Uma câmera seqüencial de cópia zero suportada -> ImageReader -> SurfaceTexture ou equivalente seria perfeita.

questionAnswers(1)

yourAnswerToTheQuestion