From 3e0023ae89895f215791a8472f22b213f5a9ae93 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Sun, 6 Mar 2016 18:40:01 -0800 Subject: [PATCH] Camera2: Add buffer drop error callback Previously single buffer drop errors were not propagated to the client application, even though the HAL generated them. Add new error callback to handle this case. Bug: 24168122 Change-Id: Ice0d9a3592efed222351353abd7acc35854a20bd --- api/current.txt | 1 + api/system-current.txt | 1 + api/test-current.txt | 1 + .../camera2/CameraCaptureSession.java | 24 +++++ .../camera2/impl/CameraDeviceImpl.java | 99 ++++++++++++------- .../camera2/impl/CaptureResultExtras.java | 10 +- .../camera2/legacy/LegacyCameraDevice.java | 4 +- 7 files changed, 99 insertions(+), 41 deletions(-) diff --git a/api/current.txt b/api/current.txt index 9d4674e637172..4fd92177a6e33 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13775,6 +13775,7 @@ package android.hardware.camera2 { public static abstract class CameraCaptureSession.CaptureCallback { ctor public CameraCaptureSession.CaptureCallback(); + method public void onCaptureBufferLost(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.view.Surface, long); method public void onCaptureCompleted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult); method public void onCaptureFailed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure); method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult); diff --git a/api/system-current.txt b/api/system-current.txt index 23b9d97efd98d..db48e1d89b68b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -14176,6 +14176,7 @@ package android.hardware.camera2 { public static abstract class CameraCaptureSession.CaptureCallback { ctor public CameraCaptureSession.CaptureCallback(); + method public void onCaptureBufferLost(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.view.Surface, long); method public void onCaptureCompleted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult); method public void onCaptureFailed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure); method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult); diff --git a/api/test-current.txt b/api/test-current.txt index cdffa46df1720..5c1acc73b4c86 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -13785,6 +13785,7 @@ package android.hardware.camera2 { public static abstract class CameraCaptureSession.CaptureCallback { ctor public CameraCaptureSession.CaptureCallback(); + method public void onCaptureBufferLost(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.view.Surface, long); method public void onCaptureCompleted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult); method public void onCaptureFailed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure); method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult); diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index 8724a96ee30a4..38279a47f2a9b 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -990,6 +990,30 @@ public abstract class CameraCaptureSession implements AutoCloseable { int sequenceId) { // default empty implementation } + + /** + *

This method is called if a single buffer for a capture could not be sent to its + * destination surface.

+ * + *

If the whole capture failed, then {@link #onCaptureFailed} will be called instead. If + * some but not all buffers were captured but the result metadata will not be available, + * then onCaptureFailed will be invoked with {@link CaptureFailure#wasImageCaptured} + * returning true, along with one or more calls to {@link #onCaptureBufferLost} for the + * failed outputs.

+ * + * @param session + * The session returned by {@link CameraDevice#createCaptureSession} + * @param request + * The request that was given to the CameraDevice + * @param target + * The target Surface that the buffer will not be produced for + * @param frameNumber + * The frame number for the request + */ + public void onCaptureBufferLost(@NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) { + // default empty implementation + } } /** diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 37d2ea2badfb8..d84a6fcbd16fe 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -1116,6 +1116,11 @@ public class CameraDeviceImpl extends CameraDevice int sequenceId) { // default empty implementation } + + public void onCaptureBufferLost(CameraDevice camera, + CaptureRequest request, Surface target, long frameNumber) { + // default empty implementation + } } /** @@ -1887,48 +1892,66 @@ public class CameraDeviceImpl extends CameraDevice final CaptureRequest request = holder.getRequest(subsequenceId); - // No way to report buffer errors right now + Runnable failureDispatch = null; if (errorCode == ERROR_CAMERA_BUFFER) { - Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber)); - return; - } - - boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT); - - // This is only approximate - exact handling needs the camera service and HAL to - // disambiguate between request failures to due abort and due to real errors. - // For now, assume that if the session believes we're mid-abort, then the error - // is due to abort. - int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ? - CaptureFailure.REASON_FLUSHED : - CaptureFailure.REASON_ERROR; - - final CaptureFailure failure = new CaptureFailure( - request, - reason, - /*dropped*/ mayHaveBuffers, - requestId, - frameNumber); - - Runnable failureDispatch = new Runnable() { - @Override - public void run() { - if (!CameraDeviceImpl.this.isClosed()){ - holder.getCallback().onCaptureFailed( - CameraDeviceImpl.this, - request, - failure); - } + final Surface outputSurface = + mConfiguredOutputs.get(resultExtras.getErrorStreamId()).getSurface(); + if (DEBUG) { + Log.v(TAG, String.format("Lost output buffer reported for frame %d, target %s", + frameNumber, outputSurface)); } - }; - holder.getHandler().post(failureDispatch); + failureDispatch = new Runnable() { + @Override + public void run() { + if (!CameraDeviceImpl.this.isClosed()){ + holder.getCallback().onCaptureBufferLost( + CameraDeviceImpl.this, + request, + outputSurface, + frameNumber); + } + } + }; + } else { + boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT); - // Fire onCaptureSequenceCompleted if appropriate - if (DEBUG) { - Log.v(TAG, String.format("got error frame %d", frameNumber)); + // This is only approximate - exact handling needs the camera service and HAL to + // disambiguate between request failures to due abort and due to real errors. For + // now, assume that if the session believes we're mid-abort, then the error is due + // to abort. + int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ? + CaptureFailure.REASON_FLUSHED : + CaptureFailure.REASON_ERROR; + + final CaptureFailure failure = new CaptureFailure( + request, + reason, + /*dropped*/ mayHaveBuffers, + requestId, + frameNumber); + + failureDispatch = new Runnable() { + @Override + public void run() { + if (!CameraDeviceImpl.this.isClosed()){ + holder.getCallback().onCaptureFailed( + CameraDeviceImpl.this, + request, + failure); + } + } + }; + + // Fire onCaptureSequenceCompleted if appropriate + if (DEBUG) { + Log.v(TAG, String.format("got error frame %d", frameNumber)); + } + mFrameNumberTracker.updateTracker(frameNumber, /*error*/true, request.isReprocess()); + checkAndFireSequenceComplete(); } - mFrameNumberTracker.updateTracker(frameNumber, /*error*/true, request.isReprocess()); - checkAndFireSequenceComplete(); + + // Dispatch the failure callback + holder.getHandler().post(failureDispatch); } } // public class CameraDeviceCallbacks diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java index d859da77f82ff..40535e23eaac7 100644 --- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java +++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java @@ -28,6 +28,7 @@ public class CaptureResultExtras implements Parcelable { private int precaptureTriggerId; private long frameNumber; private int partialResultCount; + private int errorStreamId; public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -48,13 +49,14 @@ public class CaptureResultExtras implements Parcelable { public CaptureResultExtras(int requestId, int subsequenceId, int afTriggerId, int precaptureTriggerId, long frameNumber, - int partialResultCount) { + int partialResultCount, int errorStreamId) { this.requestId = requestId; this.subsequenceId = subsequenceId; this.afTriggerId = afTriggerId; this.precaptureTriggerId = precaptureTriggerId; this.frameNumber = frameNumber; this.partialResultCount = partialResultCount; + this.errorStreamId = errorStreamId; } @Override @@ -70,6 +72,7 @@ public class CaptureResultExtras implements Parcelable { dest.writeInt(precaptureTriggerId); dest.writeLong(frameNumber); dest.writeInt(partialResultCount); + dest.writeInt(errorStreamId); } public void readFromParcel(Parcel in) { @@ -79,6 +82,7 @@ public class CaptureResultExtras implements Parcelable { precaptureTriggerId = in.readInt(); frameNumber = in.readLong(); partialResultCount = in.readInt(); + errorStreamId = in.readInt(); } public int getRequestId() { @@ -104,4 +108,8 @@ public class CaptureResultExtras implements Parcelable { public int getPartialResultCount() { return partialResultCount; } + + public int getErrorStreamId() { + return errorStreamId; + } } diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index 4c4adea838efc..661edd734a713 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -91,11 +91,11 @@ public class LegacyCameraDevice implements AutoCloseable { private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) { if (holder == null) { return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, - ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE); + ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE); } return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(), /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(), - /*partialResultCount*/1); + /*partialResultCount*/1, /*errorStreamId*/-1); } /**