Java 如何将RejectCaptureRequest与camera2 API一起使用
我正试图将一个摄像头项目升级到安卓N,结果我把我的旧的移动到了一个新的平台上。我这样做了,效果很好,但是有了这个新功能,我可以在我的设备中使用Java 如何将RejectCaptureRequest与camera2 API一起使用,java,android,image,camera,android-camera2,Java,Android,Image,Camera,Android Camera2,我正试图将一个摄像头项目升级到安卓N,结果我把我的旧的移动到了一个新的平台上。我这样做了,效果很好,但是有了这个新功能,我可以在我的设备中使用CameraDevice.TEMPLATE\u ZERO\u SHUTTER\u LAG模板,我可以用 这就是我的问题所在。因为我找不到任何示例,而且我也不太理解关于如何使用RepostCaptureRequest的小文档: 每个重新处理捕获请求处理一个从CameraCaptureSession的输入表面到重新处理捕获请求中包含的所有输出表面的缓冲区。重新
CameraDevice.TEMPLATE\u ZERO\u SHUTTER\u LAG
模板,我可以用
这就是我的问题所在。因为我找不到任何示例,而且我也不太理解关于如何使用RepostCaptureRequest
的小文档:
每个重新处理捕获请求处理一个从CameraCaptureSession的输入表面到重新处理捕获请求中包含的所有输出表面的缓冲区。重新处理输入图像必须由从同一摄像机设备捕获的一个或多个输出图像生成。应用程序可以通过queueInputImage(图像)向相机设备提供输入图像。应用程序必须使用其中一个输出图像的捕获结果来创建再处理捕获请求,以便相机设备可以使用该信息来实现最佳再处理图像质量。对于仅支持一个输出曲面的相机设备,提交具有多个输出目标的重新处理CaptureRequest将导致CaptureFailure
我试着看一看CTS关于相机的测试,但是他们做的和我一样。使用多个ImageReader,将图片的TotalCaptureResult
保存在LinkedBlockingQueue
中。后来我打电话来:
TotalCaptureResult totalCaptureResult = state.captureCallback.getTotalCaptureResult();
CaptureRequest.Builder reprocessCaptureRequest = cameraStore.state().cameraDevice.createReprocessCaptureRequest(totalCaptureResult);
reprocessCaptureRequest.addTarget(state.yuvImageReader.getSurface());
sessionStore.state().session.capture(reprocessCaptureRequest.build(), null, this.handlers.bg());
但它总是向我抛出一个RuntimeException:
java.lang.RuntimeException:捕获失败:第170帧中的原因0,
我只想知道哪种方法是使用RemovableCaptureSession的正确方法,因为我已经尝试了所有方法,但我不知道我做错了什么。最后我找到了使我的
RemovableCaptureSession
工作的解决方案。
我与Flux架构一起使用,所以当您看到Dispatcher.dispatch(action)
时,不要感到困惑,只需将其视为回调即可。这是我的代码:
首先,会话是如何创建的:
//Configure preview surface
Size previewSize = previewState.previewSize;
previewState.previewTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
ArrayList<Surface> targets = new ArrayList<>();
for (SessionOutputTarget outputTarget : state.outputTargets) {
Surface surface = outputTarget.getSurface();
if (surface != null) targets.add(surface);
}
targets.add(previewState.previewSurface);
CameraCharacteristics cameraCharacteristics = cameraStore.state().availableCameras.get(cameraStore.state().selectedCamera);
Size size = CameraCharacteristicsUtil.getYuvOutputSizes(cameraCharacteristics).get(0);
InputConfiguration inputConfiguration = new InputConfiguration(size.getWidth(),
size.getHeight(), ImageFormat.YUV_420_888);
CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
if (sessionId != currentSessionId) {
Timber.e("Session opened for an old open request, skipping. Current %d, Request %d", currentSessionId, sessionId);
//performClose(session);
return;
}
try {
session.getInputSurface();
//This call is irrelevant,
//however session might have closed and this will throw an IllegalStateException.
//This happens if another camera app (or this one in another PID) takes control
//of the camera while its opening
} catch (IllegalStateException e) {
Timber.e("Another process took control of the camera while creating the session, aborting!");
}
Dispatcher.dispatchOnUi(new SessionOpenedAction(session));
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
if (sessionId != currentSessionId) {
Timber.e("Configure failed for an old open request, skipping. Current %d, request %d", currentSessionId, sessionId);
return;
}
Timber.e("Failed to configure the session");
Dispatcher.dispatchOnUi(new SessionFailedAction(session, new IllegalStateException("onConfigureFailed")));
}
};
if (state.outputMode == OutputMode.PHOTO) {
cameraState.cameraDevice.createReprocessableCaptureSession(inputConfiguration, targets, sessionStateCallback, handlers.bg());
} else if (state.outputMode == OutputMode.VIDEO) {
cameraState.cameraDevice.createCaptureSession(targets, sessionStateCallback, handlers.bg());
}
} catch (IllegalStateException | IllegalArgumentException e) {
Timber.e(e, "Something went wrong trying to start the session");
} catch (CameraAccessException e) {
//Camera will throw CameraAccessException if another we try to open / close the
//session very fast.
Timber.e("Failed to access camera, it was closed");
}
好的,现在我们已经创建了ImageWriter和会话。否我们使用重复请求开始流式处理:
CaptureRequest.Builder captureRequestBuilder =
cameraStore.state().cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
captureRequestBuilder.addTarget(previewStore.state().previewSurface);
captureRequestBuilder.addTarget(photoStore.state().yuvImageReader.getSurface());
state.session.setRepeatingRequest(captureRequestBuilder.build(), state.zslCaptureCallback, handlers.bg());
要避免添加大量代码,只需假设zslCaptureCallback是一个自定义回调,它保存在LinkedBlockingQueue
X个最后的TotalCaptureRequests中。另外,我对yuvImageReader(输入一)也做了同样的操作,它将最后的X图像保存在队列中
最后是我的“拍照”方法:
你想在这里做什么?这是为了对相机在同一个会话中早些时候捕获的图像进行最终的高质量图像处理(可能还有JPEG压缩),所以它对零快门延迟模式很有用。我想要的是实现零快门延迟模式。但是我在文档中找不到这样做的方法,请包括更多的logcat输出,包括整个系统,而不仅仅是你的应用程序。这里可能有更多关于失败的解释。首先,你是否向ImageWriter提交了一张要重新处理的图像。昨天我实现了用ZSL会话和ImageWriter拍摄照片。但是我不知道它是否被正确使用,或者我是否做了一些错误的事情,因为当设备应该支持重新处理时,我的预览丢失了一些帧。我附上了上面所有的代码,非常感谢!嗨@EddyTalvala!你看过我上面贴的代码了吗?
CaptureRequest.Builder captureRequestBuilder =
cameraStore.state().cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
captureRequestBuilder.addTarget(previewStore.state().previewSurface);
captureRequestBuilder.addTarget(photoStore.state().yuvImageReader.getSurface());
state.session.setRepeatingRequest(captureRequestBuilder.build(), state.zslCaptureCallback, handlers.bg());
try {
//Retrieve the last image stored by the zslImageReader
Image image = zslImageReaderListener.getImage();
//Retrieve the last totalCaptureResult from the zslCaptureCallback and create a reprocessableCaptureRequest with it
TotalCaptureResult captureResult = sessionStore.state().zslCaptureCallback.getCaptureResult(image.getTimestamp());
CaptureRequest.Builder captureRequest = cameraStore.state().cameraDevice.createReprocessCaptureRequest(captureResult);
//Add the desired target and values to the captureRequest
captureRequest.addTarget(state().jpegImageReader.getSurface());
//Queued back to ImageWriter for future consumption.
state.zslImageWriter.queueInputImage(image);
//Drain all the unused and queued CapturedResult from the CaptureCallback
sessionStore.state().zslCaptureCallback.drain();
//Capture the desired frame
CaptureRequest futureCaptureResult = captureRequest.build();
sessionStore.state().session.capture(futureCaptureResult, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
Dispatcher.dispatchOnUi(new PhotoStatusChangedAction(PhotoState.Status.SUCCESS));
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Exception captureFailedException = new RuntimeException(
String.format("Capture failed: Reason %s in frame %d, was image captured? -> %s",
failure.getReason(),
failure.getFrameNumber(),
failure.wasImageCaptured()));
Timber.e(captureFailedException, "Cannot take mediaType, capture failed!");
Dispatcher.dispatchOnUi(new PhotoStatusChangedAction(PhotoState.Status.ERROR, captureFailedException));
}
}, this.handlers.bg());
//Capture did not blow up, we are taking the photo now.
newState.status = PhotoState.Status.TAKING;
} catch (CameraAccessException | InterruptedException| IllegalStateException | IllegalArgumentException | SecurityException e) {
Timber.e(e, "Cannot take picture, capture error!");
newState.status = PhotoState.Status.ERROR;
}