简体   繁体   English

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

[英]Getting android camera2 preview frames without lagging the screen preview

In the original (now deprecated) camera API, we used to be able to get preview frames in the Camera.PreviewCallback and be able to process it (taking possibly very long) and release the buffer to be able to receive another frame, without lagging the screen preview, with some code like the following: 在原始(现已弃用)的相机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();
}

The API would only callback with a new frame if there was another buffer available to receive it, without lagging the screen preview. 如果有另一个可用于接收它的缓冲区,API将仅使用新帧进行回调,而不会滞后屏幕预览。

I'm trying to replicate the same behaviour on the new Camera2 API, but I can't find a way to do it without lagging the screen preview. 我试图在新的Camera2 API上复制相同的行为,但我找不到一种方法来做到这一点而不会滞后于屏幕预览。 If I add a second target (same resolution as the screen one, YUV_420_888) to the preview request: 如果我向预览请求添加第二个目标(与屏幕1相同的分辨率,YUV_420_888):

mPreviewRequestBuilder.addTarget(surface);
mPreviewRequestBuilder.addTarget(previewImageReader.getSurface());
mCameraDevice.createCaptureSession(
    Arrays.asList(surface, previewImageReader.getSurface()), ...

the screen preview will lag, even if I just close the image as soon as I get it: 屏幕预览会滞后,即使我只是在我得到它时立即关闭图像:

@Override
public void onImageAvailable(ImageReader reader) {
    reader.acquireNextImage().close();
}

What's the correct way to use Camera2 to emulate the original camera API behaviour (ie having a new buffer whenever one is free and not slowing the screen preview)? 使用Camera2模拟原始相机API行为的正确方法是什么(即,只要有一个空闲且没有减慢屏幕预览,就会有一个新的缓冲区)?

Update: In case anyone is wondering how the rest of the code looks like, it is just a modified version of the standard android-camera2Basic sample, here's what I've changed . 更新:如果有人想知道代码的其余部分是什么样的,它只是标准android-camera2Basic示例的修改版本, 这就是我改变的内容

If anyone is still interested. 如果有人仍然感兴趣。

Create a SurfaceTextureListener and call your async function from the onSurfaceTextureUpdated method. 创建一个SurfaceTextureListener并从onSurfaceTextureUpdated方法调用您的异步函数。 I have used this successfully when checking frames for barcodes with the BarcodeDetection API and the Camera 2 API. 在使用BarcodeDetection API和Camera 2 API检查条形码的帧时,我已成功使用此功能。

Here is a sample of an async function launched from the onSurfaceTextureUpdated method. 以下是从onSurfaceTextureUpdated方法启动的异步函数示例。 If you only want to run one async task in the background at a time, you can use a flag to check if the previous task has completed. 如果您只想在后台运行一个异步任务,则可以使用标志来检查上一个任务是否已完成。

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

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM