diff --git a/api/current.txt b/api/current.txt
index 97acea931b5c6..741c491e95871 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15576,6 +15576,7 @@ package android.hardware.camera2 {
method public java.util.List
The list returned is not modifiable, so any attempts to modify it will throw + * a {@code UnsupportedOperationException}.
+ * + *Each physical camera id is only listed once in the list. The order of the keys + * is undefined.
+ * + * @return List of physical camera ids for this logical camera device. + */ + @NonNull + public ListThis key is available on all devices.
* @@ -1594,6 +1638,7 @@ public final class CameraCharacteristics extends CameraMetadataString containing the ids of the underlying physical cameras.
+ *For a logical camera, this is concatenation of all underlying physical camera ids. + * The null terminator for physical camera id must be preserved so that the whole string + * can be tokenized using '\0' to generate list of physical camera ids.
+ *For example, if the physical camera ids of the logical camera are "2" and "3", the + * value of this tag will be ['2', '\0', '3', '\0'].
+ *The number of physical camera ids must be no less than 2.
+ *Units: UTF-8 null-terminated string
+ *Optional - This value may be {@code null} on some devices.
+ *Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key
+ * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + public static final KeyThe accuracy of frame timestamp synchronization between physical cameras
+ *The accuracy of the frame timestamp synchronization determines the physical cameras' + * ability to start exposure at the same time. If the sensorSyncType is CALIBRATED, + * the physical camera sensors usually run in master-slave mode so that their shutter + * time is synchronized. For APPROXIMATE sensorSyncType, the camera sensors usually run in + * master-master mode, and there could be offset between their start of exposure.
+ *In both cases, all images generated for a particular capture request still carry the same + * timestamps, so that they can be used to look up the matching frame number and + * onCaptureStarted callback.
+ *Possible values: + *
Optional - This value may be {@code null} on some devices.
+ *Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key
+ * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE + * @see #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED + */ + @PublicKey + public static final KeyThe camera device is a logical camera backed by two or more physical cameras that are + * also exposed to the application.
+ *This capability requires the camera device to support the following:
+ *Both the logical camera device and its underlying physical devices support the + * mandatory stream combinations required for their device levels.
+ *Additionally, for each guaranteed stream combination, the logical camera supports:
+ *Using physical streams in place of a logical stream of the same size and format will + * not slow down the frame rate of the capture, as long as the minimum frame duration + * of the physical and logical streams are the same.
+ * + * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION + * @see CameraCharacteristics#LENS_POSE_REFERENCE + * @see CameraCharacteristics#LENS_POSE_ROTATION + * @see CameraCharacteristics#LENS_POSE_TRANSLATION + * @see CameraCharacteristics#LENS_RADIAL_DISTORTION + * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + */ + public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11; + // // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE // @@ -1159,6 +1206,26 @@ public abstract class CameraMetadataA software mechanism is used to synchronize between the physical cameras. As a result, + * the timestamp of an image from a physical stream is only an approximation of the + * image sensor start-of-exposure time.
+ * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE + */ + public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE = 0; + + /** + *The camera device supports frame timestamp synchronization at the hardware level, + * and the timestamp of a physical stream image accurately reflects its + * start-of-exposure time.
+ * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE + */ + public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED = 1; + // // Enumeration values for CaptureRequest#COLOR_CORRECTION_MODE // diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 4455d45d41602..8d1c96f6fb7fc 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -18,13 +18,14 @@ package android.hardware.camera2.impl; import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable; +import android.hardware.ICameraService; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; -import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.ICameraDeviceUser; import android.hardware.camera2.TotalCaptureResult; @@ -34,7 +35,6 @@ import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.SubmitInfo; import android.hardware.camera2.utils.SurfaceUtils; -import android.hardware.ICameraService; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -49,16 +49,14 @@ import android.view.Surface; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.LinkedList; +import java.util.List; import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; /** * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate @@ -956,7 +954,8 @@ public class CameraDeviceImpl extends CameraDevice // callback is valid handler = checkHandler(handler, callback); - // Make sure that there all requests have at least 1 surface; all surfaces are non-null + // Make sure that there all requests have at least 1 surface; all surfaces are non-null; + // the surface isn't a physical stream surface for reprocessing request for (CaptureRequest request : requestList) { if (request.getTargets().isEmpty()) { throw new IllegalArgumentException( @@ -967,7 +966,20 @@ public class CameraDeviceImpl extends CameraDevice if (surface == null) { throw new IllegalArgumentException("Null Surface targets are not allowed"); } + + if (!request.isReprocess()) { + continue; + } + for (int i = 0; i < mConfiguredOutputs.size(); i++) { + OutputConfiguration configuration = mConfiguredOutputs.valueAt(i); + if (configuration.isForPhysicalCamera() + && configuration.getSurfaces().contains(surface)) { + throw new IllegalArgumentException( + "Reprocess request on physical stream is not allowed"); + } + } } + } synchronized(mInterfaceLock) { diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index a85b5f7106965..f47cd665fd9c1 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -31,13 +31,12 @@ import android.util.Log; import android.util.Size; import android.view.Surface; -import java.util.Arrays; -import java.util.List; -import java.util.Collections; -import java.util.ArrayList; - import static com.android.internal.util.Preconditions.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * A class for describing camera output, which contains a {@link Surface} and its specific * configuration for creating capture session. @@ -266,6 +265,7 @@ public final class OutputConfiguration implements Parcelable { mConfiguredGenerationId = surface.getGenerationId(); mIsDeferredConfig = false; mIsShared = false; + mPhysicalCameraId = null; } /** @@ -319,6 +319,7 @@ public final class OutputConfiguration implements Parcelable { mConfiguredGenerationId = 0; mIsDeferredConfig = true; mIsShared = false; + mPhysicalCameraId = null; } /** @@ -348,8 +349,9 @@ public final class OutputConfiguration implements Parcelable { * * *To enable surface sharing, this function must be called before {@link - * CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after {@link - * CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.
+ * CameraDevice#createCaptureSessionByOutputConfigurations} or {@link + * CameraDevice#createReprocessableCaptureSessionByConfigurations}. Calling this function after + * {@link CameraDevice#createCaptureSessionByOutputConfigurations} has no effect. * *Up to {@link #getMaxSharedSurfaceCount} surfaces can be shared for an OutputConfiguration. * The supported surfaces for sharing must be of type SurfaceTexture, SurfaceView, @@ -359,6 +361,44 @@ public final class OutputConfiguration implements Parcelable { mIsShared = true; } + /** + * Set the id of the physical camera for this OutputConfiguration + * + *
In the case one logical camera is made up of multiple physical cameras, it could be + * desirable for the camera application to request streams from individual physical cameras. + * This call achieves it by mapping the OutputConfiguration to the physical camera id.
+ * + *The valid physical camera id can be queried by {@link + * android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds}. + *
+ * + *Passing in a null physicalCameraId means that the OutputConfiguration is for a logical + * stream.
+ * + *This function must be called before {@link + * CameraDevice#createCaptureSessionByOutputConfigurations} or {@link + * CameraDevice#createReprocessableCaptureSessionByConfigurations}. Calling this function + * after {@link CameraDevice#createCaptureSessionByOutputConfigurations} or {@link + * CameraDevice#createReprocessableCaptureSessionByConfigurations} has no effect.
+ * + *The surface belonging to a physical camera OutputConfiguration must not be used as input + * or output of a reprocessing request.
+ */ + public void setPhysicalCameraId(@Nullable String physicalCameraId) { + mPhysicalCameraId = physicalCameraId; + } + + /** + * Check if this configuration is for a physical camera. + * + *This returns true if the output configuration was for a physical camera making up a + * logical multi camera via {@link OutputConfiguration#setPhysicalCameraId}.
+ * @hide + */ + public boolean isForPhysicalCamera() { + return (mPhysicalCameraId != null); + } + /** * Check if this configuration has deferred configuration. * @@ -487,6 +527,7 @@ public final class OutputConfiguration implements Parcelable { this.mConfiguredGenerationId = other.mConfiguredGenerationId; this.mIsDeferredConfig = other.mIsDeferredConfig; this.mIsShared = other.mIsShared; + this.mPhysicalCameraId = other.mPhysicalCameraId; } /** @@ -502,6 +543,7 @@ public final class OutputConfiguration implements Parcelable { boolean isShared = source.readInt() == 1; ArrayList