¿Cómo obtengo el búfer de cámara raw de Android en C usando JNI?


He estado buscando en Google y StackOverflow exhaustivamente y no puedo encontrar esto. Tal vez me estoy perdiendo algo obvio. ¡Gracias!

(Esto se debe a que la implementación Java de la devolución de llamada de vista previa [incluso con buffer] es demasiado ineficiente.)

Author: Nick, 2012-05-20

3 answers

Hice una pequeña investigación sobre el tema. Estapresentación (de p. 277, chino) ayudó mucho.

Cadena de llamadas de vista previa de la cámara

Como otros mencionaron, puede obtener un búfer usando un método Camera.setPreviewCallback.
Así es como sucede allí (una versión detallada):

  1. El usuario llama a Camera.startPreview() que es una función nativa.
  2. android_hardware_Camera_startPreview llama al método startPreview de la clase C++ Camera.
  3. Camera llama a un método startPreview de la interfaz ICamera
  4. ICamera hace un IPC llamada al cliente remoto.
  5. Llama a un método setCameraMode de la clase CameraService.
  6. CameraService establece una ventana para mostrar una vista previa y llama a un método startPreview de la clase CameraHardwareInterface.
  7. Este último intenta llamar a un método start_preview en un dispositivo camera_device_t particular.
    No miré más, pero debería realizar una llamada al conductor.
  8. Cuando llega la imagen, se invoca dataCallback de CameraService.
  9. Pasa datos al método handlePreviewData del cliente.
  10. Cliente copia el buffer o lo envía directamente al ICameraClient.
  11. ICameraClient lo envía a IPC al Camera.
  12. Camera llama a un oyente registrado y pasa buffer a JNI.
  13. Invoca una devolución de llamada en la clase Java. Si el usuario proporciona un búfer con Camera.addCallbackBuffer entonces se copia al búfer primero.
  14. Finalmente la clase Java Camera maneja el mensaje e invoca un método onPreviewFrame de Camera.PreviewCallback.

Como puede ver, se invocaron 2 IPC llamadas y se copió buffer al menos dos veces en los escalones 10, 11. La primera instancia de raw buffer que devuelve camera_device_t está alojada en otro proceso y no puede acceder a ella debido a las comprobaciones de seguridad en CameraService.

Vista previa de la superficie

Sin embargo, cuando se establece una superficie de vista previa utilizando Camera.setPreviewTexture o Camera.setPreviewDisplay se pasa directamente al dispositivo de la cámara y se actualiza en tiempo real sin la participación de toda la cadena anterior. Como dice la documentación:

Manejar en un búfer sin procesar que está siendo administrado por el compositor de pantalla.

Java class Surface tiene un método para recuperar su contenido:

public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);

Pero esta API está oculta. Ver i.e. esta pregunta para una forma de usarla.

 25
Author: Andrey Ermakov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:33:44

No hay una API pública para hacer lo que quieras; el único método oficial (es decir, garantizado para funcionar) es la vista previa de llamadas a nivel Java configurada a través de calling Camera.setPreviewCallback () . En Android > 3.0, también puede utilizar Cámara.setPreviewTexture () para enrutar los datos de vista previa a la GPU, y procesarlos allí usando GLES (o leerlos de nuevo a la CPU). La ruta de la GPU es lo que la aplicación de cámara ICS AOSP utiliza para sus efectos de vídeo.

Presumiblemente, OpenCV y otros han mirado a través del código nativo del marco de trabajo de Android y han omitido la API de Java Camera, hablando directamente con los servicios a continuación.

Esto es bastante peligroso, porque no hay absolutamente ninguna garantía de que esas interfaces no cambien entre las versiones de Android, ya que no forman parte de la API pública. Usarlas puede estar bien ahora, y luego, cuando un usuario actualice su dispositivo, su aplicación dejará de funcionar.

 5
Author: Eddy Talvala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-27 18:23:51

¿Has echado un vistazo a OpenCV para Android. Sus tutoriales avanzados muestran cómo usar JNI y hay un objeto NativeProcessor en su paquete de cámara.

 1
Author: Jeff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-22 19:48:45