0

我的子类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 次左右。为什么不是每帧都调用它?

4

2 回答 2

6

您可能已经想通了:Camera.setPreviewCallback() 对垃圾收集器施加了太大的压力。您可以改用 Camera.setPreviewCallbackWithBuffer()。

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

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

于 2013-11-12T08:45:23.023 回答
0

每一帧都会调用它。可以参考Camera的在线参考。看看这句话“除了在屏幕上显示它们之外,还为每个预览帧安装要调用的回调”。

于 2013-09-18T02:40:33.223 回答