我有一个扩展 SurfaceView 并实现 Camera.PreviewCallback 的类。在这个类中,我将相机设置为预览到提供的缓冲区(setPreviewCallbackWithBuffer)和几个缓冲区(addCallbackBuffer)。在我调用 startPreview 后,成功调用了 onPreviewFrame 回调。在 onPreviewFrame 中,我将工作交给另一个线程,该线程进行一些处理并最终将数据可视化。
但是,我注意到有时不再调用 onPreviewFrame 了。在探索这个问题的过程中,我观察到它最有可能发生在处理 1280x720 帧(相机支持)时,但它也发生在较低的分辨率上,但频率较低。我最终将代码简化为一个几乎为空的 onPreviewFrame(它只记录接收呼叫并再次调用 addCallbackBuffer;仅此而已)。处理线程未启动。可以观察到相同的行为。
在这种情况下,有 3 个缓冲区用于 1280x720 的预览,这将运行大约 20 分钟,然后不再调用 onPreviewFrame。Logcat 没有显示任何其他问题。这 20 分钟各不相同,有时是 5 分钟,有时不到一分钟。使用日志记录,我验证了每个 onPreviewFrame 调用的缓冲区序列是相当干净的(buffer1、buffer2、buffer3、buffer1、buffer2,...)。
我正在使用的设备是 Galaxy Tab 2(使用 Android 4.2.2 CyanogenMod);但我也在其他使用库存 rom 的设备上看到了这一点 - 所以我怀疑这是由于 rom 造成的。
所以我想这涉及到这些问题:
- 我需要提供多少缓冲区(给定一定的分辨率和一定的处理时间)?
- 为什么不再调用 onPreviewFrame (当时是空闲缓冲区)?
相关代码归结为:
private void startPreview()
{
Camera.Parameters parameters = mCamera.getParameters();
int width = 1280;
int height = 720;
Resolution bestCameraResolution = getBestCameraResolutionMatch(width, height);
width = bestCameraResolution.width();
height = bestCameraResolution.height();
parameters.setPreviewSize(width, height);
mCamera.setParameters(parameters);
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
// calculate imageBufferSize here...
mCamera.addCallbackBuffer(new byte[imageBufferSize]);
mCamera.addCallbackBuffer(new byte[imageBufferSize]);
mCamera.addCallbackBuffer(new byte[imageBufferSize]);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
Log.d(TAG, "Start preview with " + width + "x" + height);
}
@Override
public void onPreviewFrame(byte[] frameData, Camera camera)
{
// Log to a separate tag to allow better filtering
Log.d(TAG + "Frame", "preview frame on buffer " + frameData.toString());
// Give used buffer back for future grabbing
if (mCamera != null) {
mCamera.addCallbackBuffer(frameData);
}
}