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

Shu*_*uri 0 android surfaceview android-camera

我的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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

尽管相机预览非常流畅,但该onPreviewFrame()方法每秒仅调用约5次.为什么不是每个帧都要调用它?

Ale*_*ohn 6

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

其次,如果onPreviewFrame()到达主(UI)线程,那么它会与触摸,布局甚至渲染等UI事件竞争单个CPU时间.要在单独的线程上保持onPreviewFrame(),您应该在辅助Looper线程上打开()相机,请参阅例如/sf/answers/1340810691/.

第三,即使在这种情况下,预览回调也是序列化的.如果fpscounter.logFrame()并且Log().d采用X毫秒,那么FPS将不会超过1000/X.