diff --git a/api/current.txt b/api/current.txt index 032b2cbe3c0c7..e6a5b1aa12dfe 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13776,6 +13776,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 3b8f584c30067..e70b6f61d7b3c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -14177,6 +14177,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 da31235d8e747..40e11568cf4e3 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -13786,6 +13786,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); } /**