Android Camera onPreviewFrame frame rate not consistent

xiaowoo picture xiaowoo · Nov 12, 2013 · Viewed 7.8k times · Source

I am trying to encode a 30 frames per second video using MediaCodec through the Camera's PreviewCall back(onPreviewFrame). The video that I encoded always plays very fast(this is not desired). So, I tried to check the number of frames that is coming into my camera's preview by setting up a int frameCount variable to remember its count. What I am expecting is 30 frames per second because I setup my camera's preview to have 30 fps preview(as shown below). The result that I get back is not the same. I called the onPreviewFrame callback for 10 second, the number of frameCount I get back is only about 100 frames. This is bad because I am expecting 300 frames. Is my camera parameters setup correctly? Is this a limitation of Android's Camera preview call back? And if this is a limitation on the Android Camera's preview call back, then is there any other camera callback that can return the camera's image data(nv21,yuv, yv12) in 30 frames per second?

thanks for reading and taking your time to helpout. i would appreciate any comments and opinions.

Here is an example an encoded video using Camera's onPreviewFrame:

http://www.youtube.com/watch?v=I1Eg2bvrHLM&feature=youtu.be

                Camera.Parameters parameters = mCamera.getParameters();
                parameters.setPreviewFormat(ImageFormat.NV21);
                parameters.setPictureSize(previewWidth,previewHeight);
                parameters.setPreviewSize(previewWidth, previewHeight);
//              parameters.setPreviewFpsRange(30000,30000);

                parameters.setPreviewFrameRate(30);
                mCamera.setParameters(parameters);

                mCamera.setPreviewCallback(previewCallback);
                mCamera.setPreviewDisplay(holder);

Answer

Alex Cohn picture Alex Cohn · Nov 12, 2013

No, Android camera does not guarantee stable frame rate, especially at 30 FPS. For example, it may choose longer exposure at low lighting conditions.

But there are some ways we, app developers, can make things worse.

First, by using setPreviewCallback() instead of setPreviewCallbackWithBuffer(). This may cause unnecessary pressure on the garbage collector.

Second, if onPreviewFrame() arrives on the main (UI) thread, you cause any UI action directly delay the camera frames arrival. To keep onPreviewFrame() on a separate thread, you should open() the camera on a secondary Looper thread. Here I explained in detail how this can be achieved: Best use of HandlerThread over other similar classes.

Third, check that processing time is less than 20ms.