由于图像 Reader 表面,基于 camera2 API 的应用程序在某些设备中崩溃

APP based on camera2 API crash in certain devices due to an Image Reader surface

我遇到了这些神秘的 android' 问题之一(至少从我的角度来看)。我的应用程序通过 camera2 api 库管理设备的相机。在我的例子中,我有两个表面,其中之一来自 Image Reader 对象。接下来我定义我的捕获会话并将这些表面设置为目标。正如您在下面的代码中看到的,在这种情况下,我遵循的是典型的工作流程:

        // Create ImageReader Surface
        int max = 2;
        mReader = ImageReader.newInstance(mWidth, mHeight, ImageFormat.YV12, max);
        ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader mReader) {
                Image image = null;
                image = mReader.acquireLatestImage();
                if (image == null) {
                    return;
                }                           

                byte[] bytes = convertYUV420ToNV21(image);

                nativeVideoFrame(bytes);
                image.close();   
            }
        };

        if (OPENGL_SOURCE==2){
            nativeVideoInit(mWidth, mHeight, 0, false);
        }

        mReader.setOnImageAvailableListener(readerListener, mBackgroundHandler);

        // Create Texture Surface
        texture = createTexture();
        mSurfaceTexture = new SurfaceTexture(texture);
        mSurfaceTexture.setOnFrameAvailableListener(this);
        mSurfaceTexture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
        mSurface = new Surface(mSurfaceTexture);

        //Attach surfaces to CaptureRequest
        List<Surface> outputSurfaces = new ArrayList<Surface>(2);
        outputSurfaces.add(mReader.getSurface());
        outputSurfaces.add(mSurface);
        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        captureRequestBuilder.addTarget(mSurface);
        captureRequestBuilder.addTarget(mReader.getSurface());

        //Define the capture request
        cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback(){
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                        //The camera is already closed
                        if (null == cameraDevice) {
                            return;
                        }
                        // When the session is ready, we start displaying the preview.
                        cameraCaptureSessions = cameraCaptureSession;
                        updatePreview();
                    }
                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                        Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
                    }
                }, null);
        } catch (CameraAccessException e) {
             e.printStackTrace();
        }

问题是我在平板电脑 Samsung TAB A 上没有遇到任何问题 运行 此代码。但是,在我的 Nexus 5X 或我朋友的 Samsung S6 上尝试时,应用程序崩溃并抛出此错误:

08-23 11:28:51.772: E/AndroidRuntime(20315): 致命异常: main 08-23 11:28:51.772: E/AndroidRuntime(20315): 进程: com.example.opengltest, PID: 20315 08-23 11:28:51.772: E/AndroidRuntime(20315): java.lang.IllegalArgumentException: 传递给相机服务的参数错误 08-23 11:28:51.772: E/AndroidRuntime(20315): 在 android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:114)

做了一些测试,我发现问题出在图像 reader 表面。如果我从捕获会话的设置中删除此表面,代码将无缝运行。

为什么这种情况只发生在我的 Nexus 5x 或三星 S6 上,而不发生在我的平板电脑上?我该如何解决?

谢谢,

JM

如果你看一下整个系统logcat,相机服务应该有一个 更详细的行说明为什么你的输出表面集是坏的。

但是,YV12 不是保证支持的格式,所以可能就是这样。有些设备支持,有些不支持。

唯一保证所有设备都支持的 YUV 格式是 ImageFormat.YUV_420_888

如果您希望尽可能使用 YV12,则需要在尝试使用之前检查 StreamConfigurationMap.getOutputFormats() 列表以查看它是否已列出。但是您仍然需要在许多设备上回退到 YUV_420_888,因此最简单的方法是直接支持它,仅此而已。