From cbd1a8fa1de58eb5d564f6e967d80480cd249b30 Mon Sep 17 00:00:00 2001
From: Shuzhen Wang
This timestamp may not match {@link CaptureResult#SENSOR_TIMESTAMP the result - * timestamp field}. It will, however, match the timestamp of buffers sent to the - * output surfaces with {@link OutputConfiguration#TIMESTAMP_BASE_READOUT_SENSOR} - * timestamp base.
+ *The timestamps match the timestamps of the output surfaces with readout timestamp + * enabled (via {@link OutputConfiguration#useReadoutTimestamp}) if:
+ *Otherwise, the timestamps won't match the timestamp of the output surfaces. See + * the possible parameters for {@link OutputConfiguration#setTimestampBase} for details.
* *This callback will be called only if {@link
* CameraCharacteristics#SENSOR_READOUT_TIMESTAMP} is
@@ -1261,8 +1279,6 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* the timestamp at the input image's start of readout for a
* reprocess request, in nanoseconds.
* @param frameNumber the frame number for this capture
- *
- * @hide
*/
public void onReadoutStarted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, long timestamp, long frameNumber) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a6f7e945bef80..320af06f34a33 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -4588,22 +4588,26 @@ public final class CameraCharacteristics extends CameraMetadata
If this tag is HARDWARE, the camera device calls onReadoutStarted in addition to the - * onCaptureStarted callback for each capture. The timestamp passed into the callback - * is the start of camera image readout rather than the start of the exposure. In - * addition, the application can configure an - * {@link android.hardware.camera2.params.OutputConfiguration } with - * TIMESTAMP_BASE_READOUT_SENSOR timestamp base, in which case, the timestamp of the - * output surface matches the timestamp from the corresponding onReadoutStarted callback.
+ * {@code onReadoutStarted} callback. + *If this tag is {@code HARDWARE}, the camera device calls + * {@link CameraCaptureSession.CaptureCallback#onReadoutStarted } in addition to the + * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted } callback for each capture. + * The timestamp passed into the callback is the start of camera image readout rather than + * the start of the exposure. The timestamp source of + * {@link CameraCaptureSession.CaptureCallback#onReadoutStarted } is the same as that of + * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted }.
+ *In addition, the application can switch an output surface's timestamp from start of + * exposure to start of readout by calling + * {@link android.hardware.camera2.params.OutputConfiguration#useReadoutTimestamp }.
*The readout timestamp is beneficial for video recording, because the encoder favors * uniform timestamps, and the readout timestamps better reflect the cadence camera sensors * output data.
- *If this tag is HARDWARE, the camera device produces the start-of-exposure and - * start-of-readout together. As a result, the onReadoutStarted is called right after - * onCaptureStarted. The difference in start-of-readout and start-of-exposure is the sensor - * exposure time, plus certain constant offset. The offset is usually due to camera sensor - * level crop, and it remains constant for a given camera sensor mode.
+ *Note that the camera device produces the start-of-exposure and start-of-readout callbacks + * together. As a result, the {@link CameraCaptureSession.CaptureCallback#onReadoutStarted } + * is called right after {@link CameraCaptureSession.CaptureCallback#onCaptureStarted }. The + * difference in start-of-readout and start-of-exposure is the sensor exposure time, plus + * certain constant offset. The offset is usually due to camera sensor level crop, and it is + * generally constant over time for the same set of output resolutions and capture settings.
*Possible values:
*This camera device supports the onReadoutStarted callback as well as outputting - * readout timestamp for streams with TIMESTAMP_BASE_READOUT_SENSOR timestamp base. The - * readout timestamp is generated by the camera hardware and it has the same accuracy - * and timing characteristics of the start-of-exposure time.
+ * readout timestamps. The readout timestamp is generated by the camera hardware and it + * has the same accuracy and timing characteristics of the start-of-exposure time. * @see CameraCharacteristics#SENSOR_READOUT_TIMESTAMP */ public static final int SENSOR_READOUT_TIMESTAMP_HARDWARE = 1; diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index f4b87b9f5ae91..65df5d1d43597 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -191,7 +191,9 @@ public final class OutputConfiguration implements Parcelable { * *The timestamps of the output images are in the time base as specified by {@link * CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE}. The application can look up the - * corresponding result metadata for a particular output image using this timestamp.
+ * corresponding result metadata by matching the timestamp with a {@link + * CameraCaptureSession.CaptureCallback#onCaptureStarted}, or with a {@link + * CameraCaptureSession.CaptureCallback#onReadoutStarted} if readout timestamp is used. */ public static final int TIMESTAMP_BASE_SENSOR = 1; @@ -204,7 +206,8 @@ public final class OutputConfiguration implements Parcelable { * *If the camera device's {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE} is * REALTIME, timestamps with this time base cannot directly match the timestamps in - * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted} or the sensor timestamps in + * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted}, {@link + * CameraCaptureSession.CaptureCallback#onReadoutStarted}, or the sensor timestamps in * {@link android.hardware.camera2.CaptureResult}.
*/ public static final int TIMESTAMP_BASE_MONOTONIC = 2; @@ -218,7 +221,8 @@ public final class OutputConfiguration implements Parcelable { * *If the camera device's {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE} is * UNKNOWN, timestamps with this time base cannot directly match the timestamps in - * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted} or the sensor timestamps in + * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted}, {@link + * CameraCaptureSession.CaptureCallback#onReadoutStarted}, or the sensor timestamps in * {@link android.hardware.camera2.CaptureResult}.
* *If using a REALTIME timestamp base on a device that supports only @@ -243,7 +247,8 @@ public final class OutputConfiguration implements Parcelable { * displayed right away.
* *Timestamps with this time base cannot directly match the timestamps in - * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted} or the sensor timestamps in + * {@link CameraCaptureSession.CaptureCallback#onCaptureStarted}, {@link + * CameraCaptureSession.CaptureCallback#onReadoutStarted}, or the sensor timestamps in * {@link android.hardware.camera2.CaptureResult}. This timestamp base shouldn't be used if the * timestamp needs to be used for audio-video synchronization.
*/ @@ -252,18 +257,7 @@ public final class OutputConfiguration implements Parcelable { /** * Timestamp is the start of readout in the same time domain as TIMESTAMP_BASE_SENSOR. * - *The start of the camera sensor readout after exposure. For a rolling shutter camera - * sensor, the timestamp is typically equal to the start of exposure time + - * exposure time + certain fixed offset. The fixed offset could be due to camera sensor - * level crop. The benefit of using readout time is that when camera runs in a fixed - * frame rate, the timestamp intervals between frames are constant.
- * - *This timestamp is in the same time domain as in TIMESTAMP_BASE_SENSOR, with the exception - * that one is start of exposure, and the other is start of readout.
- * - *This timestamp base is supported only if {@link - * CameraCharacteristics#SENSOR_READOUT_TIMESTAMP} is - * {@link CameraMetadata#SENSOR_READOUT_TIMESTAMP_HARDWARE}.
+ *NOTE: do not use! Use useReadoutTimestamp instead.
* * @hide */ @@ -579,6 +573,8 @@ public final class OutputConfiguration implements Parcelable { mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; mTimestampBase = TIMESTAMP_BASE_DEFAULT; mMirrorMode = MIRROR_MODE_AUTO; + mUseReadoutTimestamp = false; + mIsReadoutSensorTimestampBase = false; } /** @@ -679,6 +675,8 @@ public final class OutputConfiguration implements Parcelable { mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; mColorSpace = ColorSpaceProfiles.UNSPECIFIED; mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; + mUseReadoutTimestamp = false; + mIsReadoutSensorTimestampBase = false; } /** @@ -1048,7 +1046,15 @@ public final class OutputConfiguration implements Parcelable { throw new IllegalArgumentException("Not a valid timestamp base value " + timestampBase); } - mTimestampBase = timestampBase; + + if (timestampBase == TIMESTAMP_BASE_READOUT_SENSOR) { + mTimestampBase = TIMESTAMP_BASE_SENSOR; + mUseReadoutTimestamp = true; + mIsReadoutSensorTimestampBase = true; + } else { + mTimestampBase = timestampBase; + mIsReadoutSensorTimestampBase = false; + } } /** @@ -1060,7 +1066,11 @@ public final class OutputConfiguration implements Parcelable { * @return The currently set timestamp base */ public @TimestampBase int getTimestampBase() { - return mTimestampBase; + if (mIsReadoutSensorTimestampBase) { + return TIMESTAMP_BASE_READOUT_SENSOR; + } else { + return mTimestampBase; + } } /** @@ -1099,6 +1109,37 @@ public final class OutputConfiguration implements Parcelable { return mMirrorMode; } + /** + * Use the camera sensor's readout time for the image timestamp. + * + *The start of the camera sensor readout after exposure. For a rolling shutter camera + * sensor, the timestamp is typically equal to {@code (the start of exposure time) + + * (exposure time) + (certain fixed offset)}. The fixed offset can vary per session, depending + * on the underlying sensor configuration. The benefit of using readout time is that when + * camera runs in a fixed frame rate, the timestamp intervals between frames are constant.
+ * + *Readout timestamp is supported only if {@link + * CameraCharacteristics#SENSOR_READOUT_TIMESTAMP} is + * {@link CameraMetadata#SENSOR_READOUT_TIMESTAMP_HARDWARE}.
+ * + *As long as readout timestamp is supported, if the timestamp base isi + * {@link #TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED}, or if the timestamp base is DEFAULT for a + * SurfaceView output, the image timestamps for the output are always readout time regardless + * of whether this function is called.
+ * + * @param on The output image timestamp is the start of exposure time if false, and + * the start of readout time if true. + */ + public void useReadoutTimestamp(boolean on) { + mUseReadoutTimestamp = on; + } + + /** Whether readout timestamp is used for this OutputConfiguration. + */ + public boolean isReadoutTimestampUsed() { + return mUseReadoutTimestamp; + } + /** * Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration} * instance. @@ -1130,6 +1171,7 @@ public final class OutputConfiguration implements Parcelable { this.mStreamUseCase = other.mStreamUseCase; this.mTimestampBase = other.mTimestampBase; this.mMirrorMode = other.mMirrorMode; + this.mUseReadoutTimestamp = other.mUseReadoutTimestamp; } /** @@ -1157,6 +1199,7 @@ public final class OutputConfiguration implements Parcelable { int timestampBase = source.readInt(); int mirrorMode = source.readInt(); + boolean useReadoutTimestamp = source.readInt() == 1; mSurfaceGroupId = surfaceSetId; mRotation = rotation; @@ -1185,6 +1228,7 @@ public final class OutputConfiguration implements Parcelable { mStreamUseCase = streamUseCase; mTimestampBase = timestampBase; mMirrorMode = mirrorMode; + mUseReadoutTimestamp = useReadoutTimestamp; } /** @@ -1305,6 +1349,7 @@ public final class OutputConfiguration implements Parcelable { dest.writeLong(mStreamUseCase); dest.writeInt(mTimestampBase); dest.writeInt(mMirrorMode); + dest.writeInt(mUseReadoutTimestamp ? 1 : 0); } /** @@ -1338,7 +1383,8 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution != other.mIsMultiResolution || mStreamUseCase != other.mStreamUseCase || mTimestampBase != other.mTimestampBase || - mMirrorMode != other.mMirrorMode) + mMirrorMode != other.mMirrorMode || + mUseReadoutTimestamp != other.mUseReadoutTimestamp) return false; if (mSensorPixelModesUsed.size() != other.mSensorPixelModesUsed.size()) { return false; @@ -1381,7 +1427,7 @@ public final class OutputConfiguration implements Parcelable { mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(), mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(), mDynamicRangeProfile, mColorSpace, mStreamUseCase, - mTimestampBase, mMirrorMode); + mTimestampBase, mMirrorMode, mUseReadoutTimestamp ? 1 : 0); } return HashCodeHelpers.hashCode( @@ -1391,7 +1437,7 @@ public final class OutputConfiguration implements Parcelable { mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(), mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(), mDynamicRangeProfile, mColorSpace, mStreamUseCase, mTimestampBase, - mMirrorMode); + mMirrorMode, mUseReadoutTimestamp ? 1 : 0); } private static final String TAG = "OutputConfiguration"; @@ -1433,4 +1479,8 @@ public final class OutputConfiguration implements Parcelable { private int mTimestampBase; // Mirroring mode private int mMirrorMode; + // Use readout timestamp + private boolean mUseReadoutTimestamp; + // Whether the timestamp base is set to READOUT_SENSOR + private boolean mIsReadoutSensorTimestampBase; }