我想了解传递给addCallbackBuffer
的预览缓冲区如何与通过byte[]
传递的onPreviewFrame
数组相关联,这会引发以下相关问题。
Q1。我猜测addCallbackBuffer
中传递的缓冲区用于存储新的相机帧,并且在调用onPreviewFrame
之前,该缓冲区被复制到通过onPreviewFrame
传递的数据缓冲区中。如果是这种情况,这意味着我可以在输入addCallbackBuffer
后立即通过调用onPreviewFrame
来重用我的预览帧缓冲区,并在完成处理返回的缓冲区后在函数末尾注意按onPreviewFrame
。这是对的吗?
Q2。我也不清楚使用两个预览帧缓冲区的机制。假设我在初始化期间添加了两个私有byte[]
预览缓冲区,如下所示:
addCallbackBuffer(mPreviewBuffer1);
addCallbackBuffer(mPreviewBuffer2);
当我在onPreviewFrame
时,如何知道使用了哪个预览缓冲区,以便我可以再次使用addCallbackBuffer
重新添加正确的预览帧缓冲区?
private byte[] mPreviewBuffer1;
private byte[] mPreviewBuffer1;
...
public void onPreviewFrame(byte[] camera, Camera c) {
...
// how do I decide which buffer to re-add?
//c.addCallbackBuffer(mPreviewBuffer1);
//c.addCallbackBuffer(mPreviewBuffer2);
...
}
Q3。我是否正确理解另一个线程负责获取帧缓冲区,即只要预览缓冲区在队列中,我们将在onPreviewFrame
执行时捕获帧?如果情况并非如此,那么拥有两个回调缓冲区对速度没有帮助,是吗?
答案 0 :(得分:3)
Q1 是的,如果您不关心其内容,可以提前将缓冲区返回到摄像机。您可以在致电addCallbackBuffer()
之后读取此缓冲区,或者您可以阅读,但像素数据将会出错。
Q2 你可以简单地将你在回调时收到的缓冲区返回相机,即
@Override public void onPreviewFrame(byte[] data, Camera camera) {
…
camera.addCallbackBuffer(data);
}
在这种情况下,您不关心data == mPreviewBuffer1
或data == mPreviewBuffer2
。但是下面的代码也没关系:
private byte[][] mPrevieBuffers = new byte[4][];
@Override public void onPreviewFrame(byte[] data, Camera camera) {
for (int i=0; i<mPreviewBuffers.length; i++) {
if (data == mPreviewBuffers[i]) {
processData(i);
}
}
}
Q3 正确,onPreviewFrame()
与填充其他缓冲区并行执行,但所有onPreviewFrame()
回调都在同一个线程上调用。如果要处理尽可能多的预览帧,则应 a)将处理委派给工作线程(尤其是在多核设备上)。请注意,您可以从其他线程安全地调用addCallbackBuffer()
; b) start the camera on a separate Looper让onPreviewFrame()
与UI线程分离。
答案 1 :(得分:1)
这对我有用:
public void surfaceChanged(SurfaceHolder holder, int format, int ww, int hh)
{
if (mCamera == null) return;
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
//get camera parameters
prepareSizeScreen();
mCamera.setParameters(mMyCameraParameters.makeParameters(mCamera.getParameters(), mSizeScreen));
try
{
mCamera.setPreviewDisplay(mHolder);
} catch (Exception e)
{
}
Camera.Size setSize = mCamera.getParameters().getPreviewSize();
int bufferSize = setSize.width * setSize.height
* ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat()) / 8;
setupCallback(bufferSize);//this is what you are looking for
mCamera.startPreview();
}
您可以选择更多回调次数,您可以更多地使用预览帧。
static final private int NUM_BUFFERS = 5;
private void setupCallback(int bufferSize)
{
mCamera.setPreviewCallbackWithBuffer(this);
for (int i = 0; i <= NUM_BUFFERS; ++i)
{
byte[] cameraBuffer = new byte[bufferSize];
mCamera.addCallbackBuffer(cameraBuffer);
}
}
当你收到回电时,你应该使用与设置另一个回调相同的数据。
@Override
public void onPreviewFrame(byte[] data, Camera camera)
{//data has NV21 format
processData(data);
camera.addCallbackBuffer(data);//same data is sent for another callback. So you will be managing NUM_BUFFERS at all times.
}
不要忘记onDestroy: public void surfaceDestroyed(SurfaceHolder holder) { if(mCamera!= null) { mCamera.setPreviewCallback(NULL); mCamera.stopPreview(); mCamera.release(); } mCamera = null; }