¿Cómo obtener datos de vista previa sin procesar del objeto Cámara al menos 15 fotogtwigs por segundo en Android?

Necesito obtener datos de vista previa en bruto del objeto Cámara al menos 15 fotogtwigs por segundo , pero solo puedo obtener un fotogtwig en 110 milisegundos, lo que significa que puedo obtener solo 9 fotogtwigs por segundo. Resumo mi código a continuación.

Camera mCamera = Camera.open(); Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewFrameRate(30); parameters.setPreviewFpsRange(15000,30000); mCamera.setParameters(parameters); mCamera.addCallbackBuffer(new byte[dataBufferSize]); //dataBufferSize stands for the byte size for a picture frame mCamera.addCallbackBuffer(new byte[dataBufferSize]); mCamera.addCallbackBuffer(new byte[dataBufferSize]); mCamera.setPreviewDisplay(videoCaptureViewHolder); //videoCaptureViewHolder is a SurfaceHolder object mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() { private long timestamp=0; public synchronized void onPreviewFrame(byte[] data, Camera camera) { Log.v("CameraTest","Time Gap = "+(System.currentTimeMillis()-timestamp)); timestamp=System.currentTimeMillis(); //do picture data process camera.addCallbackBuffer(data); return; } } mCamera.startPreview(); 

En el código anterior, dataBufferSize y videoCaptureViewHolder se definen, calculan o asignan en otras declaraciones.

Ejecuto mi código, puedo ver la vista previa en la pantalla y obtengo el registro a continuación:

 ... V/CameraTest( 5396): Time Gap = 105 V/CameraTest( 5396): Time Gap = 112 V/CameraTest( 5396): Time Gap = 113 V/CameraTest( 5396): Time Gap = 115 V/CameraTest( 5396): Time Gap = 116 V/CameraTest( 5396): Time Gap = 113 V/CameraTest( 5396): Time Gap = 115 ... 

Esto significa que onPreviewFrame (datos byte [], cámara de la cámara) se llama cada 110 milisegundos, por lo que puedo obtener no más de 9 fotogtwigs por segundo. Y no importa qué velocidad de fotogtwigs de vista previa establezca en el tema setPreviewFrameRate () y qué rango de vista previa Fps establezca en el problema setPreviewFpsRange () , el registro es el mismo.

¿Alguien podría ayudarme con este problema? Necesito obtener datos de vista previa sin procesar del objeto Cámara al menos 15 fotogtwigs por segundo. Gracias de antemano.

Puse todo mi código a continuación.

CameraTest.java

 package test.cameratest; import java.io.IOException; import java.util.Iterator; import java.util.List; import android.app.Activity; import android.graphics.ImageFormat; import android.hardware.Camera; import android.hardware.Camera.ErrorCallback; import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceHolder.Callback; public class CameraTestActivity extends Activity { SurfaceView mVideoCaptureView; Camera mCamera; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mVideoCaptureView = (SurfaceView) findViewById(R.id.video_capture_surface); SurfaceHolder videoCaptureViewHolder = mVideoCaptureView.getHolder(); videoCaptureViewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); videoCaptureViewHolder.addCallback(new Callback() { public void surfaceDestroyed(SurfaceHolder holder) { } public void surfaceCreated(SurfaceHolder holder) { startVideo(); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } }); } private void startVideo() { SurfaceHolder videoCaptureViewHolder = null; try { mCamera = Camera.open(); } catch (RuntimeException e) { Log.e("CameraTest", "Camera Open filed"); return; } mCamera.setErrorCallback(new ErrorCallback() { public void onError(int error, Camera camera) { } }); Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewFrameRate(30); parameters.setPreviewFpsRange(15000,30000); List supportedPreviewFps=parameters.getSupportedPreviewFpsRange(); Iterator supportedPreviewFpsIterator=supportedPreviewFps.iterator(); while(supportedPreviewFpsIterator.hasNext()){ int[] tmpRate=supportedPreviewFpsIterator.next(); StringBuffer sb=new StringBuffer(); sb.append("supportedPreviewRate: "); for(int i=tmpRate.length,j=0;j<i;j++){ sb.append(tmpRate[j]+", "); } Log.v("CameraTest",sb.toString()); } List supportedPreviewSizes=parameters.getSupportedPreviewSizes(); Iterator supportedPreviewSizesIterator=supportedPreviewSizes.iterator(); while(supportedPreviewSizesIterator.hasNext()){ Size tmpSize=supportedPreviewSizesIterator.next(); Log.v("CameraTest","supportedPreviewSize.width = "+tmpSize.width+"supportedPreviewSize.height = "+tmpSize.height); } mCamera.setParameters(parameters); if (null != mVideoCaptureView) videoCaptureViewHolder = mVideoCaptureView.getHolder(); try { mCamera.setPreviewDisplay(videoCaptureViewHolder); } catch (Throwable t) { } Log.v("CameraTest","Camera PreviewFrameRate = "+mCamera.getParameters().getPreviewFrameRate()); Size previewSize=mCamera.getParameters().getPreviewSize(); int dataBufferSize=(int)(previewSize.height*previewSize.width* (ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat())/8.0)); mCamera.addCallbackBuffer(new byte[dataBufferSize]); mCamera.addCallbackBuffer(new byte[dataBufferSize]); mCamera.addCallbackBuffer(new byte[dataBufferSize]); mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() { private long timestamp=0; public synchronized void onPreviewFrame(byte[] data, Camera camera) { Log.v("CameraTest","Time Gap = "+(System.currentTimeMillis()-timestamp)); timestamp=System.currentTimeMillis(); try{ camera.addCallbackBuffer(data); }catch (Exception e) { Log.e("CameraTest", "addCallbackBuffer error"); return; } return; } }); try { mCamera.startPreview(); } catch (Throwable e) { mCamera.release(); mCamera = null; return; } } private void stopVideo() { if(null==mCamera) return; try { mCamera.stopPreview(); mCamera.setPreviewDisplay(null); mCamera.setPreviewCallbackWithBuffer(null); mCamera.release(); } catch (IOException e) { e.printStackTrace(); return; } mCamera = null; } public void finish(){ stopVideo(); super.finish(); }; } 

AndroidManifest.xml

                            

Tengo miedo, no puedes. La configuración de velocidad de previsualización es una pista para la aplicación de la cámara (que se ejecuta en un proceso separado), y es libre de aceptar o ignorarla silenciosamente. Tampoco está relacionado con la recuperación de marcos de vista previa

Cuando solicita un marco de vista previa, solo dice la aplicación externa que le gustaría tener. Buffer for it se asigna en la aplicación de la cámara y luego se pasa a su actividad a través del segmento de memoria mmaped – esto lleva tiempo.

Puede obtener el rendimiento deseado en algunos dispositivos, pero no necesariamente en el que está jugando.

Si necesita una velocidad de fotogtwigs definida, tendrá que capturar video y luego analizar / descomprimir la transmisión binaria resultante.

Mi experiencia con la cámara ha sido complicada y depende del hardware. Intente ejecutarlo en otro hardware si es posible.

También podría valer la pena intentar algunas configuraciones más de la cámara.

  • Finalizar setRecordingHint (sugerencia booleana) .
  • Podría incluso probar FOCUS_MODE .

Gracias por incluir una muestra de código por cierto.

Esto no debería ser un problema. Mi aplicación androangelo (está en el mercado) obtiene hasta 30 fotogtwigs por segundo (al menos implementé un freno de velocidad para ralentizarlo).

Verifique cuidadosamente si su registro está lleno de declaraciones de recolector de basura. Este es el caso si se agregan muy pocos búferes. Este ha sido el truco para mí. ¡Por lo menos vine a sumr 20! buffers a la cámara.

Entonces, el procesamiento de cada cuadro debe tener lugar en un hilo separado. Mientras una imagen está en el hilo para procesar, la callback debe omitir el cuadro actual.

Según tengo entendido, Android no permite al usuario establecer un framerate fijo, ni garantiza que el valor de fps que especifique será respetado se debe al tiempo de exposición del fotogtwig establecido por el hardware o firmware de la cámara. La velocidad de fotogtwigs que observas puede ser una función de las condiciones de iluminación. Por ejemplo, cierto teléfono puede darle una velocidad de vista previa de 30 fps en una luz diurna pero solo 7 fps si está filmando en condiciones de poca luz.

Una cosa que parece boost la fluidez de la vista previa, si no el FPS real necesariamente, es establecer el formato de vista previa a YV12 si es compatible. Son menos bytes para copiar, 16 bytes alineados y posiblemente optimizados de otras formas:

  // PREVIEW FORMATS List supportedPreviewFormats = parameters.getSupportedPreviewFormats(); Iterator supportedPreviewFormatsIterator = supportedPreviewFormats.iterator(); while(supportedPreviewFormatsIterator.hasNext()){ Integer previewFormat =supportedPreviewFormatsIterator.next(); // 16 ~ NV16 ~ YCbCr // 17 ~ NV21 ~ YCbCr ~ DEFAULT // 4 ~ RGB_565 // 256~ JPEG // 20 ~ YUY2 ~ YcbCr ... // 842094169 ~ YV12 ~ 4:2:0 YCrCb comprised of WXH Y plane, W/2xH/2 Cr & Cb. see documentation Log.v("CameraTest","Supported preview format:"+previewFormat); if (previewFormat == ImageFormat.YV12) { parameters.setPreviewFormat(previewFormat); Log.v("CameraTest","SETTING FANCY YV12 FORMAT"); } } 

http://developer.android.com/reference/android/graphics/ImageFormat.html#YV12 describe el formato. Esto, además de algunos búferes de reserva, me da “intervalos de tiempo” de tan solo 80 … que todavía no es “lo suficientemente bueno”, pero … ¿mejor? (De hecho, tengo uno a los 69 … pero en realidad, son más o menos 90 en promedio). ¿No estás seguro de cuánto la tala está ralentizando las cosas?

Configurar el tamaño de la vista previa a 320×240 (frente a 1280×720) hace que las cosas bajen al rango de 50-70msec … ¿entonces quizás eso es lo que tiene que hacer? Es cierto que esos pequeños datos pueden ser mucho menos útiles.

// todos probados en Nexus4

Por lo general, declaro un boolean lockCameraUse global. La función de callback generalmente se ve así.

  public void onPreviewFrame(byte[] data, Camera camera) { if (lockCameraUse) { camera.addCallbackBuffer(data); return; } lockCameraUse = true; // processinng data // done processing data camera.addCallbackBuffer(data); lockCameraUse = false; return; }