使用 ImageReader 后,无法在三星 Note5 上使用 Camera2 API 录制视频

sam*_*gak 5 android samsung-mobile android-camera2

正如标题所说,我在使用 Camera2 API 在三星 Note5 上录制视频时遇到问题。

我已经从 Camera2Video 示例中修改了我的代码,但不同之处在于我设置了类中的MediaRecorderusing 配置选项,CamcorderProfile并且在开始视频录制之前进行预览时,我正在捕捉到一个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;
}
Run Code Online (Sandbox Code Playgroud)

这是我在开始预览时设置图像阅读器的代码:

        // 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...
Run Code Online (Sandbox Code Playgroud)

这一切都是非常标准的东西,并且在 Nexus 5 上运行良好:我可以使用ImageReader捕获表面列表中的开始一个用于预览的捕获会话,然后停止它并开始一个MediaRecorder在表面列表中使用 a 的新会话并记录一个视频。但是,这不适用于 Note5。createCaptureSession使用MediaRecorderin调用时发生崩溃startVideoCapture

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)
Run Code Online (Sandbox Code Playgroud)

如果我ImageReader从预览捕获中删除它,那么它工作正常。

我是否关闭ImageReaderinclosePreviewSession没有区别(我已经在调用abortCapturesclose预览CaptureSession)。

有谁知道如何解决这个问题?

编辑:这可能与东西使用,当ImageReader这个设备上,关闭CameraDeviceonPause采取一个可笑的很长一段时间(最多6秒)。我已经设法通过在单独的线程中对用户隐藏它,但是如果onResume在 6 秒内调用,onPause则会有延迟,因为我必须等待它完成关闭才能再次打开它。显然,在开始视频录制时,我无法承受 6 秒的延迟。

即使我除了调用acquireLatestImage()、关闭它并onImageAvailableImageReader. 当 的捕获分辨率ImageReader非常小时也会发生这种情况。因此,它似乎不是由处理ImageReader数据过载引起的。

此 Pastebin 中涵盖从应用程序启动到视频录制(和应用程序关闭)的时间段的系统日志。

Edd*_*ala 3

从你的 Pastebin 日志中:

10-15 19:45:32.501:E / Camera3-Device(3151):相机0:waitUntilDrainedLocked:等待HAL耗尽时出错:连接超时(-110)

这通常意味着相机 HAL 内部出现了问题 - 相机服务在创建新会话之前等待飞行中的捕获完成,但有些永远不会返回。因此,事情会超时,并且错误会返回到应用程序。

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

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

这会增加额外的延迟,并且预览会冻结更长的时间,但在这种情况下可能会更稳定。