理解和加速 addCallbackBuffer
Understanding and speeding up addCallbackBuffer
想了解传递给addCallbackBuffer
的预览缓冲区与onPreviewFrame
传递的byte[]
数组有什么关系,从而提示以下相关问题。
Q1。我猜测传入 addCallbackBuffer
的缓冲区用于存储新的相机帧,并且在调用 onPreviewFrame
之前,该缓冲区被复制到通过 onPreviewFrame
传递的数据缓冲区中。如果是这样,那意味着我可以通过在输入 onPreviewFrame
后立即调用 addCallbackBuffer
来重用我的预览帧缓冲区,并在处理完返回的缓冲区时在函数末尾注明通过 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
执行时捕获帧?如果不是这种情况,那么拥有两个回调缓冲区将无助于提高速度,对吗?
这对我有用:
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();
}
您可以选择回调的数量,回调越多,您将获得 onPreviewFrame。
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)
{
如果(mCamera!= null)
{
mCamera.setPreviewCallback(空);
mCamera.stopPreview();
mCamera.release();
}
mCamera = null;
}
Q1 是的,如果你不关心它的内容,你可以 return 尽早将缓冲区缓存到相机。为它调用 addCallbackBuffer()
后,您可能无法从该缓冲区读取,或者您可以读取,但像素数据将是错误的。
Q2 您可以简单地 return 拍摄您在回调中收到的缓冲区,即
@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 线程分离。
想了解传递给addCallbackBuffer
的预览缓冲区与onPreviewFrame
传递的byte[]
数组有什么关系,从而提示以下相关问题。
Q1。我猜测传入 addCallbackBuffer
的缓冲区用于存储新的相机帧,并且在调用 onPreviewFrame
之前,该缓冲区被复制到通过 onPreviewFrame
传递的数据缓冲区中。如果是这样,那意味着我可以通过在输入 onPreviewFrame
后立即调用 addCallbackBuffer
来重用我的预览帧缓冲区,并在处理完返回的缓冲区时在函数末尾注明通过 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
执行时捕获帧?如果不是这种情况,那么拥有两个回调缓冲区将无助于提高速度,对吗?
这对我有用:
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();
}
您可以选择回调的数量,回调越多,您将获得 onPreviewFrame。
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) { 如果(mCamera!= null) { mCamera.setPreviewCallback(空); mCamera.stopPreview(); mCamera.release(); } mCamera = null; }
Q1 是的,如果你不关心它的内容,你可以 return 尽早将缓冲区缓存到相机。为它调用 addCallbackBuffer()
后,您可能无法从该缓冲区读取,或者您可以读取,但像素数据将是错误的。
Q2 您可以简单地 return 拍摄您在回调中收到的缓冲区,即
@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 线程分离。