首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >安卓Camera2,连续拍照

安卓Camera2,连续拍照
EN

Stack Overflow用户
提问于 2017-02-13 23:03:11
回答 2查看 5.5K关注 0票数 2

我需要使用Camera2 API连续拍照。它在高端设备(比如Nexus5X)上工作得很好,但对于速度较慢的设备(比如三星Galaxy A3),预览版就会冻结。

代码有点长,所以我只发布最相关的部分:

方法来启动我的预览:

代码语言:javascript
运行
复制
private void startPreview() {

    SurfaceTexture texture = mTextureView.getSurfaceTexture();

    if(texture != null) {

        try {

            // We configure the size of default buffer to be the size of camera preview we want.
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

            // This is the output Surface we need to start preview.
            Surface surface = new Surface(texture);

            // We set up a CaptureRequest.Builder with the output Surface.
            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequestBuilder.addTarget(surface);

            // Here, we create a CameraCaptureSession for camera preview.
            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {

                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {

                        // If the camera is already closed, return:
                        if (mCameraDevice == null) { return; }

                        // When the session is ready, we start displaying the preview.
                        mCaptureSession = cameraCaptureSession;

                        // Auto focus should be continuous for camera preview.
                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                        mPreviewRequest = mPreviewRequestBuilder.build();

                        // Start the preview
                        try { mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mPreviewBackgroundHandler); }
                        catch (CameraAccessException e) { e.printStackTrace(); }
                    }

                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                        Log.e(TAG, "Configure failed");
                    }
                }, null
            );
        }
        catch (CameraAccessException e) { e.printStackTrace(); }
    }
}

方法来拍摄照片:

代码语言:javascript
运行
复制
private void takePicture() {

    try {

        CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(mImageReader.getSurface());
        mCaptureSession.capture(captureBuilder.build(), null, mCaptureBackgroundHandler);
    }
    catch (CameraAccessException e) { e.printStackTrace(); }
}

这是我的ImageReader:

代码语言:javascript
运行
复制
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {

    @Override
    public void onImageAvailable(final ImageReader reader) {

        mSaveBackgroundHandler.post(new Runnable() {

            @Override
            public void run() {

                // Set the destination file:
                File destination = new File(getExternalFilesDir(null), "image_" + mNumberOfImages + ".jpg");
                mNumberOfImages++;

                // Acquire the latest image:
                Image image = reader.acquireLatestImage();

                // Save the image:
                ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);

                FileOutputStream output = null;
                try {
                    output = new FileOutputStream(destination);
                    output.write(bytes);
                }
                catch (IOException e) { e.printStackTrace(); }
                finally {

                    image.close();

                    if (null != output) {

                        try { output.close(); }
                        catch (IOException e) { e.printStackTrace(); }
                    }
                }

                // Take a new picture if needed:
                if(mIsTakingPictures) {
                    takePicture();
                }
            }
        });
    }
};

我有一个按钮,可以切换mIsTakingPictures布尔值,并进行第一个takePicture调用。

综上所述,我使用了3个线程:

  • 一张用于预览
  • 一张是抓捕的
  • 一个用于图像保存

冻结的原因是什么?

EN

回答 2

Stack Overflow用户

发布于 2017-02-15 14:54:09

当你在脆弱的设备上拍摄图像时,不可能避免在你的预览中丢失帧。避免这种情况的唯一方法是在支持TEMPLATE_ZERO_SHUTTER_LAG和使用reprocessableCaptureSession的设备上。关于这方面的文档是相当可怕的,并且找到一种方法来实现它可能是一个奥德赛。几个月前,我遇到了这个问题,最后我找到了实现它的方法:

How to use a reprocessCaptureRequest with camera2 API

在这个答案中,您还可以找到一些Google测试,它也实现了ReprocessableCaptureSession,并使用ZSL模板拍摄了一些突发捕获。

最后,您还可以使用带有预览面和图像读取器界面的CaptureBuilder,在这种情况下,预览将继续工作,并且还可以将每一帧保存为新图片。但你还是会有冻结的问题。

我还尝试使用一个处理程序实现一个突发捕获,该处理程序每100毫秒发送一个新的capture调用,第二个选项的性能相当好,并且避免了帧速率丢失,但是您不会像两个ImageReader选项那样每秒获得那么多的捕获。

希望我的答案能对你有所帮助,API 2仍然有点复杂,而且没有太多的例子或信息。

票数 2
EN

Stack Overflow用户

发布于 2017-03-13 16:48:36

在低端设备上,我注意到了一件事:预览在捕获后停止,即使使用了Camer1API,因此必须手动重新启动它,从而在捕获高分辨率图片时产生一个小的预览冻结。

但是,相机2 api提供了在拍摄静态捕捉时获取原始图像的可能性(这在我使用相机1(华为P7、索尼Xperia E5、wiko UFeel)时是不可能的)。使用此功能比捕获JPEG (可能是由于JPEG压缩)要快得多,因此可以更早地重新启动预览,并且预览冻结时间更短。当然,使用此解决方案,您必须在后台任务中将图片从YUV转换为JPEG。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42215106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档