camera2: Add support for logical camera

- Add physicalCameraId in OutputConfiguration
- Add static metadata for logical camera

Test: LogicalCameraDeviceTest CTS test
Bug: 64691172
Change-Id: I1b3ea005796d07e361cc3d1b04aa6e5ca26643f4
This commit is contained in:
Shuzhen Wang
2017-11-26 17:24:56 -08:00
parent dbe2852e15
commit 23d2938f22
5 changed files with 242 additions and 16 deletions

View File

@@ -22,9 +22,11 @@ import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.PublicKey;
import android.hardware.camera2.impl.SyntheticKey;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.TypeReference;
import android.util.Rational;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -407,6 +409,47 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
return Collections.unmodifiableList(staticKeyList);
}
/**
* Returns the list of physical camera ids that this logical {@link CameraDevice} is
* made up of.
*
* <p>A camera device is a logical camera if it has
* REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability. If the camera device
* doesn't have the capability, the return value will be an empty list. </p>
*
* <p>The list returned is not modifiable, so any attempts to modify it will throw
* a {@code UnsupportedOperationException}.</p>
*
* <p>Each physical camera id is only listed once in the list. The order of the keys
* is undefined.</p>
*
* @return List of physical camera ids for this logical camera device.
*/
@NonNull
public List<String> getPhysicalCameraIds() {
int[] availableCapabilities = get(REQUEST_AVAILABLE_CAPABILITIES);
if (availableCapabilities == null) {
throw new AssertionError("android.request.availableCapabilities must be non-null "
+ "in the characteristics");
}
if (!ArrayUtils.contains(availableCapabilities,
REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
return Collections.emptyList();
}
byte[] physicalCamIds = get(LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
String physicalCamIdString = null;
try {
physicalCamIdString = new String(physicalCamIds, "UTF-8");
} catch (java.io.UnsupportedEncodingException e) {
throw new AssertionError("android.logicalCam.physicalIds must be UTF-8 string");
}
String[] physicalCameraIdList = physicalCamIdString.split("\0");
return Collections.unmodifiableList(Arrays.asList(physicalCameraIdList));
}
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The key entries below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
@@ -1579,6 +1622,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT DEPTH_OUTPUT}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO CONSTRAINED_HIGH_SPEED_VIDEO}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA LOGICAL_MULTI_CAMERA}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -1594,6 +1638,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* @see #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT
* @see #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
* @see #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING
* @see #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
*/
@PublicKey
public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -3167,6 +3212,54 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
public static final Key<Boolean> DEPTH_DEPTH_IS_EXCLUSIVE =
new Key<Boolean>("android.depth.depthIsExclusive", boolean.class);
/**
* <p>String containing the ids of the underlying physical cameras.</p>
* <p>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.</p>
* <p>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'].</p>
* <p>The number of physical camera ids must be no less than 2.</p>
* <p><b>Units</b>: UTF-8 null-terminated string</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Limited capability</b> -
* 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</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @hide
*/
public static final Key<byte[]> LOGICAL_MULTI_CAMERA_PHYSICAL_IDS =
new Key<byte[]>("android.logicalMultiCamera.physicalIds", byte[].class);
/**
* <p>The accuracy of frame timestamp synchronization between physical cameras</p>
* <p>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.</p>
* <p>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.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE APPROXIMATE}</li>
* <li>{@link #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED CALIBRATED}</li>
* </ul></p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Limited capability</b> -
* 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</p>
*
* @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 Key<Integer> LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE =
new Key<Integer>("android.logicalMultiCamera.sensorSyncType", int.class);
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/

View File

@@ -845,6 +845,53 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10;
/**
* <p>The camera device is a logical camera backed by two or more physical cameras that are
* also exposed to the application.</p>
* <p>This capability requires the camera device to support the following:</p>
* <ul>
* <li>This camera device must list the following static metadata entries in {@link android.hardware.camera2.CameraCharacteristics }:<ul>
* <li>android.logicalMultiCamera.physicalIds</li>
* <li>{@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType}</li>
* </ul>
* </li>
* <li>The underlying physical cameras' static metadata must list the following entries,
* so that the application can correlate pixels from the physical streams:<ul>
* <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
* <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
* <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
* <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
* <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
* </ul>
* </li>
* <li>The logical camera device must be LIMITED or higher device.</li>
* </ul>
* <p>Both the logical camera device and its underlying physical devices support the
* mandatory stream combinations required for their device levels.</p>
* <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
* <ul>
* <li>Replacing one logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
* or raw stream with two physical streams of the same size and format, each from a
* separate physical camera, given that the size and format are supported by both
* physical cameras.</li>
* <li>Adding two raw streams, each from one physical camera, if the logical camera doesn't
* advertise RAW capability, but the underlying physical cameras do. This is usually
* the case when the physical cameras have different sensor sizes.</li>
* </ul>
* <p>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.</p>
*
* @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 CameraMetadata<TKey> {
*/
public static final int SYNC_MAX_LATENCY_UNKNOWN = -1;
//
// Enumeration values for CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
//
/**
* <p>A 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.</p>
* @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
*/
public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE = 0;
/**
* <p>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.</p>
* @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
//

View File

@@ -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) {

View File

@@ -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 {
* </ol>
*
* <p>To enable surface sharing, this function must be called before {@link
* CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after {@link
* CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.</p>
* CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
* CameraDevice#createReprocessableCaptureSessionByConfigurations}. Calling this function after
* {@link CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.</p>
*
* <p>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
*
* <p>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.</p>
*
* <p>The valid physical camera id can be queried by {@link
* android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds}.
* </p>
*
* <p>Passing in a null physicalCameraId means that the OutputConfiguration is for a logical
* stream.</p>
*
* <p>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.</p>
*
* <p>The surface belonging to a physical camera OutputConfiguration must not be used as input
* or output of a reprocessing request. </p>
*/
public void setPhysicalCameraId(@Nullable String physicalCameraId) {
mPhysicalCameraId = physicalCameraId;
}
/**
* Check if this configuration is for a physical camera.
*
* <p>This returns true if the output configuration was for a physical camera making up a
* logical multi camera via {@link OutputConfiguration#setPhysicalCameraId}.</p>
* @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<Surface> surfaces = new ArrayList<Surface>();
source.readTypedList(surfaces, Surface.CREATOR);
String physicalCameraId = source.readString();
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
@@ -524,6 +566,7 @@ public final class OutputConfiguration implements Parcelable {
StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
mConfiguredGenerationId = 0;
}
mPhysicalCameraId = physicalCameraId;
}
/**
@@ -622,6 +665,7 @@ public final class OutputConfiguration implements Parcelable {
dest.writeInt(mIsDeferredConfig ? 1 : 0);
dest.writeInt(mIsShared ? 1 : 0);
dest.writeTypedList(mSurfaces);
dest.writeString(mPhysicalCameraId);
}
/**
@@ -675,13 +719,15 @@ public final class OutputConfiguration implements Parcelable {
if (mIsDeferredConfig) {
return HashCodeHelpers.hashCode(
mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0);
mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
}
return HashCodeHelpers.hashCode(
mRotation, mSurfaces.hashCode(), mConfiguredGenerationId,
mConfiguredSize.hashCode(), mConfiguredFormat,
mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0);
mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
}
private static final String TAG = "OutputConfiguration";
@@ -701,4 +747,6 @@ public final class OutputConfiguration implements Parcelable {
private final boolean mIsDeferredConfig;
// Flag indicating if this config has shared surfaces
private boolean mIsShared;
// The physical camera id that this output configuration is for.
private String mPhysicalCameraId;
}