diff options
6 files changed, 121 insertions, 20 deletions
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index 31e6e254a951..0cf8df130cd4 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -65,6 +65,12 @@ import java.util.List; public abstract class CameraCaptureSession implements AutoCloseable { /** + * Used to identify invalid session ID. + * @hide + */ + public static final int SESSION_ID_NONE = -1; + + /** * Get the camera device that this session is created for. */ public abstract CameraDevice getDevice(); @@ -168,10 +174,11 @@ public abstract class CameraCaptureSession implements AutoCloseable { * @throws IllegalArgumentException if the request targets no Surfaces or Surfaces that are not * configured as outputs for this session; or a reprocess * capture request is submitted in a non-reprocessible capture - * session; or the capture targets a Surface in the middle - * of being {@link #prepare prepared}; or the handler is - * null, the listener is not null, and the calling thread has - * no looper. + * session; or the reprocess capture request was created with + * a {@link TotalCaptureResult} from a different session; or + * the capture targets a Surface in the middle of being + * {@link #prepare prepared}; or the handler is null, the + * listener is not null, and the calling thread has no looper. * * @see #captureBurst * @see #setRepeatingRequest @@ -226,7 +233,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * capture request is submitted in a non-reprocessible capture * session; or the list of requests contains both requests to * capture images from the camera and reprocess capture - * requests; or one of the captures targets a Surface in the + * requests; or one of the reprocess capture requests was + * created with a {@link TotalCaptureResult} from a different + * session; or one of the captures targets a Surface in the * middle of being {@link #prepare prepared}; or if the handler * is null, the listener is not null, and the calling thread * has no looper. diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 35727e871e40..19d17b136bff 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -158,6 +158,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> private final HashSet<Surface> mSurfaceSet; private final CameraMetadataNative mSettings; private boolean mIsReprocess; + // Each reprocess request must be tied to a reprocessible session ID. + // Valid only for reprocess requests (mIsReprocess == true). + private int mReprocessibleSessionId; private Object mUserTag; @@ -170,6 +173,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> mSettings = new CameraMetadataNative(); mSurfaceSet = new HashSet<Surface>(); mIsReprocess = false; + mReprocessibleSessionId = CameraCaptureSession.SESSION_ID_NONE; } /** @@ -182,6 +186,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> mSettings = new CameraMetadataNative(source.mSettings); mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone(); mIsReprocess = source.mIsReprocess; + mReprocessibleSessionId = source.mReprocessibleSessionId; mUserTag = source.mUserTag; } @@ -189,11 +194,36 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * Take ownership of passed-in settings. * * Used by the Builder to create a mutable CaptureRequest. + * + * @param settings Settings for this capture request. + * @param isReprocess Indicates whether to create a reprocess capture request. {@code true} + * to create a reprocess capture request. {@code false} to create a regular + * capture request. + * @param reprocessibleSessionId The ID of the camera capture session this capture is created + * for. This is used to validate if the application submits a + * reprocess capture request to the same session where + * the {@link TotalCaptureResult}, used to create the reprocess + * capture, came from. + * + * @throws IllegalArgumentException If creating a reprocess capture request with an invalid + * reprocessibleSessionId. + * + * @see CameraDevice#createReprocessCaptureRequest */ - private CaptureRequest(CameraMetadataNative settings, boolean isReprocess) { + private CaptureRequest(CameraMetadataNative settings, boolean isReprocess, + int reprocessibleSessionId) { mSettings = CameraMetadataNative.move(settings); mSurfaceSet = new HashSet<Surface>(); mIsReprocess = isReprocess; + if (isReprocess) { + if (reprocessibleSessionId == CameraCaptureSession.SESSION_ID_NONE) { + throw new IllegalArgumentException("Create a reprocess capture request with an " + + "invalid session ID: " + reprocessibleSessionId); + } + mReprocessibleSessionId = reprocessibleSessionId; + } else { + mReprocessibleSessionId = CameraCaptureSession.SESSION_ID_NONE; + } } /** @@ -277,6 +307,23 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> } /** + * Get the reprocessible session ID this reprocess capture request is associated with. + * + * @return the reprocessible session ID this reprocess capture request is associated with + * + * @throws IllegalStateException if this capture request is not a reprocess capture request. + * @hide + */ + public int getReprocessibleSessionId() { + if (mIsReprocess == false || + mReprocessibleSessionId == CameraCaptureSession.SESSION_ID_NONE) { + throw new IllegalStateException("Getting the reprocessible session ID for a "+ + "non-reprocess capture request is illegal."); + } + return mReprocessibleSessionId; + } + + /** * Determine whether this CaptureRequest is equal to another CaptureRequest. * * <p>A request is considered equal to another is if it's set of key/values is equal, it's @@ -298,7 +345,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> && Objects.equals(mUserTag, other.mUserTag) && mSurfaceSet.equals(other.mSurfaceSet) && mSettings.equals(other.mSettings) - && mIsReprocess == other.mIsReprocess; + && mIsReprocess == other.mIsReprocess + && mReprocessibleSessionId == other.mReprocessibleSessionId; } @Override @@ -347,6 +395,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> } mIsReprocess = (in.readInt() == 0) ? false : true; + mReprocessibleSessionId = CameraCaptureSession.SESSION_ID_NONE; } @Override @@ -397,10 +446,23 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * Initialize the builder using the template; the request takes * ownership of the template. * + * @param template Template settings for this capture request. + * @param reprocess Indicates whether to create a reprocess capture request. {@code true} + * to create a reprocess capture request. {@code false} to create a regular + * capture request. + * @param reprocessibleSessionId The ID of the camera capture session this capture is + * created for. This is used to validate if the application + * submits a reprocess capture request to the same session + * where the {@link TotalCaptureResult}, used to create the + * reprocess capture, came from. + * + * @throws IllegalArgumentException If creating a reprocess capture request with an invalid + * reprocessibleSessionId. * @hide */ - public Builder(CameraMetadataNative template, boolean reprocess) { - mRequest = new CaptureRequest(template, reprocess); + public Builder(CameraMetadataNative template, boolean reprocess, + int reprocessibleSessionId) { + mRequest = new CaptureRequest(template, reprocess, reprocessibleSessionId); } /** diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java index 6f7dd78952c2..fb3c098a8f29 100644 --- a/core/java/android/hardware/camera2/TotalCaptureResult.java +++ b/core/java/android/hardware/camera2/TotalCaptureResult.java @@ -50,6 +50,7 @@ import java.util.List; public final class TotalCaptureResult extends CaptureResult { private final List<CaptureResult> mPartialResults; + private final int mSessionId; /** * Takes ownership of the passed-in camera metadata and the partial results @@ -58,7 +59,7 @@ public final class TotalCaptureResult extends CaptureResult { * @hide */ public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent, - CaptureResultExtras extras, List<CaptureResult> partials) { + CaptureResultExtras extras, List<CaptureResult> partials, int sessionId) { super(results, parent, extras); if (partials == null) { @@ -66,6 +67,8 @@ public final class TotalCaptureResult extends CaptureResult { } else { mPartialResults = partials; } + + mSessionId = sessionId; } /** @@ -78,6 +81,7 @@ public final class TotalCaptureResult extends CaptureResult { super(results, sequenceId); mPartialResults = new ArrayList<>(); + mSessionId = CameraCaptureSession.SESSION_ID_NONE; } /** @@ -95,4 +99,14 @@ public final class TotalCaptureResult extends CaptureResult { public List<CaptureResult> getPartialResults() { return Collections.unmodifiableList(mPartialResults); } + + /** + * Get the ID of the session where the capture request of this result was submitted. + * + * @return The session ID + * @hide + */ + public int getSessionId() { + return mSessionId; + } } diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index c74204d63c96..3c195298b759 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -156,9 +156,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { } else if (request.isReprocess() && !isReprocessible()) { throw new IllegalArgumentException("this capture session cannot handle reprocess " + "requests"); + } else if (request.isReprocess() && request.getReprocessibleSessionId() != mId) { + throw new IllegalArgumentException("capture request was created for another session"); } - checkNotClosed(); handler = checkHandler(handler, callback); @@ -185,12 +186,17 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { if (reprocess && !isReprocessible()) { throw new IllegalArgumentException("this capture session cannot handle reprocess " + "requests"); + } else if (reprocess && requests.get(0).getReprocessibleSessionId() != mId) { + throw new IllegalArgumentException("capture request was created for another session"); } for (int i = 1; i < requests.size(); i++) { if (requests.get(i).isReprocess() != reprocess) { throw new IllegalArgumentException("cannot mix regular and reprocess capture " + " requests"); + } else if (reprocess && requests.get(i).getReprocessibleSessionId() != mId) { + throw new IllegalArgumentException("capture request was created for another " + + "session"); } } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 1e680dfd21b3..ff4ad79f120f 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -585,8 +585,8 @@ public class CameraDeviceImpl extends CameraDevice { return null; } - CaptureRequest.Builder builder = - new CaptureRequest.Builder(templatedRequest, /*reprocess*/false); + CaptureRequest.Builder builder = new CaptureRequest.Builder( + templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); return builder; } @@ -601,7 +601,8 @@ public class CameraDeviceImpl extends CameraDevice { CameraMetadataNative resultMetadata = new CameraMetadataNative(inputResult.getNativeCopy()); - return new CaptureRequest.Builder(resultMetadata, /*reprocess*/true); + return new CaptureRequest.Builder(resultMetadata, /*reprocess*/true, + inputResult.getSessionId()); } } @@ -763,7 +764,7 @@ public class CameraDeviceImpl extends CameraDevice { if (callback != null) { mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback, - requestList, handler, repeating)); + requestList, handler, repeating, mNextSessionId - 1)); } else { if (DEBUG) { Log.d(TAG, "Listen for request " + requestId + " is null"); @@ -1095,9 +1096,10 @@ public class CameraDeviceImpl extends CameraDevice { private final CaptureCallback mCallback; private final List<CaptureRequest> mRequestList; private final Handler mHandler; + private final int mSessionId; CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList, - Handler handler, boolean repeating) { + Handler handler, boolean repeating, int sessionId) { if (callback == null || handler == null) { throw new UnsupportedOperationException( "Must have a valid handler and a valid callback"); @@ -1106,6 +1108,7 @@ public class CameraDeviceImpl extends CameraDevice { mHandler = handler; mRequestList = new ArrayList<CaptureRequest>(requestList); mCallback = callback; + mSessionId = sessionId; } public boolean isRepeating() { @@ -1140,6 +1143,10 @@ public class CameraDeviceImpl extends CameraDevice { return mHandler; } + public int getSessionId() { + return mSessionId; + } + } /** @@ -1643,8 +1650,8 @@ public class CameraDeviceImpl extends CameraDevice { List<CaptureResult> partialResults = mFrameNumberTracker.popPartialResults(frameNumber); - final TotalCaptureResult resultAsCapture = - new TotalCaptureResult(result, request, resultExtras, partialResults); + final TotalCaptureResult resultAsCapture = new TotalCaptureResult(result, + request, resultExtras, partialResults, holder.getSessionId()); // Final capture result resultDispatch = new Runnable() { @@ -1665,7 +1672,8 @@ public class CameraDeviceImpl extends CameraDevice { holder.getHandler().post(resultDispatch); // Collect the partials for a total result; or mark the frame as totally completed - mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult, isReprocess); + mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult, + isReprocess); // Fire onCaptureSequenceCompleted if (!isPartialResult) { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java index 6f336725eab5..d71b44bf549a 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java @@ -19,6 +19,7 @@ package com.android.mediaframeworktest.integration; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.ICameraDeviceCallbacks; @@ -170,7 +171,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase { assertEquals(CameraBinderTestUtils.NO_ERROR, status); assertFalse(metadata.isEmpty()); - CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false); + CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false, + CameraCaptureSession.SESSION_ID_NONE); assertFalse(request.isEmpty()); assertFalse(metadata.isEmpty()); if (needStream) { |