Enfoque más bajo de cámara superior a CPU a GPU en Android

Mi aplicación necesita hacer un procesamiento en los marcos de las cámaras en vivo en la CPU, antes de procesarlos en la GPU. También hay otras cosas que se procesan en la GPU que dependen de los resultados del procesamiento de la CPU; por lo tanto, es importante mantener todo sincronizado para que no procesemos el marco en la GPU hasta que los resultados del procesamiento de la CPU para ese marco también estén disponibles.

La pregunta es ¿cuál es el enfoque de gastos generales más bajo para esto en Android?

El procesamiento de la CPU en mi caso solo necesita una imagen en escala de grises, por lo que un formato YUV donde está empaquetado el plano Y es ideal (y tiende a ser una buena coincidencia con el formato nativo de los dispositivos de la cámara también). NV12, NV21 o YUV completamente plano proporcionarían un acceso ideal de baja sobrecarga a escala de grises, por lo que sería preferible en el lado de la CPU.

En la API de cámara original, setPreviewCallbackWithBuffer () era la única forma sensata de obtener datos en la CPU para su procesamiento. Esto tenía el plano Y separado, por lo que era ideal para el procesamiento de la CPU. Lograr que este marco estuviera disponible para OpenGL para renderizar en una forma de baja sobrecarga fue el aspecto más desafiante. Al final, escribí una rutina de conversión de color NEON para generar RGB565 y solo uso glTexSubImage2d para que esté disponible en la GPU. Esto se implementó por primera vez en el período de tiempo de Nexus 1, donde incluso una llamada glTexSubImage2d de 320x240 tomó 50 ms de tiempo de CPU (supongo que los controladores deficientes que intentaban mezclar la textura) mejoraron significativamente en una actualización del sistema más adelante).

En el pasado, busqué cosas como las extensiones de eglImage, pero no parecen estar disponibles o no están suficientemente documentadas para las aplicaciones de los usuarios. Eché un vistazo a las clases internas de GraphicsBuffer de Android, pero idealmente quiero permanecer en el mundo de las API públicas compatibles.

La API android.hardware.camera2 prometió poder adjuntar un ImageReader y un SurfaceTexture a una sesión de captura. Desafortunadamente, no puedo ver ninguna manera de asegurar la tubería secuencial correcta aquí: retrasar la llamada a updateTexImage () hasta que la CPU haya procesado es bastante fácil, pero si ha llegado otro marco durante ese procesamiento, updateTexImage () saltará directamente a la última cuadro. También parece que con múltiples salidas habrá copias independientes de los marcos en cada una de las colas que idealmente me gustaría evitar.

Idealmente, esto es lo que me gustaría:

El controlador de la cámara llena algo de memoria con el último cuadroLa CPU obtiene el puntero a los datos en la memoria, puede leer los datos Y sin hacer una copiaLa CPU procesa datos y establece un indicador en mi código cuando el marco está listoCuando comience a renderizar un marco, verifique si hay un nuevo marco listoLlame a alguna API para enlazar la misma memoria que una textura GLCuando un marco más nuevo esté listo, suelte el búfer que retiene el marco anterior en el grupo

No puedo ver una manera de hacer exactamente ese estilo de copia cero con API pública en Android, pero ¿qué es lo más cercano que es posible obtener?

Una cosa loca que probé parece funcionar, pero no está documentada: la API ANativeWindow NDK puede aceptar el formato de datos NV12, aunque la constante de formato apropiada no es una de las cabeceras públicas. Eso permite que una SurfaceTexture se llene con datos NV12 por memcpy () para evitar la conversión de color del lado de la CPU y cualquier oscilación que ocurra en el lado del controlador en glTexImage2d. Eso sigue siendo una copia adicional de los datos, aunque parece que debería ser innecesario, y de nuevo, ya que no está documentado, podría no funcionar en todos los dispositivos. Una cámara secuencial compatible con copia cero -> ImageReader -> SurfaceTexture o equivalente sería perfecta.

Respuestas a la pregunta(1)

Su respuesta a la pregunta