使用ImageReader后,Samsung Note5上的Camera2 API无法录制视频

6
正如标题所说,我在使用Camera2 API录制三星Note5的视频时遇到了问题。 我已经从Camera2Video示例中调整了代码,但不同之处在于我使用CamcorderProfile类的配置选项设置MediaRecorder,并且在开始录制视频之前预览时,我同时使用ImageReader捕获和呈现预览到SurfaceTexture(该示例不使用ImageReader)。 这是我的startVideoCapture函数(与示例几乎相同)。
private boolean startVideoCapture() {
    if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
        debugToast("Can't start video preview");
        return false;
    }
    try {           
        closePreviewSession();
        if(!setUpMediaRecorder())
        {
            debugToast("setUpMediaRecorder failed");
            return false;
        }
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        assert texture != null;
        texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
        List<Surface> surfaces = new ArrayList<Surface>();

        Surface previewSurface = new Surface(texture);
        surfaces.add(previewSurface);
        previewRequestBuilder.addTarget(previewSurface);

        Surface recorderSurface = mMediaRecorder.getSurface();
        surfaces.add(recorderSurface);
        previewRequestBuilder.addTarget(recorderSurface);

        mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {

            @Override
            public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                debugToast("onConfigured callback received");
                mCaptureSession = cameraCaptureSession;
                updateVideoPreview(previewRequestBuilder);
            }

            @Override
            public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                debugToast("onConfigureFailed");                    
            }
        }, mCallbacksInterface.getBackgroundHandler());
    } catch (CameraAccessException e) {
        e.printStackTrace();
        debugToast("CameraAccessException");
        return false;
    } catch (IOException e) {
        e.printStackTrace();
        debugToast("IOException");
        return false;
    }
    debugToast("startVideoCapture success");        
    return true;
}

以下是我设置图像阅读器的代码,用于启动预览:

        // We set up a CaptureRequest.Builder with the output Surface.
        CaptureRequest.Builder previewRequestBuilder = mCameraDevice
                .createCaptureRequest(templateType);

        previewRequestBuilder.addTarget(mImageReader.getSurface());
        previewRequestBuilder.addTarget(surface);

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

        // etc...

这些都是非常标准的内容,并且在Nexus 5上运行良好:我可以在捕获表面列表中使用ImageReader开始一个预览捕获会话,然后停止它并在表面列表中使用MediaRecorder启动新的捕获会话并录制视频。但是,在Note5上无法正常工作。当在startVideoCapture中使用MediaRecorder调用createCaptureSession时会崩溃:

10-14 14:49:25.991: E/CameraCaptureSession(13566): Session 1: Failed to create capture session; configuration failed
10-14 14:49:26.011: W/System.err(13566): android.hardware.camera2.CameraAccessException: Operation timed out in camera service
10-14 14:49:26.011: W/System.err(13566):    at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:118)
10-14 14:49:26.021: W/System.err(13566):    at android.hardware.camera2.utils.CameraBinderDecorator$CameraBinderDecoratorListener.onAfterInvocation(CameraBinderDecorator.java:73)
10-14 14:49:26.021: W/System.err(13566):    at android.hardware.camera2.utils.Decorator.invoke(Decorator.java:81)
10-14 14:49:26.021: W/System.err(13566):    at java.lang.reflect.Proxy.invoke(Proxy.java:393)
10-14 14:49:26.021: W/System.err(13566):    at $Proxy1.waitUntilIdle(Unknown Source)
10-14 14:49:26.021: W/System.err(13566):    at android.hardware.camera2.impl.CameraDeviceImpl.waitUntilIdle(CameraDeviceImpl.java:950)
10-14 14:49:26.021: W/System.err(13566):    at android.hardware.camera2.impl.CameraDeviceImpl.configureStreamsChecked(CameraDeviceImpl.java:399)
10-14 14:49:26.021: W/System.err(13566):    at android.hardware.camera2.impl.CameraDeviceImpl.createCaptureSessionInternal(CameraDeviceImpl.java:561)
10-14 14:49:26.021: W/System.err(13566):    at android.hardware.camera2.impl.CameraDeviceImpl.createCaptureSession(CameraDeviceImpl.java:476)
10-14 14:49:26.021: W/System.err(13566):    at com.example.Camera2Object.startVideoCapture(Camera2Object.java:2262)

如果我从预览捕获中移除ImageReader,那么它就可以正常工作。
无论我是否在closePreviewSession中关闭ImageReader都没有任何区别(我已经在预览CaptureSession上调用了abortCapturesclose)。
有人知道如何解决这个问题吗?
编辑:可能相关的一件事是,在此设备上使用ImageReader时,在onPause中关闭CameraDevice需要非常长的时间(长达6秒)。我已经通过在单独的线程中执行它来将其大部分隐藏在用户视野之外,但是如果在onPause后的6秒内调用onResume,则会出现延迟,因为我必须等待它完成关闭才能再次打开它。显然,当开始录制视频时,我无法承受6秒的延迟。
即使我只调用acquireLatestImage(),关闭它并立即在ImageReaderonImageAvailable回调中返回,问题仍然存在。当ImageReader的捕获分辨率非常小时,也会发生这种情况。因此,似乎不是由于处理ImageReader数据过载引起的。 这里是从应用程序启动到录制视频(以及应用程序关闭)期间涵盖的系统日志。

如果您拥有覆盖应用程序启动和尝试启动视频录制的时间段的完整系统日志(logcat)输出,那么更容易了解发生了什么。这将包括来自相机服务和相机HAL的日志记录。 - Eddy Talvala
@EddyTalvala,日志太大了,无法编辑到问题中,因此我在这里发布了它:http://pastebin.com/uqyaC5aM - samgak
1个回答

3

从你的pastebin日志中:

10-15 19:45:32.501: E/Camera3-Device(3151): Camera 0: waitUntilDrainedLocked: Error waiting for HAL to drain: Connection timed out (-110)

这通常意味着相机HAL的内部出现了问题 - 相机服务正在等待正在进行的捕获完成,然后创建一个新会话,但有些永远不会返回。因此,超时并向应用程序返回错误。

不幸的是,这是设备特定相机代码中的错误,因此三星需要修复它。

作为解决方法,您可以尝试停止重复请求,等待所有正在进行的请求完成(设备切换到“准备就绪”状态),然后创建新会话。然后没有仍在进行的捕获供HAL处理。

这将增加额外的延迟,并且预览将冻结更长一段时间,但在这种情况下可能更加健壮。


非常感谢,这个解决方法有效。对于其他遇到这个问题的人,请注意:在停止视频录制和重新启动预览时不需要做同样的事情。它会按预期工作。 - samgak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接