不为SurfaceView上显示的每个帧调用onPreviewFrame

时间:2013-09-17 20:25:57

标签: android android-camera surfaceview

我的SurfaceView的子类实现Camera.PreviewCallback& 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());
        }
    }
}

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;
}

即使相机预览非常流畅,onPreviewFrame()方法也只会被调用大约5次。为什么不是每个帧都被调用?

2 个答案:

答案 0 :(得分:6)

你可能已经知道了:Camera.setPreviewCallback()对垃圾收集器施加了太大的压力。您可以使用Camera.setPreviewCallbackWithBuffer()代替。

其次,如果onPreviewFrame()到达主(UI)线程,那么它会与触摸,布局甚至渲染等UI事件竞争单个CPU时间。要在单独的线程上保持onPreviewFrame(),你应该在辅助Looper线程上打开()相机,参见例如https://stackoverflow.com/a/19154438/192373

第三,即使在这种情况下,预览回调也是序列化的。如果fpscounter.logFrame()Log().d需要X毫秒,则FPS不会超过1000 / X.

答案 1 :(得分:0)

每帧都需要它。您可以参考相机的在线reference。看看这句话“除了在屏幕上显示之外,还为每个预览帧安装一个回调函数。”