Java 基于camera2 API的应用程序由于图像读取器表面而在某些设备中崩溃

Java 基于camera2 API的应用程序由于图像读取器表面而在某些设备中崩溃,java,android,android-camera,android-camera2,Java,Android,Android Camera,Android Camera2,我有一个神秘的安卓问题(至少在我看来)。我的应用程序通过camera2 api库管理设备的摄像头。在我的例子中,我有两个曲面,其中一个来自图像读取器对象。接下来,我定义捕获会话并将这些曲面设置为目标。正如您在下面的代码中所看到的,在这种情况下,我遵循典型的工作流: // Create ImageReader Surface int max = 2; mReader = ImageReader.newInstance(mWidth, mHeight,

我有一个神秘的安卓问题(至少在我看来)。我的应用程序通过camera2 api库管理设备的摄像头。在我的例子中,我有两个曲面,其中一个来自图像读取器对象。接下来,我定义捕获会话并将这些曲面设置为目标。正如您在下面的代码中所看到的,在这种情况下,我遵循典型的工作流:

        // 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();
        }
//创建ImageReader曲面
int max=2;
mReader=ImageReader.newInstance(mWidth,mHeight,ImageFormat.YV12,max);
ImageReader.OnImageAvailableListener readerListener=新建ImageReader.OnImageAvailableListener(){
@凌驾
公共图像可用(图像阅读器mReader){
图像=空;
image=mReader.acquiredlatestimage();
if(image==null){
返回;
}                           
byte[]bytes=convertYUV420ToNV21(图像);
本地视频帧(字节);
image.close();
}
};
如果(OPENGL_源代码==2){
nativeVideoInit(mWidth,mHeight,0,false);
}
mReader.setOnImageAvailableListener(readerListener,mBackgroundHandler);
//创建纹理曲面
纹理=createTexture();
mSurfaceTexture=新的表面纹理(纹理);
mSurfaceTexture.setOnFrameAvailableListener(此);
mSurfaceTexture.setDefaultBufferSize(imageDimension.getWidth(),imageDimension.getHeight());
mSurface=新曲面(mSurfaceTexture);
//将曲面附加到CaptureRequest
List outputSurfaces=新的ArrayList(2);
add(mReader.getSurface());
outputSurfaces.add(mSurface);
captureRequestBuilder=cameraDevice.createCaptureRequest(cameraDevice.TEMPLATE\u预览);
captureRequestBuilder.addTarget(mSurface);
addTarget(mReader.getSurface());
//定义捕获请求
cameraDevice.createCaptureSession(outputSurfaces,新的CameraCaptureSession.StateCallback(){
@凌驾
未配置公共void(@NonNull CameraCaptureSession CameraCaptureSession){
//摄像机已经关上了
如果(null==cameraDevice){
返回;
}
//当会话准备就绪时,我们开始显示预览。
cameraCaptureSessions=cameraCaptureSession;
updatePreview();
}
@凌驾
已配置公用void onconfig(@NonNull CameraCaptureSession CameraCaptureSession){
Toast.makeText(MainActivity.this,“配置更改”,Toast.LENGTH_SHORT.show();
}
},空);
}捕获(CameraAccessE异常){
e、 printStackTrace();
}
问题是,在我的平板电脑Samsung TAB A上运行此代码没有任何问题。但是,当在我的Nexus 5X或我朋友的Samsung S6上尝试时,应用程序突然崩溃,抛出以下错误:

08-23 11:28:51.772:E/AndroidRuntime(20315):致命异常:主 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)

做一些测试,我发现问题来自图像阅读器表面。如果我从捕获会话的设置中去掉这个表面,代码将无缝运行

为什么这只发生在我的Nexus 5x或三星S6上,而不发生在我的平板电脑上?我怎样才能修好它

谢谢


JM

如果查看整个系统日志,则摄像头服务应具有 更详细的行说明了输出曲面集不好的原因

然而,YV12并不是一种保证支持的格式,所以它可能就是这样。有些设备支持,有些不支持

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


如果您想在可能的情况下使用YV12,在尝试使用之前,您需要检查列表以查看是否列出了它。但是,在许多设备上,您仍然需要回到YUV_420_888,因此直接支持该功能而不支持其他功能是最简单的。

如果查看整个系统日志,相机服务应该有一个 更详细的行说明了输出曲面集不好的原因

然而,YV12并不是一种保证支持的格式,所以它可能就是这样。有些设备支持,有些不支持

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


如果您想在可能的情况下使用YV12,在尝试使用之前,您需要检查列表以查看是否列出了它。但在许多设备上,您仍然需要回到YUV_420_888,因此,直接支持它而不支持其他功能是最简单的。

这正是您所说的。那些设备不支持YV12格式,这正是你所说的。这些设备不支持YV12格式