OnPreviewFrame is not called for every frame that is displayed in SurfaceView

My subclass of SurfaceView implements Camera.PreviewCallback and SurfaceHolder.Callback .

 private SurfaceHolder mHolder; private Camera mCamera; private final FPSCounter fpscounter = new FPSCounter(); public MySurfaceView(Context context, AttributeSet attrs) { super(context, attrs); mHolder = getHolder(); mHolder.addCallback(this); } @Override public void onPreviewFrame(byte[] data, Camera camera) { fpscounter.logFrame(); Log.d("fps", String.valueOf(fpscounter.getLastFrameCount())); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { synchronized (this) { mCamera.stopPreview(); Camera.Parameters parameters = mCamera.getParameters(); parameters.setRecordingHint(true); parameters.setPreviewFormat(ImageFormat.NV21); mCamera.setParameters(parameters); try { mCamera.setPreviewDisplay(holder); mCamera.setPreviewCallback(this); mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } } @Override public void surfaceCreated(SurfaceHolder holder) { synchronized (this) { setWillNotDraw(false); mCamera = Camera.open(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { synchronized (this) { try { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); } } catch (Exception e) { Log.e("cam error", e.getMessage()); } } } 

and class FPSCounter

 private long startTime; private int frames, lastFrameCount; public void logFrame() { frames++; if (System.nanoTime() - startTime >= 1000000000) { lastFrameCount = frames; frames = 0; startTime = System.nanoTime(); } } public int getLastFrameCount() { return lastFrameCount; } 

Although the camera preview is extremely smooth, the onPreviewFrame() method is called only 5 times per second. Why is it not called for every frame?

0
source share
2 answers

You probably already understood: Camera.setPreviewCallback () puts too much pressure on the garbage collector. You can use Camera.setPreviewCallbackWithBuffer () instead.

Secondly, if onPreviewFrame () enters the main (UI) stream, then it competes for one processor time with user interface events such as touch, layout, or even rendering. To save onPreviewFrame () in a separate stream, you must open () the camera on the secondary Looper stream, see, for example, fooobar.com/questions/94582 / ....

Third, even in this case, preview callbacks are serialized. If fpscounter.logFrame() and Log().d accept X milliseconds, then FPS will not exceed 1000 / X.

+5
source

It is called for each frame. You can link to the online reference camera. Take a look at this sentence "Sets callback for each preview frame in addition to displaying them on the screen."

0
source

Source: https://habr.com/ru/post/959238/


All Articles