son segundo que por pantalla los grabar fotogramas fotografías entre diferencia cuadros como cine 60fps android camera preview

android - segundo - grabar pantalla 60fps



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

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

Verifique cuidadosamente si su registro está lleno de declaraciones de recolector de basura. Este es el caso si se agregan muy pocos buffers. Este había sido el truco para mí. ¡Al menos vine a sumar 20! tampones a la cámara.

Luego, el procesamiento de cada cuadro debe tener lugar en un hilo separado. Mientras una imagen está en el hilo para procesar, la devolución de llamada debe omitir el cuadro actual.

Necesito obtener datos de vista previa en bruto del objeto Cámara al menos 15 fotogramas por segundo , pero solo puedo obtener un fotograma en 110 milisegundos, lo que significa que puedo obtener solo 9 fotogramas 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 se llama onPreviewFrame (byte [] data, Camera Camera) cada 110 milisegundos, por lo que no puedo obtener más de 9 cuadros por segundo. Y no importa qué velocidad de fotogramas 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 fotogramas 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<int[]> supportedPreviewFps=parameters.getSupportedPreviewFpsRange(); Iterator<int[]> 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<Size> supportedPreviewSizes=parameters.getSupportedPreviewSizes(); Iterator<Size> 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

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="test.cameratest" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="10" android:maxSdkVersion="10"/> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permission android:name="android.permission.BOOT_COMPLETED"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".CameraTestActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>


Mi experiencia con las cosas de la cámara ha sido delicada y dependiente del hardware. Intente ejecutarlo en otro hardware si es posible.

También podría valer la pena probar algunos ajustes más de la cámara.

Gracias por incluir un código de ejemplo por cierto.


Por lo general declaro un lockCameraUso booleano global. La función de devolución de llamada 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; }


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 fotograma establecido por el hardware o firmware de la cámara. La velocidad de fotogramas 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.


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 fotogramas definida, tendrá que capturar video y luego analizar / descomprimir la transmisión binaria resultante.


Una cosa que parece aumentar 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<Integer> supportedPreviewFormats = parameters.getSupportedPreviewFormats(); Iterator<Integer> 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?

Establecer el tamaño de la vista previa en 320x240 (en lugar de 1280x720) hace que las cosas alcancen el rango de 50-70msec ... así que tal vez eso es lo que necesita hacer. Es cierto que esa poca información puede ser mucho menos útil.

// todos probados en Nexus4