获取android camera2预览帧而不会滞后屏幕预览

时间:2016-09-12 06:17:05

标签: android android-camera android-camera2

在原始(现已弃用)相机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的修改版本。

2 个答案:

答案 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) {

    }
}