Android cámara2 jpeg framerate

Estoy tratando de guardar secuencias de imágenes con frames fijos (preferiblemente hasta 30) en un dispositivo Android con capacidad COMPLETA para camera2 (Galaxy S7), pero no soy capaz de a) obtener un framerate estable, b) alcanzar incluso 20fps (con jpeg Codificación). Ya he incluido las sugerencias de la captura de la cámara Android2 ráfaga es demasiado lento .

La duración mínima de la trama para JPEG es de 33,33 milisegundos (para resoluciones inferiores a 1920×1080) según

characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputMinFrameDuration(ImageFormat.JPEG, size); 

Y el stallduration es 0ms para cada tamaño (similar para YUV_420_888).

Mi constructor de captura se ve así:

 captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CONTROL_AE_MODE_OFF); captureBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, _exp_time); captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); captureBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, _iso_value); captureBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, _foc_dist); captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CONTROL_AF_MODE_OFF); captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, _wb_value); // https://stackoverflow.com/questions/29265126/android-camera2-capture-burst-is-too-slow captureBuilder.set(CaptureRequest.EDGE_MODE,CaptureRequest.EDGE_MODE_OFF); captureBuilder.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE, CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF); captureBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF); captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); // Orientation int rotation = getWindowManager().getDefaultDisplay().getRotation(); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation)); 

La distancia de enfoque se establece en 0.0 (inf), iso se fija en 100, tiempo de exposición 5ms. La balanza de blancos se puede ajustar en OFF / AUTO / ANY VALUE, no afecta los tiempos que se indican a continuación.

Comienzo la sesión de captura con el siguiente comando:

 session.setRepeatingRequest(_capReq.build(), captureListener, mBackgroundHandler); 

Nota: No hace ninguna diferencia si solicito RepeatingRequest o RepeatingBurst.

En la vista previa (sólo superficie de textura adjunta), todo está a 30fps. Sin embargo, tan pronto como adjunto un lector de imágenes (oyente que se ejecuta en HandlerThread) que instancio como sigue (sin guardar, sólo medir el tiempo entre fotogramas):

 reader = ImageReader.newInstance(_img_width, _img_height, ImageFormat.JPEG, 2); reader.setOnImageAvailableListener(readerListener, mBackgroundHandler); 

Con código de medición del tiempo:

 ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader myreader) { Image image = null; image = myreader.acquireNextImage(); if (image == null) { return; } long curr = image.getTimestamp(); Log.d("curr- _last_ts", "" + ((curr - last_ts) / 1000000) + " ms"); last_ts = curr; image.close(); } } 

Recibo periódicamente repitiendo diferencias de tiempo como esta:

99 ms – 66 ms – 66 ms – 99 ms – 66 ms – 66 ms …

¿No entiendo porqué éstos toman el doble o el triple el tiempo que el mapa de la configuración de la corriente anunció para el JPEG? El tiempo de exposición está muy por debajo de la duración de la trama de 33ms. ¿Hay algún otro proceso interno que no conozco?

He intentado lo mismo para el formato YUV_420_888, lo que dio lugar a constantes diferencias de tiempo de 33ms. El problema que tengo aquí es que el teléfono celular carece del ancho de banda para almacenar las imágenes lo suficientemente rápido (probé el método descrito en Cómo guardar una imagen YUV_420_888? ). Si usted sabe de cualquier método para comprimir o codificar estas imágenes lo suficientemente rápido, por favor hágamelo saber.

Edit: De la documentación de getOutputStallDuration: "En otras palabras, usar una repetición de solicitud YUV daría lugar a una velocidad de cuadros fija (digamos que es 30 FPS) .Si una sola solicitud JPEG se presenta periódicamente, la velocidad de fotogramas se mantendrá en 30 FPS (Siempre y cuando esperemos a que el JPEG anterior regrese cada vez) Si intentamos enviar una solicitud YUV + JPEG repetitiva, la velocidad de fotogramas caerá de 30 FPS ". ¿Esto implica que necesito solicitar periódicamente una sola captura ()?

Edit2: From https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html : "La información necesaria para la aplicación, dado el modelo anterior, se proporciona a través del campo android.scaler.streamConfigurationMap utilizando getOutputMinFrameDuration (Int, Size), que se utilizan para determinar la velocidad máxima de trama / duración mínima de trama que es posible para una configuración de flujo dada.

Específicamente, la aplicación puede utilizar las siguientes reglas para determinar la duración de trama mínima que puede solicitar desde el dispositivo de cámara:

Deje que el conjunto de corrientes de entrada / salida actualmente configuradas sea llamado S. Encuentre las duraciones de marco mínimas para cada flujo en S, buscando en android.scaler.streamConfigurationMap usando getOutputMinFrameDuration (int, Size) (con su tamaño / formato respectivo) . Deje que este conjunto de duraciones de trama sea llamado F. Para cualquier petición dada R, la duración mínima de trama permitida para R es el máximo de todos los valores en F. Deje que los flujos usados ​​en R se llamen S_r. Si ninguna de las secuencias de S_r tiene un tiempo de parada (enumerado en getOutputStallDuration (int, Size) usando su tamaño / formato respectivo), entonces la duración de la trama en F determina la velocidad de cuadro estacionario que obtendrá la aplicación si usa R como Una petición repetida ".

La salida JPEG no es, por lo tanto, la forma más rápida de recuperar los fotogramas. Puede lograr esto mucho más rápido dibujando los marcos directamente en un Quad usando OpenGL.

Para la captura de ráfaga, una solución más rápida sería capturar las imágenes a la RAM sin codificarlas, luego codificarlas y guardarlas de forma asíncrona.

En este sitio web se puede encontrar un montón de excelente código relacionado con la multimedia android en general.

Este programa específico utiliza OpenGL para obtener los datos de píxeles de un vídeo MPEG. No es difícil utilizar la cámara como entrada en lugar de un video. Básicamente puede utilizar la textura utilizada en la clase CodecOutputSurface del programa mencionado como textura de salida para su solicitud de captura.

Una posible solución que encontré consiste en usar y descargar YUV sin codificarlo como JPEG en combinación con una micro tarjeta Sd que es capaz de ahorrar hasta 95 Mb por segundo. (Tuve la idea errónea de que las imágenes YUV serían más grandes, por lo que con un teléfono celular que tiene pleno soporte para la cámara 2-pipeline, la velocidad de escritura debe ser el factor limitante.

Con esta configuración, pude lograr las siguientes tasas estables:

  • 1920×1080, 15fps (aproximadamente 4Mb * 15 == 60Mb / s)
  • 960 x 720, 30 fps. (Aproximadamente 1,5Mb * 30 = 45Mb / s)

Entonces codifico las imágenes fuera de línea de YUV a PNG usando una escritura del python.

  • Convertir el marco de vista previa en un mapa de bits
  • Fuera de memoria al usar compresstojpeg en varios YuvImage uno a la vez
  • Camera2 api convertir yuv420 a rgb verde hacia fuera
  • Rotación de la imagen YUV420 / NV21 en android
  • YUV_420_888 interpretación en Samsung Galaxy S7 (Camera2)
  • Cámara adecuada2 YUV_420_888 a conversión de JPEG
  • Convertir android.media.Image (YUV_420_888) en mapa de bits
  • Cómo convertir el formato de imagen NV21 en mapa de bits?
  • Convertir YUV-> RGB (procesamiento de imágenes) -> YUV durante onPreviewFrame en android?
  • La manera más rápida de dibujar un marco de vídeo decodificado con MediaCodec a la pantalla?
  • Convertir matriz de mapa de bits a YUV (YCbCr NV21)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.