我正在开发相机应用程序,你需要提取每帧预览的一些数据,所以我试图用onPreviewFrame来做,问题是我的代码onPreviewFrame只调用一次而调试我不得到错误所以我不知道该怎么做
这是我的代码
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
public byte[] buffer;//for previewcallback
public CameraPreview(Context context, Camera camera) {
super(context);
Log.d("Function", "CameraPreview constructor iniciado");
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
Log.d("Function", "SurfaceCreated iniciado");
try {
mCamera.setPreviewDisplay(holder);
buffer = previewBuffer();
mCamera.addCallbackBuffer(buffer);
mCamera.setPreviewCallbackWithBuffer(previewCallback);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
Log.d("Function", "SurfaceDestroyed iniciado");
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
Log.d("Function", "surfaceChanged iniciado");
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
buffer = previewBuffer();
mCamera.addCallbackBuffer(buffer);
mCamera.setPreviewCallbackWithBuffer(previewCallback);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
//Create the callback to access preview frames
PreviewCallback previewCallback = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
Log.d("Function", "onPreviewFrame iniciado");
//Convert to jpg
Size previewSize = camera.getParameters().getPreviewSize();
Log.d("Function", "onPreviewFrame: preview size=" + previewSize.height + " " + previewSize.width);
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 80, baos);
byte jpgData[] = baos.toByteArray();
}
};
//To create a buffer of the preview bytes size
private byte[] previewBuffer() {
Log.d("Function", "previewBuffer iniciado");
int bufferSize;
byte buffer[];
int bitsPerPixel;
Camera.Parameters mParams = mCamera.getParameters();
Camera.Size mSize = mParams.getPreviewSize();
Log.d("Function", "previewBuffer: preview size=" + mSize.height + " " + mSize.width);
int mImageFormat = mParams.getPreviewFormat();
if (mImageFormat == ImageFormat.YV12) {
int yStride = (int) Math.ceil(mSize.width / 16.0) * 16;
int uvStride = (int) Math.ceil((yStride / 2) / 16.0) * 16;
int ySize = yStride * mSize.height;
int uvSize = uvStride * mSize.height / 2;
bufferSize = ySize + uvSize * 2;
buffer = new byte[bufferSize];
Log.d("Function", "previewBuffer: buffer size=" + Integer.toString(bufferSize));
return buffer;
}
bitsPerPixel = ImageFormat.getBitsPerPixel(mImageFormat);
bufferSize = (int) (mSize.height * mSize.width * ((bitsPerPixel / (float) 8)));
buffer = new byte[bufferSize];
Log.d("Function", "previewBuffer: buffer size=" + Integer.toString(bufferSize));
return buffer;
}
}
答案 0 :(得分:17)
收到addCallbackBuffer添加的预览缓冲区后,您需要在完成后将其还原到相机(否则,相机可能会在您使用完之前覆盖您的数据) )。因此,一旦您在onPreviewFrame调用中使用了数据字节数组,请再次使用addCallbackBuffer将其返回给摄像机。
您可能还需要考虑在设置相机时添加两个或更多回调缓冲区。如果没有可供使用的空闲缓冲区,摄像机将丢弃帧,因此如果您在处理过程中偶尔出现故障或其他延迟,则自由使用一些缓冲区可以平滑帧速率。