使用 ImageReader 后,在 Samsung Note5 上录制视频无法使用 Camera2 API
Recording video not working with Camera2 API on Samsung Note5 after using ImageReader
如标题所述,我在使用 Camera2 API.
在 Samsung Note5 上录制视频时遇到问题
我已经从 Camera2Video 示例中改编了我的代码,但不同之处在于我使用 CamcorderProfile
class 中的配置选项设置了 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;
}
这是我在开始预览时设置图像 reader 的代码:
// 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
开始捕捉 session 进行预览,然后停止捕捉并在表面列表中使用 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
中调用了 abortCaptures
和 close
).
有人知道怎么解决吗?
编辑:可能相关的是,在此设备上使用 ImageReader
时,关闭 onPause
中的 CameraDevice
需要很长时间(最多 6 秒)。我已经设法通过在一个单独的线程中对用户隐藏它,但是如果 onResume
在 onPause
的 6 秒内被调用,将会有延迟,因为我必须等待它在我再次打开它之前完成关闭。显然我无法承受开始录像时6秒的延迟
即使我只调用 acquireLatestImage()
、关闭它并立即在 ImageReader
的 onImageAvailable
回调中 return,问题仍然存在。当 ImageReader
的捕获分辨率非常小时也会发生这种情况。所以,这似乎不是由于处理 ImageReader
数据过载造成的。
中从应用启动到视频录制(和应用关闭)期间的系统日志
来自您的 pastebin 日志:
10-15 19:45:32.501:E/Camera3-Device(3151):相机 0:waitUntilDrainedLocked:等待 HAL 耗尽时出错:连接超时 (-110)
这通常意味着相机 HAL 内部出现问题 - 相机服务在创建新会话之前等待飞行中的捕获完成,但有些永远不会 return。所以事情超时并且错误被return发送到应用程序。
不幸的是,这是设备特定相机代码中的错误,因此三星需要修复它。
作为解决方法,您可以尝试停止重复请求,等待所有进行中的请求完成(设备切换到 'ready' 状态),然后创建新会话。然后没有正在进行的捕获,HAL 可能会处理不当。
这会增加额外的延迟,预览会冻结更长时间,但在这种情况下可能更稳健。
如标题所述,我在使用 Camera2 API.
在 Samsung Note5 上录制视频时遇到问题我已经从 Camera2Video 示例中改编了我的代码,但不同之处在于我使用 CamcorderProfile
class 中的配置选项设置了 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;
}
这是我在开始预览时设置图像 reader 的代码:
// 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
开始捕捉 session 进行预览,然后停止捕捉并在表面列表中使用 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
中调用了 abortCaptures
和 close
).
有人知道怎么解决吗?
编辑:可能相关的是,在此设备上使用 ImageReader
时,关闭 onPause
中的 CameraDevice
需要很长时间(最多 6 秒)。我已经设法通过在一个单独的线程中对用户隐藏它,但是如果 onResume
在 onPause
的 6 秒内被调用,将会有延迟,因为我必须等待它在我再次打开它之前完成关闭。显然我无法承受开始录像时6秒的延迟
即使我只调用 acquireLatestImage()
、关闭它并立即在 ImageReader
的 onImageAvailable
回调中 return,问题仍然存在。当 ImageReader
的捕获分辨率非常小时也会发生这种情况。所以,这似乎不是由于处理 ImageReader
数据过载造成的。
来自您的 pastebin 日志:
10-15 19:45:32.501:E/Camera3-Device(3151):相机 0:waitUntilDrainedLocked:等待 HAL 耗尽时出错:连接超时 (-110)
这通常意味着相机 HAL 内部出现问题 - 相机服务在创建新会话之前等待飞行中的捕获完成,但有些永远不会 return。所以事情超时并且错误被return发送到应用程序。
不幸的是,这是设备特定相机代码中的错误,因此三星需要修复它。
作为解决方法,您可以尝试停止重复请求,等待所有进行中的请求完成(设备切换到 'ready' 状态),然后创建新会话。然后没有正在进行的捕获,HAL 可能会处理不当。
这会增加额外的延迟,预览会冻结更长时间,但在这种情况下可能更稳健。