在原始(现已弃用)相机API中,我们曾经能够在Camera.PreviewCallback中获取预览帧并能够处理它(可能需要很长时间)并释放缓冲区以便能够接收另一帧,没有滞后于屏幕预览,使用如下代码:
public void onPreviewFrame(final byte[] data, Camera camera) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
(... do some slow processing ...)
}
@Override
protected void onPostExecute(Void aVoid) {
mCamera.addCallbackBuffer(data); // free the buffer to be able
// to process another frame
}
}.execute();
}
如果有另一个可用于接收它的缓冲区,API将仅使用新帧进行回调,而不会滞后屏幕预览。
我正在尝试在新的Camera2 API上复制相同的行为,但我找不到一种方法来做到这一点而不会滞后于屏幕预览。如果我向预览请求添加第二个目标(与屏幕1相同的分辨率,YUV_420_888):
mPreviewRequestBuilder.addTarget(surface);
mPreviewRequestBuilder.addTarget(previewImageReader.getSurface());
mCameraDevice.createCaptureSession(
Arrays.asList(surface, previewImageReader.getSurface()), ...
屏幕预览会滞后,即使我只是在我得到它时立即关闭图像:
@Override
public void onImageAvailable(ImageReader reader) {
reader.acquireNextImage().close();
}
使用Camera2模拟原始相机API行为的正确方法是什么(即,只要有一个空闲且没有减慢屏幕预览,就会有一个新的缓冲区)?
更新:如果有人想知道代码的其余部分是什么样的,它只是标准android-camera2Basic样本here's what I've changed的修改版本。
答案 0 :(得分:3)
如果有人仍然感兴趣。
创建SurfaceTextureListener
并从onSurfaceTextureUpdated
方法调用异步函数。使用BarcodeDetection API和Camera 2 API检查条形码的帧时,我成功地使用了它。
答案 1 :(得分:0)
这是从onSurfaceTextureUpdated
方法启动的异步函数的示例。如果您只想一次在后台运行一个异步任务,则可以使用一个标志来检查上一个任务是否已完成。
private final TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
boolean processing;
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
if (processing) {
return;
}
processing = true;
Bitmap photo = mTextureView.getBitmap();
new ImageTask(photo, new ImageResponse() {
@Override
public void processFinished() {
processing = false;
}
}).execute();
}
};
private interface ImageResponse {
void processFinished();
}
private class ImageTask extends AsyncTask<Void, Void, Exception> {
private Bitmap photo;
private ImageResponse imageResponse;
ImageTask(Bitmap photo, ImageResponse imageResponse) {
this.photo = photo;
this.imageResponse = imageResponse;
}
@Override
protected Exception doInBackground(Void... params) {
// do background work here
imageResponse.processFinished();
return null;
}
@Override
protected void onPostExecute(Exception result) {
}
}