Merge changes I4ff28737,I8433c40a into sc-dev
* changes:
Utils: intialize bitrate to 0
NuPlayerRenderer: intialize bitrate to 0
diff --git a/apex/Android.bp b/apex/Android.bp
index 545270e..6c45749 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -77,6 +77,9 @@
// - build artifacts (lib/javalib/bin) against Android 10 SDK
// so that the artifacts can run.
min_sdk_version: "29",
+ // Indicates that pre-installed version of this apex can be compressed.
+ // Whether it actually will be compressed is controlled on per-device basis.
+ compressible: true,
}
apex {
@@ -135,6 +138,9 @@
// - build artifacts (lib/javalib/bin) against Android 10 SDK
// so that the artifacts can run.
min_sdk_version: "29",
+ // Indicates that pre-installed version of this apex can be compressed.
+ // Whether it actually will be compressed is controlled on per-device basis.
+ compressible: true,
}
prebuilt_etc {
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index d428b4e..bbb0289 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -35,4 +35,10 @@
* Update the status of a camera device.
*/
oneway void notifyCameraState(in CameraSessionStats cameraSessionStats);
+
+ /**
+ * Reports whether the top activity needs a rotate and crop override.
+ */
+ boolean isRotateAndCropOverrideNeeded(String packageName, int sensorOrientation,
+ int lensFacing);
}
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 2f6bc30..d6642f3 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -72,6 +72,10 @@
return mIsMultiResolution;
}
+const std::vector<int32_t> &OutputConfiguration::getSensorPixelModesUsed() const {
+ return mSensorPixelModesUsed;
+}
+
OutputConfiguration::OutputConfiguration() :
mRotation(INVALID_ROTATION),
mSurfaceSetID(INVALID_SET_ID),
@@ -156,6 +160,11 @@
return err;
}
+ std::vector<int32_t> sensorPixelModesUsed;
+ if ((err = parcel->readParcelableVector(&sensorPixelModesUsed)) != OK) {
+ ALOGE("%s: Failed to read sensor pixel mode(s) from parcel", __FUNCTION__);
+ return err;
+ }
mRotation = rotation;
mSurfaceSetID = setID;
mSurfaceType = surfaceType;
@@ -171,6 +180,8 @@
mGbps.push_back(surface.graphicBufferProducer);
}
+ mSensorPixelModesUsed = std::move(sensorPixelModesUsed);
+
ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d,"
" physicalCameraId = %s, isMultiResolution = %d", __FUNCTION__, mRotation,
mSurfaceSetID, mSurfaceType, String8(mPhysicalCameraId).string(), mIsMultiResolution);
@@ -240,24 +251,51 @@
err = parcel->writeInt32(mIsMultiResolution ? 1 : 0);
if (err != OK) return err;
+ err = parcel->writeParcelableVector(mSensorPixelModesUsed);
+ if (err != OK) return err;
+
return OK;
}
+template <typename T>
+static bool simpleVectorsEqual(T first, T second) {
+ if (first.size() != second.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < first.size(); i++) {
+ if (first[i] != second[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool OutputConfiguration::gbpsEqual(const OutputConfiguration& other) const {
const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
other.getGraphicBufferProducers();
+ return simpleVectorsEqual(otherGbps, mGbps);
+}
- if (mGbps.size() != otherGbps.size()) {
- return false;
+bool OutputConfiguration::sensorPixelModesUsedEqual(const OutputConfiguration& other) const {
+ const std::vector<int32_t>& othersensorPixelModesUsed = other.getSensorPixelModesUsed();
+ return simpleVectorsEqual(othersensorPixelModesUsed, mSensorPixelModesUsed);
+}
+
+bool OutputConfiguration::sensorPixelModesUsedLessThan(const OutputConfiguration& other) const {
+ const std::vector<int32_t>& spms = other.getSensorPixelModesUsed();
+
+ if (mSensorPixelModesUsed.size() != spms.size()) {
+ return mSensorPixelModesUsed.size() < spms.size();
}
- for (size_t i = 0; i < mGbps.size(); i++) {
- if (mGbps[i] != otherGbps[i]) {
- return false;
+ for (size_t i = 0; i < spms.size(); i++) {
+ if (mSensorPixelModesUsed[i] != spms[i]) {
+ return mSensorPixelModesUsed[i] < spms[i];
}
}
- return true;
+ return false;
}
bool OutputConfiguration::gbpsLessThan(const OutputConfiguration& other) const {
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 6009370..f80ed3a 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -49,6 +49,8 @@
String16 getPhysicalCameraId() const;
bool isMultiResolution() const;
+ // set of sensor pixel mode resolutions allowed {MAX_RESOLUTION, DEFAULT_MODE};
+ const std::vector<int32_t>& getSensorPixelModesUsed() const;
/**
* Keep impl up-to-date with OutputConfiguration.java in frameworks/base
*/
@@ -86,7 +88,8 @@
mIsShared == other.mIsShared &&
gbpsEqual(other) &&
mPhysicalCameraId == other.mPhysicalCameraId &&
- mIsMultiResolution == other.mIsMultiResolution);
+ mIsMultiResolution == other.mIsMultiResolution &&
+ sensorPixelModesUsedEqual(other));
}
bool operator != (const OutputConfiguration& other) const {
return !(*this == other);
@@ -120,13 +123,19 @@
if (mIsMultiResolution != other.mIsMultiResolution) {
return mIsMultiResolution < other.mIsMultiResolution;
}
+ if (!sensorPixelModesUsedEqual(other)) {
+ return sensorPixelModesUsedLessThan(other);
+ }
return gbpsLessThan(other);
}
+
bool operator > (const OutputConfiguration& other) const {
return (*this != other && !(*this < other));
}
bool gbpsEqual(const OutputConfiguration& other) const;
+ bool sensorPixelModesUsedEqual(const OutputConfiguration& other) const;
+ bool sensorPixelModesUsedLessThan(const OutputConfiguration& other) const;
bool gbpsLessThan(const OutputConfiguration& other) const;
void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {mGbps.push_back(gbp);}
private:
@@ -140,6 +149,7 @@
bool mIsShared;
String16 mPhysicalCameraId;
bool mIsMultiResolution;
+ std::vector<int32_t> mSensorPixelModesUsed;
};
} // namespace params
} // namespace camera2
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 895514e..7387442 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -534,6 +534,7 @@
case ACAMERA_SENSOR_SENSITIVITY:
case ACAMERA_SENSOR_TEST_PATTERN_DATA:
case ACAMERA_SENSOR_TEST_PATTERN_MODE:
+ case ACAMERA_SENSOR_PIXEL_MODE:
case ACAMERA_SHADING_MODE:
case ACAMERA_STATISTICS_FACE_DETECT_MODE:
case ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE:
@@ -584,6 +585,7 @@
ANDROID_SENSOR_PROFILE_HUE_SAT_MAP,
ANDROID_SENSOR_PROFILE_TONE_CURVE,
ANDROID_SENSOR_OPAQUE_RAW_SIZE,
+ ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION,
ANDROID_SHADING_STRENGTH,
ANDROID_STATISTICS_HISTOGRAM_MODE,
ANDROID_STATISTICS_SHARPNESS_MAP_MODE,
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 889b8ab..70ce864 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -527,6 +527,13 @@
* scene as they do before. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use
* activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
* mode.</p>
+ * <p>For camera devices with the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability,
+ * ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION /
+ * ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION must be used as the
+ * coordinate system for requests where ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
* <p>The data representation is <code>int[5 * area_count]</code>.
* Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
* The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
@@ -536,7 +543,10 @@
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
*/
ACAMERA_CONTROL_AE_REGIONS = // int32[5*area_count]
ACAMERA_CONTROL_START + 4,
@@ -718,6 +728,12 @@
* scene as they do before. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use
* activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
* mode.</p>
+ * <p>For camera devices with the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability, ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION /
+ * ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION must be used as the
+ * coordinate system for requests where ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
* <p>The data representation is <code>int[5 * area_count]</code>.
* Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
* The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
@@ -727,7 +743,10 @@
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
*/
ACAMERA_CONTROL_AF_REGIONS = // int32[5*area_count]
ACAMERA_CONTROL_START + 8,
@@ -904,6 +923,12 @@
* the scene as they do before. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use
* activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
* mode.</p>
+ * <p>For camera devices with the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability, ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION /
+ * ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION must be used as the
+ * coordinate system for requests where ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
* <p>The data representation is <code>int[5 * area_count]</code>.
* Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
* The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
@@ -913,7 +938,10 @@
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
*/
ACAMERA_CONTROL_AWB_REGIONS = // int32[5*area_count]
ACAMERA_CONTROL_START + 12,
@@ -2801,6 +2829,51 @@
*/
ACAMERA_LENS_DISTORTION = // float[5]
ACAMERA_LENS_START + 13,
+ /**
+ * <p>The correction coefficients to correct for this camera device's
+ * radial and tangential lens distortion for a
+ * CaptureRequest with ACAMERA_SENSOR_PIXEL_MODE set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: float[5]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_LENS_DISTORTION, when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_LENS_DISTORTION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_LENS_DISTORTION_MAXIMUM_RESOLUTION = // float[5]
+ ACAMERA_LENS_START + 14,
+ /**
+ * <p>The parameters for this camera device's intrinsic
+ * calibration when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: float[5]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_LENS_INTRINSIC_CALIBRATION, when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_LENS_INTRINSIC_CALIBRATION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION = // float[5]
+ ACAMERA_LENS_START + 15,
ACAMERA_LENS_END,
/**
@@ -3428,6 +3501,12 @@
* coordinate system is post-zoom, meaning that the activeArraySize or
* preCorrectionActiveArraySize covers the camera device's field of view "after" zoom. See
* ACAMERA_CONTROL_ZOOM_RATIO for details.</p>
+ * <p>For camera devices with the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability, ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION /
+ * ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION must be used as the
+ * coordinate system for requests where ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
* <p>The data representation is int[4], which maps to (left, top, width, height).</p>
*
* @see ACAMERA_CONTROL_AE_TARGET_FPS_RANGE
@@ -3436,7 +3515,10 @@
* @see ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
* @see ACAMERA_SCALER_CROPPING_TYPE
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
*/
ACAMERA_SCALER_CROP_REGION = // int32[4]
ACAMERA_SCALER_START,
@@ -3538,8 +3620,6 @@
* set to either OFF or FAST.</p>
* <p>When multiple streams are used in a request, the minimum frame
* duration will be max(individual stream min durations).</p>
- * <p>The minimum frame duration of a stream (of a particular format, size)
- * is the same regardless of whether the stream is input or output.</p>
* <p>See ACAMERA_SENSOR_FRAME_DURATION and
* ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS for more details about
* calculating the max frame rate.</p>
@@ -3884,10 +3964,10 @@
* configurations which belong to this physical camera, and it will advertise and will only
* advertise the maximum supported resolutions for a particular format.</p>
* <p>If this camera device isn't a physical camera device constituting a logical camera,
- * but a standalone ULTRA_HIGH_RESOLUTION_SENSOR camera, this field represents the
- * multi-resolution input/output stream configurations of default mode and max resolution
- * modes. The sizes will be the maximum resolution of a particular format for default mode
- * and max resolution mode.</p>
+ * but a standalone <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * camera, this field represents the multi-resolution input/output stream configurations of
+ * default mode and max resolution modes. The sizes will be the maximum resolution of a
+ * particular format for default mode and max resolution mode.</p>
* <p>This field will only be advertised if the device is a physical camera of a
* logical multi-camera device or an ultra high resolution sensor camera. For a logical
* multi-camera, the camera API will derive the logical camera’s multi-resolution stream
@@ -3897,6 +3977,93 @@
ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS =
// int32[n*4] (acamera_metadata_enum_android_scaler_physical_camera_multi_resolution_stream_configurations_t)
ACAMERA_SCALER_START + 19,
+ /**
+ * <p>The available stream configurations that this
+ * camera device supports (i.e. format, width, height, output/input stream) for a
+ * CaptureRequest with ACAMERA_SENSOR_PIXEL_MODE set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_scaler_available_stream_configurations_maximum_resolution_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, for configurations
+ * which are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ * <p>Not all output formats may be supported in a configuration with
+ * an input stream of a particular format. For more details, see
+ * android.scaler.availableInputOutputFormatsMapMaximumResolution.</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION =
+ // int32[n*4] (acamera_metadata_enum_android_scaler_available_stream_configurations_maximum_resolution_t)
+ ACAMERA_SCALER_START + 20,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination when the camera device is sent a CaptureRequest with
+ * ACAMERA_SENSOR_PIXEL_MODE set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, for configurations
+ * which are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ * <p>When multiple streams are used in a request (if supported, when ACAMERA_SENSOR_PIXEL_MODE
+ * is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>), the
+ * minimum frame duration will be max(individual stream min durations).</p>
+ * <p>See ACAMERA_SENSOR_FRAME_DURATION and
+ * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION for more details about
+ * calculating the max frame rate.</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION
+ * @see ACAMERA_SENSOR_FRAME_DURATION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_SCALER_START + 21,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination when CaptureRequests are submitted with
+ * ACAMERA_SENSOR_PIXEL_MODE set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a></p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, for configurations
+ * which are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_SCALER_START + 22,
ACAMERA_SCALER_END,
/**
@@ -4683,6 +4850,67 @@
*/
ACAMERA_SENSOR_DYNAMIC_WHITE_LEVEL = // int32
ACAMERA_SENSOR_START + 29,
+ /**
+ * <p>Switches sensor pixel mode between maximum resolution mode and default mode.</p>
+ *
+ * <p>Type: byte (acamera_metadata_enum_android_sensor_pixel_mode_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * <li>ACaptureRequest</li>
+ * </ul></p>
+ *
+ * <p>This key controls whether the camera sensor operates in
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>
+ * mode or not. By default, all camera devices operate in
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_DEFAULT">CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT</a> mode.
+ * When operating in
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_DEFAULT">CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT</a> mode, sensors
+ * with <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability would typically perform pixel binning in order to improve low light
+ * performance, noise reduction etc. However, in
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>
+ * mode (supported only
+ * by <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * sensors), sensors typically operate in unbinned mode allowing for a larger image size.
+ * The stream configurations supported in
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>
+ * mode are also different from those of
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_DEFAULT">CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT</a> mode.
+ * They can be queried through
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#get">CameraCharacteristics#get</a> with
+ * <a href="https://developer.android.com/reference/CameraCharacteristics.html#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION)">CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION)</a>.
+ * Unless reported by both
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html">StreamConfigurationMap</a>s, the outputs from
+ * <code>android.scaler.streamConfigurationMapMaximumResolution</code> and
+ * <code>android.scaler.streamConfigurationMap</code>
+ * must not be mixed in the same CaptureRequest. In other words, these outputs are
+ * exclusive to each other.
+ * This key does not need to be set for reprocess requests.</p>
+ */
+ ACAMERA_SENSOR_PIXEL_MODE = // byte (acamera_metadata_enum_android_sensor_pixel_mode_t)
+ ACAMERA_SENSOR_START + 32,
+ /**
+ * <p>Whether <code>RAW</code> images requested have their bayer pattern as described by
+ * ACAMERA_SENSOR_INFO_BINNING_FACTOR.</p>
+ *
+ * @see ACAMERA_SENSOR_INFO_BINNING_FACTOR
+ *
+ * <p>Type: byte (acamera_metadata_enum_android_sensor_raw_binning_factor_used_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * </ul></p>
+ *
+ * <p>This key will only be present in devices advertisting the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability which also advertise <code>REMOSAIC_REPROCESSING</code> capability. On all other devices
+ * RAW targets will have a regular bayer pattern.</p>
+ */
+ ACAMERA_SENSOR_RAW_BINNING_FACTOR_USED = // byte (acamera_metadata_enum_android_sensor_raw_binning_factor_used_t)
+ ACAMERA_SENSOR_START + 33,
ACAMERA_SENSOR_END,
/**
@@ -4984,6 +5212,120 @@
*/
ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE = // int32[4]
ACAMERA_SENSOR_INFO_START + 10,
+ /**
+ * <p>The area of the image sensor which corresponds to active pixels after any geometric
+ * distortion correction has been applied, when the sensor runs in maximum resolution mode.</p>
+ *
+ * <p>Type: int32[4]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, when ACAMERA_SENSOR_PIXEL_MODE
+ * is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.
+ * Refer to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE for details, with sensor array related keys
+ * replaced with their
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>
+ * counterparts.
+ * This key will only be present for devices which advertise the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability.</p>
+ * <p>The data representation is <code>int[4]</code>, which maps to <code>(left, top, width, height)</code>.</p>
+ *
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION = // int32[4]
+ ACAMERA_SENSOR_INFO_START + 11,
+ /**
+ * <p>Dimensions of the full pixel array, possibly
+ * including black calibration pixels, when the sensor runs in maximum resolution mode.
+ * Analogous to ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE, when ACAMERA_SENSOR_PIXEL_MODE is
+ * set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int32[2]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>The pixel count of the full pixel array of the image sensor, which covers
+ * ACAMERA_SENSOR_INFO_PHYSICAL_SIZE area. This represents the full pixel dimensions of
+ * the raw buffers produced by this sensor, when it runs in maximum resolution mode. That
+ * is, when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.
+ * This key will only be present for devices which advertise the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability.</p>
+ *
+ * @see ACAMERA_SENSOR_INFO_PHYSICAL_SIZE
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION = // int32[2]
+ ACAMERA_SENSOR_INFO_START + 12,
+ /**
+ * <p>The area of the image sensor which corresponds to active pixels prior to the
+ * application of any geometric distortion correction, when the sensor runs in maximum
+ * resolution mode. This key must be used for crop / metering regions, only when
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int32[4]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+ * when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.
+ * This key will only be present for devices which advertise the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability.</p>
+ * <p>The data representation is <code>int[4]</code>, which maps to <code>(left, top, width, height)</code>.</p>
+ *
+ * @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION =
+ // int32[4]
+ ACAMERA_SENSOR_INFO_START + 13,
+ /**
+ * <p>Dimensions of the group of pixels which are under the same color filter.
+ * This specifies the width and height (pair of integers) of the group of pixels which fall
+ * under the same color filter for ULTRA_HIGH_RESOLUTION sensors.</p>
+ *
+ * <p>Type: int32[2]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Sensors can have pixels grouped together under the same color filter in order
+ * to improve various aspects of imaging such as noise reduction, low light
+ * performance etc. These groups can be of various sizes such as 2X2 (quad bayer),
+ * 3X3 (nona-bayer). This key specifies the length and width of the pixels grouped under
+ * the same color filter.</p>
+ * <p>This key will not be present if REMOSAIC_REPROCESSING is not supported, since RAW images
+ * will have a regular bayer pattern.</p>
+ * <p>This key will not be present for sensors which don't have the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
+ * capability.</p>
+ */
+ ACAMERA_SENSOR_INFO_BINNING_FACTOR = // int32[2]
+ ACAMERA_SENSOR_INFO_START + 14,
ACAMERA_SENSOR_INFO_END,
/**
@@ -6189,6 +6531,162 @@
*/
ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS = // int64[4*n]
ACAMERA_DEPTH_START + 8,
+ /**
+ * <p>The available depth dataspace stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream) when a CaptureRequest is submitted with
+ * ACAMERA_SENSOR_PIXEL_MODE set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_depth_available_depth_stream_configurations_maximum_resolution_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, for configurations which
+ * are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION =
+ // int32[n*4] (acamera_metadata_enum_android_depth_available_depth_stream_configurations_maximum_resolution_t)
+ ACAMERA_DEPTH_START + 9,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for depth output formats when a CaptureRequest is submitted with
+ * ACAMERA_SENSOR_PIXEL_MODE set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS, for configurations which
+ * are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ * <p>See ACAMERA_SENSOR_FRAME_DURATION and
+ * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION for more details about
+ * calculating the max frame rate.</p>
+ *
+ * @see ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS
+ * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION
+ * @see ACAMERA_SENSOR_FRAME_DURATION
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_DEPTH_START + 10,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for depth streams for CaptureRequests where
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS, for configurations which
+ * are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_DEPTH_START + 11,
+ /**
+ * <p>The available dynamic depth dataspace stream
+ * configurations that this camera device supports (i.e. format, width, height,
+ * output/input stream) for CaptureRequests where ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_maximum_resolution_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, for configurations
+ * which are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION =
+ // int32[n*4] (acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_maximum_resolution_t)
+ ACAMERA_DEPTH_START + 12,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for dynamic depth output streams for CaptureRequests where
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, for configurations
+ * which are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_DEPTH_START + 13,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for dynamic depth streams for CaptureRequests where
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Analogous to ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, for configurations
+ * which are applicable when ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ */
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_DEPTH_START + 14,
ACAMERA_DEPTH_END,
/**
@@ -6409,6 +6907,71 @@
*/
ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS = // int64[4*n]
ACAMERA_HEIC_START + 2,
+ /**
+ * <p>The available HEIC (ISO/IEC 23008-12) stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_heic_available_heic_stream_configurations_maximum_resolution_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Refer to ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS for details.</p>
+ * <p>All the configuration tuples <code>(format, width, height, input?)</code> will contain
+ * AIMAGE_FORMAT_HEIC format as OUTPUT only.</p>
+ *
+ * @see ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS
+ */
+ ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION =
+ // int32[n*4] (acamera_metadata_enum_android_heic_available_heic_stream_configurations_maximum_resolution_t)
+ ACAMERA_HEIC_START + 3,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for HEIC output formats for CaptureRequests where
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Refer to ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS for details.</p>
+ *
+ * @see ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS
+ */
+ ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_HEIC_START + 4,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for HEIC streams for CaptureRequests where
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Refer to ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS for details.</p>
+ *
+ * @see ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS
+ */
+ ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_HEIC_START + 5,
ACAMERA_HEIC_END,
} acamera_metadata_tag_t;
@@ -8359,6 +8922,20 @@
*/
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA = 14,
+ /**
+ * <p>This camera device is capable of producing ultra high resolution images in
+ * addition to the image sizes described in the
+ * android.scaler.streamConfigurationMap.
+ * It can operate in 'default' mode and 'max resolution' mode. It generally does this
+ * by binning pixels in 'default' mode and not binning them in 'max resolution' mode.
+ * <code>android.scaler.streamConfigurationMap</code> describes the streams supported in 'default'
+ * mode.
+ * The stream configurations supported in 'max resolution' mode are described by
+ * <code>android.scaler.streamConfigurationMapMaximumResolution</code>.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
+ = 16,
+
} acamera_metadata_enum_android_request_available_capabilities_t;
@@ -8514,6 +9091,16 @@
} acamera_metadata_enum_android_scaler_physical_camera_multi_resolution_stream_configurations_t;
+// ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+typedef enum acamera_metadata_enum_acamera_scaler_available_stream_configurations_maximum_resolution {
+ ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT
+ = 0,
+
+ ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT
+ = 1,
+
+} acamera_metadata_enum_android_scaler_available_stream_configurations_maximum_resolution_t;
+
// ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
typedef enum acamera_metadata_enum_acamera_sensor_reference_illuminant1 {
@@ -8672,6 +9259,42 @@
} acamera_metadata_enum_android_sensor_test_pattern_mode_t;
+// ACAMERA_SENSOR_PIXEL_MODE
+typedef enum acamera_metadata_enum_acamera_sensor_pixel_mode {
+ /**
+ * <p>This is the default sensor pixel mode. This is the only sensor pixel mode
+ * supported unless a camera device advertises
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>.</p>
+ */
+ ACAMERA_SENSOR_PIXEL_MODE_DEFAULT = 0,
+
+ /**
+ * <p>This sensor pixel mode is offered by devices with capability
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILTIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>.
+ * In this mode, sensors typically do not bin pixels, as a result can offer larger
+ * image sizes.</p>
+ */
+ ACAMERA_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION = 1,
+
+} acamera_metadata_enum_android_sensor_pixel_mode_t;
+
+// ACAMERA_SENSOR_RAW_BINNING_FACTOR_USED
+typedef enum acamera_metadata_enum_acamera_sensor_raw_binning_factor_used {
+ /**
+ * <p>The <code>RAW</code> targets in this capture have ACAMERA_SENSOR_INFO_BINNING_FACTOR as the
+ * bayer pattern.</p>
+ *
+ * @see ACAMERA_SENSOR_INFO_BINNING_FACTOR
+ */
+ ACAMERA_SENSOR_RAW_BINNING_FACTOR_USED_TRUE = 0,
+
+ /**
+ * <p>The <code>RAW</code> targets have a regular bayer pattern in this capture.</p>
+ */
+ ACAMERA_SENSOR_RAW_BINNING_FACTOR_USED_FALSE = 1,
+
+} acamera_metadata_enum_android_sensor_raw_binning_factor_used_t;
+
// ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
typedef enum acamera_metadata_enum_acamera_sensor_info_color_filter_arrangement {
@@ -9156,6 +9779,26 @@
} acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_t;
+// ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+typedef enum acamera_metadata_enum_acamera_depth_available_depth_stream_configurations_maximum_resolution {
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT
+ = 0,
+
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT
+ = 1,
+
+} acamera_metadata_enum_android_depth_available_depth_stream_configurations_maximum_resolution_t;
+
+// ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+typedef enum acamera_metadata_enum_acamera_depth_available_dynamic_depth_stream_configurations_maximum_resolution {
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT
+ = 0,
+
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT
+ = 1,
+
+} acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_maximum_resolution_t;
+
// ACAMERA_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
typedef enum acamera_metadata_enum_acamera_logical_multi_camera_sensor_sync_type {
@@ -9207,6 +9850,16 @@
} acamera_metadata_enum_android_heic_available_heic_stream_configurations_t;
+// ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+typedef enum acamera_metadata_enum_acamera_heic_available_heic_stream_configurations_maximum_resolution {
+ ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT
+ = 0,
+
+ ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT
+ = 1,
+
+} acamera_metadata_enum_android_heic_available_heic_stream_configurations_maximum_resolution_t;
+
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index 940f57c..bf9e5ff 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -1401,13 +1401,13 @@
ps_inp_raw_buf->apv_bufs[1] = uPlane;
ps_inp_raw_buf->apv_bufs[2] = vPlane;
- ps_inp_raw_buf->au4_wd[0] = input->width();
- ps_inp_raw_buf->au4_wd[1] = input->width() / 2;
- ps_inp_raw_buf->au4_wd[2] = input->width() / 2;
+ ps_inp_raw_buf->au4_wd[0] = mSize->width;
+ ps_inp_raw_buf->au4_wd[1] = mSize->width / 2;
+ ps_inp_raw_buf->au4_wd[2] = mSize->width / 2;
- ps_inp_raw_buf->au4_ht[0] = input->height();
- ps_inp_raw_buf->au4_ht[1] = input->height() / 2;
- ps_inp_raw_buf->au4_ht[2] = input->height() / 2;
+ ps_inp_raw_buf->au4_ht[0] = mSize->height;
+ ps_inp_raw_buf->au4_ht[1] = mSize->height / 2;
+ ps_inp_raw_buf->au4_ht[2] = mSize->height / 2;
ps_inp_raw_buf->au4_strd[0] = yStride;
ps_inp_raw_buf->au4_strd[1] = uStride;
@@ -1432,11 +1432,11 @@
ps_inp_raw_buf->apv_bufs[0] = yPlane;
ps_inp_raw_buf->apv_bufs[1] = uPlane;
- ps_inp_raw_buf->au4_wd[0] = input->width();
- ps_inp_raw_buf->au4_wd[1] = input->width();
+ ps_inp_raw_buf->au4_wd[0] = mSize->width;
+ ps_inp_raw_buf->au4_wd[1] = mSize->width;
- ps_inp_raw_buf->au4_ht[0] = input->height();
- ps_inp_raw_buf->au4_ht[1] = input->height() / 2;
+ ps_inp_raw_buf->au4_ht[0] = mSize->height;
+ ps_inp_raw_buf->au4_ht[1] = mSize->height / 2;
ps_inp_raw_buf->au4_strd[0] = yStride;
ps_inp_raw_buf->au4_strd[1] = uStride;
diff --git a/media/codec2/core/include/C2Buffer.h b/media/codec2/core/include/C2Buffer.h
index fe37b05..a5d6fbf 100644
--- a/media/codec2/core/include/C2Buffer.h
+++ b/media/codec2/core/include/C2Buffer.h
@@ -642,7 +642,8 @@
* \retval C2_REFUSED no permission to complete the allocation
* \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
* \retval C2_OMITTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation
+ * (unexpected)
*/
virtual c2_status_t newLinearAllocation(
uint32_t capacity __unused, C2MemoryUsage usage __unused,
@@ -666,7 +667,8 @@
* \retval C2_REFUSED no permission to recreate the allocation
* \retval C2_BAD_VALUE invalid handle (caller error)
* \retval C2_OMITTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation
+ * (unexpected)
*/
virtual c2_status_t priorLinearAllocation(
const C2Handle *handle __unused,
@@ -699,7 +701,8 @@
* \retval C2_REFUSED no permission to complete the allocation
* \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
* \retval C2_OMITTED this allocator does not support 2D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation
+ * (unexpected)
*/
virtual c2_status_t newGraphicAllocation(
uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
@@ -724,7 +727,8 @@
* \retval C2_REFUSED no permission to recreate the allocation
* \retval C2_BAD_VALUE invalid handle (caller error)
* \retval C2_OMITTED this allocator does not support 2D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during recreation
+ * (unexpected)
*/
virtual c2_status_t priorGraphicAllocation(
const C2Handle *handle __unused,
@@ -908,7 +912,8 @@
* \retval C2_REFUSED no permission to complete any required allocation
* \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
* \retval C2_OMITTED this pool does not support linear blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation
+ * (unexpected)
*/
virtual c2_status_t fetchLinearBlock(
uint32_t capacity __unused, C2MemoryUsage usage __unused,
@@ -937,7 +942,8 @@
* \retval C2_REFUSED no permission to complete any required allocation
* \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
* \retval C2_OMITTED this pool does not support circular blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation
+ * (unexpected)
*/
virtual c2_status_t fetchCircularBlock(
uint32_t capacity __unused, C2MemoryUsage usage __unused,
@@ -969,7 +975,8 @@
* \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
* error)
* \retval C2_OMITTED this pool does not support 2D blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation
+ * (unexpected)
*/
virtual c2_status_t fetchGraphicBlock(
uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
@@ -980,6 +987,90 @@
}
virtual ~C2BlockPool() = default;
+
+ /**
+ * Blocking fetch for linear block. Obtains a linear writable block of given |capacity|
+ * and |usage|. If a block can be successfully obtained, the block is stored in |block|,
+ * |fence| is set to a null-fence and C2_OK is returned.
+ *
+ * If a block cannot be temporarily obtained, |block| is set to nullptr, a waitable fence
+ * is stored into |fence| and C2_BLOCKING is returned.
+ *
+ * Otherwise, |block| is set to nullptr and |fence| is set to a null-fence. The waitable
+ * fence is signalled when the temporary restriction on fetch is lifted.
+ * e.g. more memory is available to fetch because some meomory or prior blocks were released.
+ *
+ * \param capacity the size of requested block.
+ * \param usage the memory usage info for the requested block. Returned blocks will be
+ * optimized for this usage, but may be used with any usage. One exception:
+ * protected blocks/buffers can only be used in a protected scenario.
+ * \param block pointer to where the obtained block shall be stored on success. nullptr will
+ * be stored here on failure
+ * \param fence pointer to where the fence shall be stored on C2_BLOCKING error.
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_BLOCKING the operation is blocked
+ * \retval C2_REFUSED no permission to complete any required allocation
+ * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+ * \retval C2_OMITTED this pool does not support linear blocks nor fence.
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation
+ * (unexpected)
+ */
+ virtual c2_status_t fetchLinearBlock(
+ uint32_t capacity __unused, C2MemoryUsage usage __unused,
+ std::shared_ptr<C2LinearBlock> *block /* nonnull */,
+ C2Fence *fence /* nonnull */) {
+ *block = nullptr;
+ (void) fence;
+ return C2_OMITTED;
+ }
+
+ /**
+ * Blocking fetch for 2D graphic block. Obtains a 2D graphic writable block of given |capacity|
+ * and |usage|. If a block can be successfully obtained, the block is stored in |block|,
+ * |fence| is set to a null-fence and C2_OK is returned.
+ *
+ * If a block cannot be temporarily obtained, |block| is set to nullptr, a waitable fence
+ * is stored into |fence| and C2_BLOCKING is returned.
+ *
+ * Otherwise, |block| is set to nullptr and |fence| is set to a null-fence. The waitable
+ * fence is signalled when the temporary restriction on fetch is lifted.
+ * e.g. more memory is available to fetch because some meomory or prior blocks were released.
+ *
+ * \param width the width of requested block (the obtained block could be slightly larger, e.g.
+ * to accommodate any system-required alignment)
+ * \param height the height of requested block (the obtained block could be slightly larger,
+ * e.g. to accommodate any system-required alignment)
+ * \param format the pixel format of requested block. This could be a vendor specific format.
+ * \param usage the memory usage info for the requested block. Returned blocks will be
+ * optimized for this usage, but may be used with any usage. One exception:
+ * protected blocks/buffers can only be used in a protected scenario.
+ * \param block pointer to where the obtained block shall be stored on success. nullptr
+ * will be stored here on failure
+ * \param fence pointer to where the fence shall be stored on C2_BLOCKING error.
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_BLOCKING the operation is blocked
+ * \retval C2_REFUSED no permission to complete any required allocation
+ * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
+ * error)
+ * \retval C2_OMITTED this pool does not support 2D blocks
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation
+ * (unexpected)
+ */
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+ C2MemoryUsage usage __unused,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
+ C2Fence *fence /* nonnull */) {
+ *block = nullptr;
+ (void) fence;
+ return C2_OMITTED;
+ }
protected:
C2BlockPool() = default;
};
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index 008def8..122aacd 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -15,7 +15,6 @@
defaults: ["hidl_defaults"],
srcs: [
- "OutputBufferQueue.cpp",
"types.cpp",
],
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 3a47ae9..9e17f7a 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -42,6 +42,45 @@
// Resource directory
static std::string sResourceDir = "";
+struct CompToURL {
+ std::string mime;
+ std::string mURL;
+ std::string info;
+};
+
+std::vector<CompToURL> kCompToURL = {
+ {"mp4a-latm",
+ "bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.info"},
+ {"mp4a-latm",
+ "bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"},
+ {"audio/mpeg",
+ "bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.info"},
+ {"audio/mpeg",
+ "bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"},
+ {"3gpp",
+ "sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz.info"},
+ {"3gpp",
+ "sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"},
+ {"amr-wb",
+ "bbb_amrwb_1ch_14kbps_16000hz.amrwb", "bbb_amrwb_1ch_14kbps_16000hz.info"},
+ {"amr-wb",
+ "bbb_amrwb_1ch_14kbps_16000hz.amrwb", "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"},
+ {"vorbis",
+ "bbb_vorbis_stereo_128kbps_48000hz.vorbis", "bbb_vorbis_stereo_128kbps_48000hz.info"},
+ {"opus",
+ "bbb_opus_stereo_128kbps_48000hz.opus", "bbb_opus_stereo_128kbps_48000hz.info"},
+ {"g711-alaw",
+ "bbb_g711alaw_1ch_8khz.raw", "bbb_g711alaw_1ch_8khz.info"},
+ {"g711-mlaw",
+ "bbb_g711mulaw_1ch_8khz.raw", "bbb_g711mulaw_1ch_8khz.info"},
+ {"gsm",
+ "bbb_gsm_1ch_8khz_13kbps.raw", "bbb_gsm_1ch_8khz_13kbps.info"},
+ {"raw",
+ "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le.info"},
+ {"flac",
+ "bbb_flac_stereo_680kbps_48000hz.flac", "bbb_flac_stereo_680kbps_48000hz.info"},
+};
+
class LinearBuffer : public C2Buffer {
public:
explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
@@ -76,33 +115,17 @@
mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
ASSERT_NE(mLinearPool, nullptr);
- mCompName = unknown_comp;
- struct StringToName {
- const char* Name;
- standardComp CompName;
- };
- const StringToName kStringToName[] = {
- {"xaac", xaac}, {"mp3", mp3}, {"amrnb", amrnb},
- {"amrwb", amrwb}, {"aac", aac}, {"vorbis", vorbis},
- {"opus", opus}, {"pcm", pcm}, {"g711.alaw", g711alaw},
- {"g711.mlaw", g711mlaw}, {"gsm", gsm}, {"raw", raw},
- {"flac", flac},
- };
- const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
+ std::vector<std::unique_ptr<C2Param>> queried;
+ mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
+ ASSERT_GT(queried.size(), 0);
- // Find the component type
- for (size_t i = 0; i < kNumStringToName; ++i) {
- if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
- mCompName = kStringToName[i].CompName;
- break;
- }
- }
+ mMime = ((C2PortMediaTypeSetting::input*)queried[0].get())->m.value;
+
mEos = false;
mFramesReceived = 0;
mTimestampUs = 0u;
mWorkResult = C2_OK;
mTimestampDevTest = false;
- if (mCompName == unknown_comp) mDisableTest = true;
if (mDisableTest) std::cout << "[ WARN ] Test Disabled \n";
}
@@ -119,6 +142,8 @@
virtual void validateTimestampList(int32_t* bitStreamInfo);
+ void GetURLForComponent(char* mURL, char* info, size_t streamIndex = 0);
+
struct outputMetaData {
uint64_t timestampUs;
uint32_t rangeLength;
@@ -158,29 +183,12 @@
}
}
- enum standardComp {
- xaac,
- mp3,
- amrnb,
- amrwb,
- aac,
- vorbis,
- opus,
- pcm,
- g711alaw,
- g711mlaw,
- gsm,
- raw,
- flac,
- unknown_comp,
- };
-
+ std::string mMime;
std::string mInstanceName;
std::string mComponentName;
bool mEos;
bool mDisableTest;
bool mTimestampDevTest;
- standardComp mCompName;
int32_t mWorkResult;
uint64_t mTimestampUs;
@@ -217,7 +225,7 @@
};
void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
- Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) {
+ bool& disableTest) {
// Validate its a C2 Component
if (component->getName().find("c2") == std::string::npos) {
ALOGE("Not a c2 component");
@@ -244,13 +252,6 @@
return;
}
}
-
- // Validates component name
- if (compName == Codec2AudioDecHidlTest::unknown_comp) {
- ALOGE("Component InValid");
- disableTest = true;
- return;
- }
ALOGV("Component Valid");
}
@@ -271,7 +272,7 @@
// parsing the header of elementary stream. Client needs to collect this
// information and reconfigure
void getInputChannelInfo(const std::shared_ptr<android::Codec2Client::Component>& component,
- Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
+ std::string mime, int32_t* bitStreamInfo) {
// query nSampleRate and nChannels
std::initializer_list<C2Param::Index> indices{
C2StreamSampleRateInfo::output::PARAM_TYPE,
@@ -288,89 +289,29 @@
C2Param* param = inParams[i].get();
bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
}
- switch (compName) {
- case Codec2AudioDecHidlTest::amrnb: {
- ASSERT_EQ(bitStreamInfo[0], 8000);
- ASSERT_EQ(bitStreamInfo[1], 1);
- break;
- }
- case Codec2AudioDecHidlTest::amrwb: {
- ASSERT_EQ(bitStreamInfo[0], 16000);
- ASSERT_EQ(bitStreamInfo[1], 1);
- break;
- }
- case Codec2AudioDecHidlTest::gsm: {
- ASSERT_EQ(bitStreamInfo[0], 8000);
- break;
- }
- default:
- break;
+ if (mime.find("3gpp") != std::string::npos) {
+ ASSERT_EQ(bitStreamInfo[0], 8000);
+ ASSERT_EQ(bitStreamInfo[1], 1);
+ } else if (mime.find("amr-wb") != std::string::npos) {
+ ASSERT_EQ(bitStreamInfo[0], 16000);
+ ASSERT_EQ(bitStreamInfo[1], 1);
+ } else if (mime.find("gsm") != std::string::npos) {
+ ASSERT_EQ(bitStreamInfo[0], 8000);
}
}
}
-// number of elementary streams per component
-#define STREAM_COUNT 2
-
// LookUpTable of clips and metadata for component testing
-void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL, char* info,
- size_t streamIndex = 0) {
- struct CompToURL {
- Codec2AudioDecHidlTest::standardComp comp;
- const char mURL[STREAM_COUNT][512];
- const char info[STREAM_COUNT][512];
- };
- ASSERT_TRUE(streamIndex < STREAM_COUNT);
-
- static const CompToURL kCompToURL[] = {
- {Codec2AudioDecHidlTest::standardComp::xaac,
- {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
- {"bbb_aac_stereo_128kbps_48000hz.info",
- "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
- {Codec2AudioDecHidlTest::standardComp::mp3,
- {"bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.mp3"},
- {"bbb_mp3_stereo_192kbps_48000hz.info",
- "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}},
- {Codec2AudioDecHidlTest::standardComp::aac,
- {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
- {"bbb_aac_stereo_128kbps_48000hz.info",
- "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
- {Codec2AudioDecHidlTest::standardComp::amrnb,
- {"sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz.amrnb"},
- {"sine_amrnb_1ch_12kbps_8000hz.info",
- "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}},
- {Codec2AudioDecHidlTest::standardComp::amrwb,
- {"bbb_amrwb_1ch_14kbps_16000hz.amrwb", "bbb_amrwb_1ch_14kbps_16000hz.amrwb"},
- {"bbb_amrwb_1ch_14kbps_16000hz.info",
- "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}},
- {Codec2AudioDecHidlTest::standardComp::vorbis,
- {"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""},
- {"bbb_vorbis_stereo_128kbps_48000hz.info", ""}},
- {Codec2AudioDecHidlTest::standardComp::opus,
- {"bbb_opus_stereo_128kbps_48000hz.opus", ""},
- {"bbb_opus_stereo_128kbps_48000hz.info", ""}},
- {Codec2AudioDecHidlTest::standardComp::g711alaw,
- {"bbb_g711alaw_1ch_8khz.raw", ""},
- {"bbb_g711alaw_1ch_8khz.info", ""}},
- {Codec2AudioDecHidlTest::standardComp::g711mlaw,
- {"bbb_g711mulaw_1ch_8khz.raw", ""},
- {"bbb_g711mulaw_1ch_8khz.info", ""}},
- {Codec2AudioDecHidlTest::standardComp::gsm,
- {"bbb_gsm_1ch_8khz_13kbps.raw", ""},
- {"bbb_gsm_1ch_8khz_13kbps.info", ""}},
- {Codec2AudioDecHidlTest::standardComp::raw,
- {"bbb_raw_1ch_8khz_s32le.raw", ""},
- {"bbb_raw_1ch_8khz_s32le.info", ""}},
- {Codec2AudioDecHidlTest::standardComp::flac,
- {"bbb_flac_stereo_680kbps_48000hz.flac", ""},
- {"bbb_flac_stereo_680kbps_48000hz.info", ""}},
- };
-
- for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
- if (kCompToURL[i].comp == comp) {
- strcat(mURL, kCompToURL[i].mURL[streamIndex]);
- strcat(info, kCompToURL[i].info[streamIndex]);
- return;
+void Codec2AudioDecHidlTestBase::GetURLForComponent(char* mURL, char* info, size_t streamIndex) {
+ int streamCount = 0;
+ for (size_t i = 0; i < kCompToURL.size(); ++i) {
+ if (mMime.find(kCompToURL[i].mime) != std::string::npos) {
+ if (streamCount == streamIndex) {
+ strcat(mURL, kCompToURL[i].mURL.c_str());
+ strcat(info, kCompToURL[i].info.c_str());
+ return;
+ }
+ streamCount++;
}
}
}
@@ -461,7 +402,7 @@
void Codec2AudioDecHidlTestBase::validateTimestampList(int32_t* bitStreamInfo) {
uint32_t samplesReceived = 0;
// Update SampleRate and ChannelCount
- ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+ ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mMime, bitStreamInfo));
int32_t nSampleRate = bitStreamInfo[0];
int32_t nChannels = bitStreamInfo[1];
std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
@@ -486,7 +427,7 @@
TEST_P(Codec2AudioDecHidlTest, validateCompName) {
if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ALOGV("Checks if the given component is a valid audio component");
- validateComponent(mComponent, mCompName, mDisableTest);
+ validateComponent(mComponent, mDisableTest);
ASSERT_EQ(mDisableTest, false);
}
@@ -495,7 +436,7 @@
if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ASSERT_EQ(mComponent->start(), C2_OK);
int32_t bitStreamInfo[2] = {0};
- ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+ ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mMime, bitStreamInfo));
setupConfigParam(mComponent, bitStreamInfo);
ASSERT_EQ(mComponent->stop(), C2_OK);
}
@@ -523,7 +464,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info, streamIndex);
+ GetURLForComponent(mURL, info, streamIndex);
if (!strcmp(mURL, sResourceDir.c_str())) {
ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL %s ", sResourceDir.c_str(), mURL);
return;
@@ -536,11 +477,11 @@
mFramesReceived = 0;
mTimestampUs = 0;
int32_t bitStreamInfo[2] = {0};
- if (mCompName == raw) {
+ if (mMime.find("raw") != std::string::npos) {
bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1;
} else {
- ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+ ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mMime, bitStreamInfo));
}
if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n";
@@ -591,17 +532,17 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
int32_t bitStreamInfo[2] = {0};
- if (mCompName == raw) {
+ if (mMime.find("raw") != std::string::npos) {
bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1;
} else {
- ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+ ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mMime, bitStreamInfo));
}
if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n";
@@ -683,17 +624,17 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
int32_t bitStreamInfo[2] = {0};
- if (mCompName == raw) {
+ if (mMime.find("raw") != std::string::npos) {
bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1;
} else {
- ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+ ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mMime, bitStreamInfo));
}
if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n";
@@ -768,7 +709,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
eleInfo.open(info);
ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
@@ -798,11 +739,11 @@
}
eleInfo.close();
int32_t bitStreamInfo[2] = {0};
- if (mCompName == raw) {
+ if (mMime.find("raw") != std::string::npos) {
bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1;
} else {
- ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+ ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mMime, bitStreamInfo));
}
if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n";
@@ -853,7 +794,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
if (!strcmp(mURL, sResourceDir.c_str())) {
ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL %s ", sResourceDir.c_str(), mURL);
return;
@@ -864,11 +805,11 @@
ASSERT_GE(numCsds, 0) << "Error in parsing input info file";
int32_t bitStreamInfo[2] = {0};
- if (mCompName == raw) {
+ if (mMime.find("raw") != std::string::npos) {
bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1;
} else {
- ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+ ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mMime, bitStreamInfo));
}
if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n";
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index b520c17..e23a5bd 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -48,6 +48,52 @@
// Resource directory
static std::string sResourceDir = "";
+struct CompToURL {
+ std::string mime;
+ std::string mURL;
+ std::string info;
+ std::string chksum;
+};
+std::vector<CompToURL> kCompToURL = {
+ {"avc",
+ "bbb_avc_176x144_300kbps_60fps.h264", "bbb_avc_176x144_300kbps_60fps.info",
+ "bbb_avc_176x144_300kbps_60fps_chksum.md5"},
+ {"avc",
+ "bbb_avc_640x360_768kbps_30fps.h264", "bbb_avc_640x360_768kbps_30fps.info",
+ "bbb_avc_640x360_768kbps_30fps_chksum.md5"},
+ {"hevc",
+ "bbb_hevc_176x144_176kbps_60fps.hevc", "bbb_hevc_176x144_176kbps_60fps.info",
+ "bbb_hevc_176x144_176kbps_60fps_chksum.md5"},
+ {"hevc",
+ "bbb_hevc_640x360_1600kbps_30fps.hevc", "bbb_hevc_640x360_1600kbps_30fps.info",
+ "bbb_hevc_640x360_1600kbps_30fps_chksum.md5"},
+ {"mpeg2",
+ "bbb_mpeg2_176x144_105kbps_25fps.m2v", "bbb_mpeg2_176x144_105kbps_25fps.info", ""},
+ {"mpeg2",
+ "bbb_mpeg2_352x288_1mbps_60fps.m2v","bbb_mpeg2_352x288_1mbps_60fps.info", ""},
+ {"3gpp",
+ "bbb_h263_352x288_300kbps_12fps.h263", "bbb_h263_352x288_300kbps_12fps.info", ""},
+ {"mp4v-es",
+ "bbb_mpeg4_352x288_512kbps_30fps.m4v", "bbb_mpeg4_352x288_512kbps_30fps.info", ""},
+ {"vp8",
+ "bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_176x144_240kbps_60fps.info", ""},
+ {"vp8",
+ "bbb_vp8_640x360_2mbps_30fps.vp8", "bbb_vp8_640x360_2mbps_30fps.info",
+ "bbb_vp8_640x360_2mbps_30fps_chksm.md5"},
+ {"vp9",
+ "bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_176x144_285kbps_60fps.info", ""},
+ {"vp9",
+ "bbb_vp9_640x360_1600kbps_30fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.info",
+ "bbb_vp9_640x360_1600kbps_30fps_chksm.md5"},
+ {"vp9",
+ "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9",
+ "bbb_vp9_704x480_280kbps_24fps_altref_2.info", ""},
+ {"av01",
+ "bbb_av1_640_360.av1", "bbb_av1_640_360.info", "bbb_av1_640_360_chksum.md5"},
+ {"av01",
+ "bbb_av1_176_144.av1", "bbb_av1_176_144.info", "bbb_av1_176_144_chksm.md5"},
+};
+
class LinearBuffer : public C2Buffer {
public:
explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
@@ -85,26 +131,11 @@
mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
ASSERT_NE(mLinearPool, nullptr);
- mCompName = unknown_comp;
- struct StringToName {
- const char* Name;
- standardComp CompName;
- };
+ std::vector<std::unique_ptr<C2Param>> queried;
+ mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
+ ASSERT_GT(queried.size(), 0);
- const StringToName kStringToName[] = {
- {"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4},
- {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9}, {"av1", av1},
- };
-
- const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
-
- // Find the component type
- for (size_t i = 0; i < kNumStringToName; ++i) {
- if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
- mCompName = kStringToName[i].CompName;
- break;
- }
- }
+ mMime = ((C2PortMediaTypeSetting::input*)queried[0].get())->m.value;
mEos = false;
mFramesReceived = 0;
mTimestampUs = 0u;
@@ -114,11 +145,11 @@
mMd5Offset = 0;
mMd5Enable = false;
mRefMd5 = nullptr;
- if (mCompName == unknown_comp) mDisableTest = true;
C2SecureModeTuning secureModeTuning{};
mComponent->query({&secureModeTuning}, {}, C2_MAY_BLOCK, nullptr);
- if (secureModeTuning.value == C2Config::SM_READ_PROTECTED) {
+ if (secureModeTuning.value == C2Config::SM_READ_PROTECTED ||
+ secureModeTuning.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED) {
mDisableTest = true;
}
@@ -136,6 +167,9 @@
// Get the test parameters from GetParam call.
virtual void getParams() {}
+ void GetURLChksmForComponent(char* mURL, char* info, char* chksum, size_t streamIndex);
+ void GetURLForComponent(char* mURL, char* info, size_t streamIndex = 0);
+
/* Calculate the CKSUM for the data in inbuf */
void calc_md5_cksum(uint8_t* pu1_inbuf, uint32_t u4_stride, uint32_t u4_width,
uint32_t u4_height, uint8_t* pu1_cksum_p) {
@@ -267,18 +301,7 @@
}
}
- enum standardComp {
- h263,
- avc,
- mpeg2,
- mpeg4,
- hevc,
- vp8,
- vp9,
- av1,
- unknown_comp,
- };
-
+ std::string mMime;
std::string mInstanceName;
std::string mComponentName;
@@ -291,7 +314,6 @@
char* mRefMd5;
std::list<uint64_t> mTimestampUslist;
std::list<uint64_t> mFlushedIndices;
- standardComp mCompName;
int32_t mWorkResult;
int32_t mReorderDepth;
@@ -324,7 +346,7 @@
};
void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
- Codec2VideoDecHidlTest::standardComp compName, bool& disableTest) {
+ bool& disableTest) {
// Validate its a C2 Component
if (component->getName().find("c2") == std::string::npos) {
ALOGE("Not a c2 component");
@@ -351,83 +373,32 @@
return;
}
}
-
- // Validates component name
- if (compName == Codec2VideoDecHidlTest::unknown_comp) {
- ALOGE("Component InValid");
- disableTest = true;
- return;
- }
ALOGV("Component Valid");
}
// number of elementary streams per component
#define STREAM_COUNT 3
// LookUpTable of clips, metadata and chksum for component testing
-void GetURLChksmForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL, char* info,
- char* chksum, size_t streamIndex = 1) {
- struct CompToURL {
- Codec2VideoDecHidlTest::standardComp comp;
- const char mURL[STREAM_COUNT][512];
- const char info[STREAM_COUNT][512];
- const char chksum[STREAM_COUNT][512];
- };
- ASSERT_TRUE(streamIndex < STREAM_COUNT);
-
- static const CompToURL kCompToURL[] = {
- {Codec2VideoDecHidlTest::standardComp::avc,
- {"bbb_avc_176x144_300kbps_60fps.h264", "bbb_avc_640x360_768kbps_30fps.h264", ""},
- {"bbb_avc_176x144_300kbps_60fps.info", "bbb_avc_640x360_768kbps_30fps.info", ""},
- {"bbb_avc_176x144_300kbps_60fps_chksum.md5",
- "bbb_avc_640x360_768kbps_30fps_chksum.md5", ""}},
- {Codec2VideoDecHidlTest::standardComp::hevc,
- {"bbb_hevc_176x144_176kbps_60fps.hevc", "bbb_hevc_640x360_1600kbps_30fps.hevc", ""},
- {"bbb_hevc_176x144_176kbps_60fps.info", "bbb_hevc_640x360_1600kbps_30fps.info", ""},
- {"bbb_hevc_176x144_176kbps_60fps_chksum.md5",
- "bbb_hevc_640x360_1600kbps_30fps_chksum.md5", ""}},
- {Codec2VideoDecHidlTest::standardComp::mpeg2,
- {"bbb_mpeg2_176x144_105kbps_25fps.m2v", "bbb_mpeg2_352x288_1mbps_60fps.m2v", ""},
- {"bbb_mpeg2_176x144_105kbps_25fps.info", "bbb_mpeg2_352x288_1mbps_60fps.info", ""},
- {"", "", ""}},
- {Codec2VideoDecHidlTest::standardComp::h263,
- {"", "bbb_h263_352x288_300kbps_12fps.h263", ""},
- {"", "bbb_h263_352x288_300kbps_12fps.info", ""},
- {"", "", ""}},
- {Codec2VideoDecHidlTest::standardComp::mpeg4,
- {"", "bbb_mpeg4_352x288_512kbps_30fps.m4v", ""},
- {"", "bbb_mpeg4_352x288_512kbps_30fps.info", ""},
- {"", "", ""}},
- {Codec2VideoDecHidlTest::standardComp::vp8,
- {"bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_640x360_2mbps_30fps.vp8", ""},
- {"bbb_vp8_176x144_240kbps_60fps.info", "bbb_vp8_640x360_2mbps_30fps.info", ""},
- {"", "bbb_vp8_640x360_2mbps_30fps_chksm.md5", ""}},
- {Codec2VideoDecHidlTest::standardComp::vp9,
- {"bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9",
- "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9"},
- {"bbb_vp9_176x144_285kbps_60fps.info", "bbb_vp9_640x360_1600kbps_30fps.info",
- "bbb_vp9_704x480_280kbps_24fps_altref_2.info"},
- {"", "bbb_vp9_640x360_1600kbps_30fps_chksm.md5", ""}},
- {Codec2VideoDecHidlTest::standardComp::av1,
- {"bbb_av1_640_360.av1", "bbb_av1_176_144.av1", ""},
- {"bbb_av1_640_360.info", "bbb_av1_176_144.info", ""},
- {"bbb_av1_640_360_chksum.md5", "bbb_av1_176_144_chksm.md5", ""}},
- };
-
- for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
- if (kCompToURL[i].comp == comp) {
- strcat(mURL, kCompToURL[i].mURL[streamIndex]);
- strcat(info, kCompToURL[i].info[streamIndex]);
- strcat(chksum, kCompToURL[i].chksum[streamIndex]);
- return;
+void Codec2VideoDecHidlTestBase::GetURLChksmForComponent(char* mURL, char* info, char* chksum,
+ size_t streamIndex) {
+ int streamCount = 0;
+ for (size_t i = 0; i < kCompToURL.size(); ++i) {
+ if (mMime.find(kCompToURL[i].mime) != std::string::npos) {
+ if (streamCount == streamIndex) {
+ strcat(mURL, kCompToURL[i].mURL.c_str());
+ strcat(info, kCompToURL[i].info.c_str());
+ strcat(chksum, kCompToURL[i].chksum.c_str());
+ return;
+ }
+ streamCount++;
}
}
}
-void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL, char* info,
- size_t streamIndex = 1) {
+void Codec2VideoDecHidlTestBase::GetURLForComponent(char* mURL, char* info, size_t streamIndex) {
char chksum[512];
strcpy(chksum, sResourceDir.c_str());
- GetURLChksmForComponent(comp, mURL, info, chksum, streamIndex);
+ GetURLChksmForComponent(mURL, info, chksum, streamIndex);
}
void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
@@ -517,7 +488,7 @@
TEST_P(Codec2VideoDecHidlTest, validateCompName) {
if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ALOGV("Checks if the given component is a valid video component");
- validateComponent(mComponent, mCompName, mDisableTest);
+ validateComponent(mComponent, mDisableTest);
ASSERT_EQ(mDisableTest, false);
}
@@ -599,7 +570,7 @@
strcpy(info, sResourceDir.c_str());
strcpy(chksum, sResourceDir.c_str());
- GetURLChksmForComponent(mCompName, mURL, info, chksum, streamIndex);
+ GetURLChksmForComponent(mURL, info, chksum, streamIndex);
if (!(strcmp(mURL, sResourceDir.c_str())) || !(strcmp(info, sResourceDir.c_str()))) {
ALOGV("Skipping Test, Stream not available");
return;
@@ -688,9 +659,11 @@
TEST_P(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
description("Adaptive Decode Test");
if (mDisableTest) GTEST_SKIP() << "Test is disabled";
- if (!(mCompName == avc || mCompName == hevc || mCompName == vp8 || mCompName == vp9 ||
- mCompName == mpeg2))
+ if (!(strcasestr(mMime.c_str(), "avc") || strcasestr(mMime.c_str(), "hevc") ||
+ strcasestr(mMime.c_str(), "vp8") || strcasestr(mMime.c_str(), "vp9") ||
+ strcasestr(mMime.c_str(), "mpeg2"))) {
return;
+ }
typedef std::unique_lock<std::mutex> ULock;
ASSERT_EQ(mComponent->start(), C2_OK);
@@ -705,7 +678,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info, i % STREAM_COUNT);
+ GetURLForComponent(mURL, info, i % STREAM_COUNT);
if (!(strcmp(mURL, sResourceDir.c_str())) || !(strcmp(info, sResourceDir.c_str()))) {
ALOGV("Stream not available, skipping this index");
continue;
@@ -801,7 +774,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
@@ -888,7 +861,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
mFlushedIndices.clear();
@@ -964,7 +937,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
eleInfo.open(info);
ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
@@ -1038,7 +1011,7 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
- GetURLForComponent(mCompName, mURL, info);
+ GetURLForComponent(mURL, info);
int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
ASSERT_GE(numCsds, 0) << "Error in parsing input info file";
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index 5bcea5b..739c1af 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -110,7 +110,8 @@
C2SecureModeTuning secureModeTuning{};
mComponent->query({&secureModeTuning}, {}, C2_MAY_BLOCK, nullptr);
- if (secureModeTuning.value == C2Config::SM_READ_PROTECTED) {
+ if (secureModeTuning.value == C2Config::SM_READ_PROTECTED ||
+ secureModeTuning.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED) {
mDisableTest = true;
}
diff --git a/media/codec2/hidl/1.1/utils/Android.bp b/media/codec2/hidl/1.1/utils/Android.bp
index 71a113d..0eeedb6 100644
--- a/media/codec2/hidl/1.1/utils/Android.bp
+++ b/media/codec2/hidl/1.1/utils/Android.bp
@@ -15,7 +15,6 @@
defaults: ["hidl_defaults"],
srcs: [
- "OutputBufferQueue.cpp",
"types.cpp",
],
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h
deleted file mode 100644
index f77852d..0000000
--- a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
-#define CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
-
-#include <codec2/hidl/1.0/OutputBufferQueue.h>
-#include <codec2/hidl/1.1/types.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_1 {
-namespace utils {
-
-using ::android::hardware::media::c2::V1_0::utils::OutputBufferQueue;
-
-} // namespace utils
-} // namespace V1_1
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
diff --git a/media/codec2/hidl/1.2/utils/Android.bp b/media/codec2/hidl/1.2/utils/Android.bp
index 0a8d256..e4e4ad5 100644
--- a/media/codec2/hidl/1.2/utils/Android.bp
+++ b/media/codec2/hidl/1.2/utils/Android.bp
@@ -15,7 +15,6 @@
defaults: ["hidl_defaults"],
srcs: [
- "OutputBufferQueue.cpp",
"types.cpp",
],
diff --git a/media/codec2/hidl/1.2/utils/Component.cpp b/media/codec2/hidl/1.2/utils/Component.cpp
index 1de33b4..8924e6d 100644
--- a/media/codec2/hidl/1.2/utils/Component.cpp
+++ b/media/codec2/hidl/1.2/utils/Component.cpp
@@ -480,9 +480,31 @@
Return<Status> Component::setOutputSurfaceWithSyncObj(
uint64_t blockPoolId, const sp<HGraphicBufferProducer2>& surface,
const SurfaceSyncObj& syncObject) {
- (void) blockPoolId;
- (void) surface;
- (void) syncObject;
+ std::shared_ptr<C2BlockPool> pool;
+ GetCodec2BlockPool(blockPoolId, mComponent, &pool);
+ if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
+ C2BufferQueueBlockPool::OnRenderCallback cb =
+ [this](uint64_t producer, int32_t slot, int64_t nsecs) {
+ // TODO: batch this
+ hidl_vec<IComponentListener::RenderedFrame> rendered;
+ rendered.resize(1);
+ rendered[0] = { producer, slot, nsecs };
+ (void)mListener->onFramesRendered(rendered).isOk();
+ };
+ if (bqPool) {
+ const native_handle_t *h = syncObject.syncMemory;
+ native_handle_t *syncMemory = h ? native_handle_clone(h) : nullptr;
+ uint64_t bqId = syncObject.bqId;
+ uint32_t generationId = syncObject.generationId;
+ uint64_t consumerUsage = syncObject.consumerUsage;
+
+ bqPool->setRenderCallback(cb);
+ bqPool->configureProducer(surface, syncMemory, bqId,
+ generationId, consumerUsage);
+ }
+ }
return Status::OK;
}
diff --git a/media/codec2/hidl/1.2/utils/OutputBufferQueue.cpp b/media/codec2/hidl/1.2/utils/OutputBufferQueue.cpp
deleted file mode 100644
index 12b5f5b..0000000
--- a/media/codec2/hidl/1.2/utils/OutputBufferQueue.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <codec2/hidl/1.2/OutputBufferQueue.h>
diff --git a/media/codec2/hidl/1.2/utils/include/codec2/hidl/1.2/OutputBufferQueue.h b/media/codec2/hidl/1.2/utils/include/codec2/hidl/1.2/OutputBufferQueue.h
deleted file mode 100644
index 9fd5f07..0000000
--- a/media/codec2/hidl/1.2/utils/include/codec2/hidl/1.2/OutputBufferQueue.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CODEC2_HIDL_V1_2_UTILS_OUTPUT_BUFFER_QUEUE
-#define CODEC2_HIDL_V1_2_UTILS_OUTPUT_BUFFER_QUEUE
-
-#include <codec2/hidl/1.0/OutputBufferQueue.h>
-#include <codec2/hidl/1.2/types.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_2 {
-namespace utils {
-
-using ::android::hardware::media::c2::V1_0::utils::OutputBufferQueue;
-
-} // namespace utils
-} // namespace V1_2
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // CODEC2_HIDL_V1_2_UTILS_OUTPUT_BUFFER_QUEUE
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index b3ca5b1..0e52813 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -12,6 +12,11 @@
srcs: [
"client.cpp",
+ "output.cpp",
+ ],
+
+ header_libs: [
+ "libcodec2_internal", // private
],
shared_libs: [
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 0a61fe2..0296004 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -33,17 +33,17 @@
#include <android-base/properties.h>
#include <bufferpool/ClientManager.h>
-#include <codec2/hidl/1.0/OutputBufferQueue.h>
#include <codec2/hidl/1.0/types.h>
-#include <codec2/hidl/1.1/OutputBufferQueue.h>
#include <codec2/hidl/1.1/types.h>
#include <codec2/hidl/1.2/types.h>
+#include <codec2/hidl/output.h>
#include <cutils/native_handle.h>
#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
#include <hidl/HidlSupport.h>
+
#include <deque>
#include <iterator>
#include <limits>
@@ -74,6 +74,7 @@
V2_0::utils::B2HGraphicBufferProducer;
using H2BGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
V2_0::utils::H2BGraphicBufferProducer;
+using ::android::hardware::media::c2::V1_2::SurfaceSyncObj;
namespace /* unnamed */ {
@@ -593,9 +594,9 @@
// Codec2Client::Component::OutputBufferQueue
struct Codec2Client::Component::OutputBufferQueue :
- hardware::media::c2::V1_1::utils::OutputBufferQueue {
+ hardware::media::c2::OutputBufferQueue {
OutputBufferQueue()
- : hardware::media::c2::V1_1::utils::OutputBufferQueue() {
+ : hardware::media::c2::OutputBufferQueue() {
}
};
@@ -1492,22 +1493,29 @@
igbp = new B2HGraphicBufferProducer2(surface);
}
+ std::shared_ptr<SurfaceSyncObj> syncObj;
+
if (!surface) {
- mOutputBufferQueue->configure(nullIgbp, generation, 0);
+ mOutputBufferQueue->configure(nullIgbp, generation, 0, nullptr);
} else if (surface->getUniqueId(&bqId) != OK) {
LOG(ERROR) << "setOutputSurface -- "
"cannot obtain bufferqueue id.";
bqId = 0;
- mOutputBufferQueue->configure(nullIgbp, generation, 0);
+ mOutputBufferQueue->configure(nullIgbp, generation, 0, nullptr);
} else {
- mOutputBufferQueue->configure(surface, generation, bqId);
+ mOutputBufferQueue->configure(surface, generation, bqId,
+ mBase1_2 ? &syncObj : nullptr);
}
- ALOGD("generation remote change %u", generation);
+ ALOGD("surface generation remote change %u HAL ver: %s",
+ generation, syncObj ? "1.2" : "1.0");
- (void)mBase1_2;
- Return<Status> transStatus = mBase1_0->setOutputSurface(
- static_cast<uint64_t>(blockPoolId),
- bqId == 0 ? nullHgbp : igbp);
+ Return<Status> transStatus = syncObj ?
+ mBase1_2->setOutputSurfaceWithSyncObj(
+ static_cast<uint64_t>(blockPoolId),
+ bqId == 0 ? nullHgbp : igbp, *syncObj) :
+ mBase1_0->setOutputSurface(
+ static_cast<uint64_t>(blockPoolId),
+ bqId == 0 ? nullHgbp : igbp);
if (!transStatus.isOk()) {
LOG(ERROR) << "setOutputSurface -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1517,6 +1525,7 @@
if (status != C2_OK) {
LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
}
+ ALOGD("Surface configure completed");
return status;
}
@@ -1527,6 +1536,11 @@
return mOutputBufferQueue->outputBuffer(block, input, output);
}
+void Codec2Client::Component::setOutputSurfaceMaxDequeueCount(
+ int maxDequeueCount) {
+ mOutputBufferQueue->updateMaxDequeueBufferCount(maxDequeueCount);
+}
+
c2_status_t Codec2Client::Component::connectToInputSurface(
const std::shared_ptr<InputSurface>& inputSurface,
std::shared_ptr<InputSurfaceConnection>* connection) {
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index b574829..eca268e 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -407,6 +407,9 @@
const QueueBufferInput& input,
QueueBufferOutput* output);
+ // Set max dequeue count for output surface.
+ void setOutputSurfaceMaxDequeueCount(int maxDequeueCount);
+
// Connect to a given InputSurface.
c2_status_t connectToInputSurface(
const std::shared_ptr<InputSurface>& inputSurface,
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h b/media/codec2/hidl/client/include/codec2/hidl/output.h
similarity index 83%
rename from media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h
rename to media/codec2/hidl/client/include/codec2/hidl/output.h
index 80368f7..0f03b36 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/output.h
@@ -19,16 +19,17 @@
#include <gui/IGraphicBufferProducer.h>
#include <codec2/hidl/1.0/types.h>
+#include <codec2/hidl/1.2/types.h>
#include <C2Work.h>
struct C2_HIDE _C2BlockPoolData;
+class C2SurfaceSyncMemory;
namespace android {
namespace hardware {
namespace media {
namespace c2 {
-namespace V1_0 {
-namespace utils {
+
// BufferQueue-Based Block Operations
// ==================================
@@ -45,7 +46,8 @@
// Graphic blocks from older surface will be migrated to new surface.
bool configure(const sp<IGraphicBufferProducer>& igbp,
uint32_t generation,
- uint64_t bqId);
+ uint64_t bqId,
+ std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj);
// Render a graphic block to current surface.
status_t outputBuffer(
@@ -61,22 +63,27 @@
void holdBufferQueueBlocks(
const std::list<std::unique_ptr<C2Work>>& workList);
+ // Update # of max dequeue buffer from BQ. If # of max dequeued buffer is shared
+ // via shared memory between HAL and framework, Update # of max dequeued buffer
+ // and synchronize.
+ void updateMaxDequeueBufferCount(int maxDequeueBufferCount);
+
private:
std::mutex mMutex;
sp<IGraphicBufferProducer> mIgbp;
uint32_t mGeneration;
uint64_t mBqId;
+ int32_t mMaxDequeueBufferCount;
std::shared_ptr<int> mOwner;
// To migrate existing buffers
sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
bool registerBuffer(const C2ConstGraphicBlock& block);
};
-} // namespace utils
-} // namespace V1_0
} // namespace c2
} // namespace media
} // namespace hardware
diff --git a/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp b/media/codec2/hidl/client/output.cpp
similarity index 71%
rename from media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
rename to media/codec2/hidl/client/output.cpp
index 2b235f2..7df0da2 100644
--- a/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
+++ b/media/codec2/hidl/client/output.cpp
@@ -19,13 +19,16 @@
#include <android-base/logging.h>
#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/OutputBufferQueue.h>
+#include <codec2/hidl/output.h>
+#include <cutils/ashmem.h>
#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <sys/mman.h>
#include <C2AllocatorGralloc.h>
#include <C2BlockInternal.h>
#include <C2Buffer.h>
#include <C2PlatformSupport.h>
+#include <C2SurfaceSyncObj.h>
#include <iomanip>
@@ -33,8 +36,6 @@
namespace hardware {
namespace media {
namespace c2 {
-namespace V1_0 {
-namespace utils {
using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
V2_0::IGraphicBufferProducer;
@@ -105,7 +106,8 @@
status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
const sp<IGraphicBufferProducer>& igbp,
uint32_t generation,
- int32_t* bqSlot) {
+ int32_t* bqSlot,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem) {
if (!igbp) {
LOG(WARNING) << "attachToBufferQueue -- null producer.";
return NO_INIT;
@@ -126,7 +128,25 @@
<< ", stride " << graphicBuffer->getStride()
<< ", generation " << graphicBuffer->getGenerationNumber();
- status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
+ C2SyncVariables *syncVar = syncMem ? syncMem->mem() : nullptr;
+ status_t result = OK;
+ if (syncVar) {
+ syncVar->lock();
+ if (!syncVar->isDequeueableLocked() ||
+ syncVar->getSyncStatusLocked() == C2SyncVariables::STATUS_SWITCHING) {
+ syncVar->unlock();
+ LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+ "status = " << INVALID_OPERATION << ".";
+ return INVALID_OPERATION;
+ }
+ result = igbp->attachBuffer(bqSlot, graphicBuffer);
+ if (result == OK) {
+ syncVar->notifyDequeuedLocked();
+ }
+ syncVar->unlock();
+ } else {
+ result = igbp->attachBuffer(bqSlot, graphicBuffer);
+ }
if (result != OK) {
LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
"status = " << result << ".";
@@ -157,12 +177,40 @@
bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
uint32_t generation,
- uint64_t bqId) {
+ uint64_t bqId,
+ std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj) {
uint64_t consumerUsage = 0;
if (igbp->getConsumerUsage(&consumerUsage) != OK) {
ALOGW("failed to get consumer usage");
}
+ // TODO : Abstract creation process into C2SurfaceSyncMemory class.
+ // use C2LinearBlock instead ashmem.
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem;
+ if (syncObj && igbp) {
+ bool mapped = false;
+ int memFd = ashmem_create_region("C2SurfaceMem", sizeof(C2SyncVariables));
+ size_t memSize = memFd < 0 ? 0 : ashmem_get_size_region(memFd);
+ if (memSize > 0) {
+ syncMem = C2SurfaceSyncMemory::Create(memFd, memSize);
+ if (syncMem) {
+ mapped = true;
+ *syncObj = std::make_shared<V1_2::SurfaceSyncObj>();
+ (*syncObj)->syncMemory = syncMem->handle();
+ (*syncObj)->bqId = bqId;
+ (*syncObj)->generationId = generation;
+ (*syncObj)->consumerUsage = consumerUsage;
+ ALOGD("C2SurfaceSyncMemory created %zu(%zu)", sizeof(C2SyncVariables), memSize);
+ }
+ }
+ if (!mapped) {
+ if (memFd >= 0) {
+ ::close(memFd);
+ }
+ ALOGW("SurfaceSyncObj creation failure");
+ }
+ }
+
size_t tryNum = 0;
size_t success = 0;
sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
@@ -173,6 +221,19 @@
if (generation == mGeneration) {
return false;
}
+ std::shared_ptr<C2SurfaceSyncMemory> oldMem = mSyncMem;
+ C2SyncVariables *oldSync = mSyncMem ? mSyncMem->mem() : nullptr;
+ if (oldSync) {
+ oldSync->lock();
+ oldSync->setSyncStatusLocked(C2SyncVariables::STATUS_SWITCHING);
+ oldSync->unlock();
+ }
+ mSyncMem.reset();
+ if (syncMem) {
+ mSyncMem = syncMem;
+ }
+ C2SyncVariables *newSync = mSyncMem ? mSyncMem->mem() : nullptr;
+
mIgbp = igbp;
mGeneration = generation;
mBqId = bqId;
@@ -212,7 +273,7 @@
}
bool attach =
_C2BlockFactory::EndAttachBlockToBufferQueue(
- data, mOwner, getHgbp(mIgbp),
+ data, mOwner, getHgbp(mIgbp), mSyncMem,
generation, bqId, bqSlot);
if (!attach) {
igbp->cancelBuffer(bqSlot, Fence::NO_FENCE);
@@ -226,8 +287,12 @@
mBuffers[i] = buffers[i];
mPoolDatas[i] = poolDatas[i];
}
+ if (newSync) {
+ newSync->setInitialDequeueCount(mMaxDequeueBufferCount, success);
+ }
}
- ALOGD("remote graphic buffer migration %zu/%zu", success, tryNum);
+ ALOGD("remote graphic buffer migration %zu/%zu",
+ success, tryNum);
return true;
}
@@ -258,7 +323,7 @@
<< ", bqSlot " << oldSlot
<< ", generation " << mGeneration
<< ".";
- _C2BlockFactory::HoldBlockFromBufferQueue(data, mOwner, getHgbp(mIgbp));
+ _C2BlockFactory::HoldBlockFromBufferQueue(data, mOwner, getHgbp(mIgbp), mSyncMem);
mPoolDatas[oldSlot] = data;
mBuffers[oldSlot] = createGraphicBuffer(block);
mBuffers[oldSlot]->setGenerationNumber(mGeneration);
@@ -278,25 +343,39 @@
uint32_t generation;
uint64_t bqId;
int32_t bqSlot;
- bool display = displayBufferQueueBlock(block);
+ bool display = V1_0::utils::displayBufferQueueBlock(block);
if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
bqId == 0) {
// Block not from bufferqueue -- it must be attached before queuing.
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem;
mMutex.lock();
sp<IGraphicBufferProducer> outputIgbp = mIgbp;
uint32_t outputGeneration = mGeneration;
+ syncMem = mSyncMem;
mMutex.unlock();
status_t status = attachToBufferQueue(
- block, outputIgbp, outputGeneration, &bqSlot);
+ block, outputIgbp, outputGeneration, &bqSlot, syncMem);
+
if (status != OK) {
LOG(WARNING) << "outputBuffer -- attaching failed.";
return INVALID_OPERATION;
}
- status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
- input, output);
+ auto syncVar = syncMem ? syncMem->mem() : nullptr;
+ if(syncVar) {
+ syncVar->lock();
+ status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+ input, output);
+ if (status == OK) {
+ syncVar->notifyQueuedLocked();
+ }
+ syncVar->unlock();
+ } else {
+ status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+ input, output);
+ }
if (status != OK) {
LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
"on non-bufferqueue-based block. "
@@ -306,10 +385,12 @@
return OK;
}
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem;
mMutex.lock();
sp<IGraphicBufferProducer> outputIgbp = mIgbp;
uint32_t outputGeneration = mGeneration;
uint64_t outputBqId = mBqId;
+ syncMem = mSyncMem;
mMutex.unlock();
if (!outputIgbp) {
@@ -330,8 +411,21 @@
return DEAD_OBJECT;
}
- status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
- input, output);
+ auto syncVar = syncMem ? syncMem->mem() : nullptr;
+ status_t status = OK;
+ if (syncVar) {
+ syncVar->lock();
+ status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+ input, output);
+ if (status == OK) {
+ syncVar->notifyQueuedLocked();
+ }
+ syncVar->unlock();
+ } else {
+ status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+ input, output);
+ }
+
if (status != OK) {
LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
"on bufferqueue-based block. "
@@ -348,8 +442,18 @@
this, std::placeholders::_1));
}
-} // namespace utils
-} // namespace V1_0
+void OutputBufferQueue::updateMaxDequeueBufferCount(int maxDequeueBufferCount) {
+ mMutex.lock();
+ mMaxDequeueBufferCount = maxDequeueBufferCount;
+ auto syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
+ if (syncVar) {
+ syncVar->lock();
+ syncVar->updateMaxDequeueCountLocked(maxDequeueBufferCount);
+ syncVar->unlock();
+ }
+ mMutex.unlock();
+}
+
} // namespace c2
} // namespace media
} // namespace hardware
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 02f7cb8..4ae4c8e 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -2311,7 +2311,13 @@
return;
}
- ALOGW("previous call to %s exceeded timeout", name.c_str());
+ C2String compName;
+ {
+ Mutexed<State>::Locked state(mState);
+ compName = state->comp->getName();
+ }
+ ALOGW("[%s] previous call to %s exceeded timeout", compName.c_str(), name.c_str());
+
initiateRelease(false);
mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 3f717c9..c4f9d84 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1177,9 +1177,10 @@
if (outputFormat != nullptr) {
sp<IGraphicBufferProducer> outputSurface;
uint32_t outputGeneration;
+ int maxDequeueCount = 0;
{
Mutexed<OutputSurface>::Locked output(mOutputSurface);
- output->maxDequeueBuffers = numOutputSlots +
+ maxDequeueCount = output->maxDequeueBuffers = numOutputSlots +
reorderDepth.value + kRenderingDepth;
outputSurface = output->surface ?
output->surface->getIGraphicBufferProducer() : nullptr;
@@ -1188,6 +1189,9 @@
}
outputGeneration = output->generation;
}
+ if (maxDequeueCount > 0) {
+ mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
+ }
bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
C2BlockPool::local_id_t outputPoolId_;
@@ -1766,15 +1770,22 @@
if (needMaxDequeueBufferCountUpdate) {
size_t numOutputSlots = 0;
uint32_t reorderDepth = 0;
+ int maxDequeueCount = 0;
{
Mutexed<Output>::Locked output(mOutput);
numOutputSlots = output->numSlots;
reorderDepth = output->buffers->getReorderDepth();
}
- Mutexed<OutputSurface>::Locked output(mOutputSurface);
- output->maxDequeueBuffers = numOutputSlots + reorderDepth + kRenderingDepth;
- if (output->surface) {
- output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
+ {
+ Mutexed<OutputSurface>::Locked output(mOutputSurface);
+ maxDequeueCount = output->maxDequeueBuffers =
+ numOutputSlots + reorderDepth + kRenderingDepth;
+ if (output->surface) {
+ output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
+ }
+ }
+ if (maxDequeueCount > 0) {
+ mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
}
}
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index bf2a07e..a54af83 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -121,34 +121,46 @@
if (view.crop().width != img->mWidth || view.crop().height != img->mHeight) {
return BAD_VALUE;
}
+ const uint8_t* src_y = view.data()[0];
+ const uint8_t* src_u = view.data()[1];
+ const uint8_t* src_v = view.data()[2];
+ int32_t src_stride_y = view.layout().planes[0].rowInc;
+ int32_t src_stride_u = view.layout().planes[1].rowInc;
+ int32_t src_stride_v = view.layout().planes[2].rowInc;
+ uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
+ uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
+ uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
+ int32_t dst_stride_y = img->mPlane[0].mRowInc;
+ int32_t dst_stride_u = img->mPlane[1].mRowInc;
+ int32_t dst_stride_v = img->mPlane[2].mRowInc;
+ int width = view.crop().width;
+ int height = view.crop().height;
+
if ((IsNV12(view) && IsI420(img)) || (IsI420(view) && IsNV12(img))) {
// Take shortcuts to use libyuv functions between NV12 and I420 conversion.
- const uint8_t* src_y = view.data()[0];
- const uint8_t* src_u = view.data()[1];
- const uint8_t* src_v = view.data()[2];
- int32_t src_stride_y = view.layout().planes[0].rowInc;
- int32_t src_stride_u = view.layout().planes[1].rowInc;
- int32_t src_stride_v = view.layout().planes[2].rowInc;
- uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
- uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
- uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
- int32_t dst_stride_y = img->mPlane[0].mRowInc;
- int32_t dst_stride_u = img->mPlane[1].mRowInc;
- int32_t dst_stride_v = img->mPlane[2].mRowInc;
if (IsNV12(view) && IsI420(img)) {
if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
- dst_u, dst_stride_u, dst_v, dst_stride_v, view.crop().width,
- view.crop().height)) {
+ dst_u, dst_stride_u, dst_v, dst_stride_v, width, height)) {
return OK;
}
} else {
if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
- dst_y, dst_stride_y, dst_u, dst_stride_u, view.crop().width,
- view.crop().height)) {
+ dst_y, dst_stride_y, dst_u, dst_stride_u, width, height)) {
return OK;
}
}
}
+ if (IsNV12(view) && IsNV12(img)) {
+ libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
+ libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height / 2);
+ return OK;
+ }
+ if (IsI420(view) && IsI420(img)) {
+ libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
+ libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width / 2, height / 2);
+ libyuv::CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width / 2, height / 2);
+ return OK;
+ }
return _ImageCopy<true>(view, img, imgBase);
}
@@ -156,34 +168,47 @@
if (view.crop().width != img->mWidth || view.crop().height != img->mHeight) {
return BAD_VALUE;
}
+ const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
+ const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
+ const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
+ int32_t src_stride_y = img->mPlane[0].mRowInc;
+ int32_t src_stride_u = img->mPlane[1].mRowInc;
+ int32_t src_stride_v = img->mPlane[2].mRowInc;
+ uint8_t* dst_y = view.data()[0];
+ uint8_t* dst_u = view.data()[1];
+ uint8_t* dst_v = view.data()[2];
+ int32_t dst_stride_y = view.layout().planes[0].rowInc;
+ int32_t dst_stride_u = view.layout().planes[1].rowInc;
+ int32_t dst_stride_v = view.layout().planes[2].rowInc;
+ int width = view.crop().width;
+ int height = view.crop().height;
if ((IsNV12(img) && IsI420(view)) || (IsI420(img) && IsNV12(view))) {
// Take shortcuts to use libyuv functions between NV12 and I420 conversion.
- const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
- const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
- const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
- int32_t src_stride_y = img->mPlane[0].mRowInc;
- int32_t src_stride_u = img->mPlane[1].mRowInc;
- int32_t src_stride_v = img->mPlane[2].mRowInc;
- uint8_t* dst_y = view.data()[0];
- uint8_t* dst_u = view.data()[1];
- uint8_t* dst_v = view.data()[2];
- int32_t dst_stride_y = view.layout().planes[0].rowInc;
- int32_t dst_stride_u = view.layout().planes[1].rowInc;
- int32_t dst_stride_v = view.layout().planes[2].rowInc;
if (IsNV12(img) && IsI420(view)) {
if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
- dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
- view.height())) {
+ dst_u, dst_stride_u, dst_v, dst_stride_v, width, height)) {
return OK;
}
} else {
if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
- dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
- view.height())) {
+ dst_y, dst_stride_y, dst_u, dst_stride_u, width, height)) {
return OK;
}
}
}
+ if (IsNV12(img) && IsNV12(view)) {
+ // For NV12, copy Y and UV plane
+ libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
+ libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height / 2);
+ return OK;
+ }
+ if (IsI420(img) && IsI420(view)) {
+ // For I420, copy Y, U and V plane.
+ libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
+ libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width / 2, height / 2);
+ libyuv::CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width / 2, height / 2);
+ return OK;
+ }
return _ImageCopy<false>(view, img, imgBase);
}
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 0401c1d..be81c84 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -36,9 +36,11 @@
"C2Buffer.cpp",
"C2Config.cpp",
"C2DmaBufAllocator.cpp",
+ "C2Fence.cpp",
"C2PlatformStorePluginLoader.cpp",
"C2Store.cpp",
"platform/C2BqBuffer.cpp",
+ "platform/C2SurfaceSyncObj.cpp",
"types.cpp",
"util/C2Debug.cpp",
"util/C2InterfaceHelper.cpp",
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 12f4027..85623b8 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -30,15 +30,10 @@
#include <C2ErrnoUtils.h>
#include <C2HandleIonInternal.h>
-#include <android-base/properties.h>
-
namespace android {
namespace {
constexpr size_t USAGE_LRU_CACHE_SIZE = 1024;
-
- // max padding after ion/dmabuf allocations in bytes
- constexpr uint32_t MAX_PADDING = 0x8000; // 32KB
}
/* size_t <=> int(lo), int(hi) conversions */
@@ -381,34 +376,14 @@
unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
int bufferFd = -1;
ion_user_handle_t buffer = -1;
- // NOTE: read this property directly from the property as this code has to run on
- // Android Q, but the sysprop was only introduced in Android S.
- static size_t sPadding =
- base::GetUintProperty("media.c2.dmabuf.padding", (uint32_t)0, MAX_PADDING);
- if (sPadding > SIZE_MAX - size) {
- ALOGD("ion_alloc: size %#zx cannot accommodate padding %#zx", size, sPadding);
- // use ImplV2 as there is no allocation anyways
- return new ImplV2(ionFd, size, -1, id, -ENOMEM);
- }
-
- size_t allocSize = size + sPadding;
- if (align) {
- if (align - 1 > SIZE_MAX - allocSize) {
- ALOGD("ion_alloc: size %#zx cannot accommodate padding %#zx and alignment %#zx",
- size, sPadding, align);
- // use ImplV2 as there is no allocation anyways
- return new ImplV2(ionFd, size, -1, id, -ENOMEM);
- }
- allocSize += align - 1;
- allocSize &= ~(align - 1);
- }
+ size_t alignedSize = align == 0 ? size : (size + align - 1) & ~(align - 1);
int ret;
if (ion_is_legacy(ionFd)) {
- ret = ion_alloc(ionFd, allocSize, align, heapMask, flags, &buffer);
+ ret = ion_alloc(ionFd, alignedSize, align, heapMask, flags, &buffer);
ALOGV("ion_alloc(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
"returned (%d) ; buffer = %d",
- ionFd, allocSize, align, heapMask, flags, ret, buffer);
+ ionFd, alignedSize, align, heapMask, flags, ret, buffer);
if (ret == 0) {
// get buffer fd for native handle constructor
ret = ion_share(ionFd, buffer, &bufferFd);
@@ -417,15 +392,15 @@
buffer = -1;
}
}
- return new Impl(ionFd, size, bufferFd, buffer, id, ret);
+ return new Impl(ionFd, alignedSize, bufferFd, buffer, id, ret);
} else {
- ret = ion_alloc_fd(ionFd, allocSize, align, heapMask, flags, &bufferFd);
+ ret = ion_alloc_fd(ionFd, alignedSize, align, heapMask, flags, &bufferFd);
ALOGV("ion_alloc_fd(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
"returned (%d) ; bufferFd = %d",
- ionFd, allocSize, align, heapMask, flags, ret, bufferFd);
+ ionFd, alignedSize, align, heapMask, flags, ret, bufferFd);
- return new ImplV2(ionFd, size, bufferFd, id, ret);
+ return new ImplV2(ionFd, alignedSize, bufferFd, id, ret);
}
}
diff --git a/media/codec2/vndk/C2DmaBufAllocator.cpp b/media/codec2/vndk/C2DmaBufAllocator.cpp
index 7c8999b..750aa31 100644
--- a/media/codec2/vndk/C2DmaBufAllocator.cpp
+++ b/media/codec2/vndk/C2DmaBufAllocator.cpp
@@ -16,13 +16,11 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2DmaBufAllocator"
-
#include <BufferAllocator/BufferAllocator.h>
#include <C2Buffer.h>
#include <C2Debug.h>
#include <C2DmaBufAllocator.h>
#include <C2ErrnoUtils.h>
-
#include <linux/ion.h>
#include <sys/mman.h>
#include <unistd.h> // getpagesize, size_t, close, dup
@@ -30,15 +28,14 @@
#include <list>
+#ifdef __ANDROID_APEX__
#include <android-base/properties.h>
+#endif
namespace android {
namespace {
- constexpr size_t USAGE_LRU_CACHE_SIZE = 1024;
-
- // max padding after ion/dmabuf allocations in bytes
- constexpr uint32_t MAX_PADDING = 0x8000; // 32KB
+constexpr size_t USAGE_LRU_CACHE_SIZE = 1024;
}
/* =========================== BUFFER HANDLE =========================== */
@@ -252,23 +249,9 @@
int bufferFd = -1;
int ret = 0;
- // NOTE: read this property directly from the property as this code has to run on
- // Android Q, but the sysprop was only introduced in Android S.
- static size_t sPadding =
- base::GetUintProperty("media.c2.dmabuf.padding", (uint32_t)0, MAX_PADDING);
- if (sPadding > SIZE_MAX - size) {
- // size would overflow
- ALOGD("dmabuf_alloc: size #%zx cannot accommodate padding #%zx", size, sPadding);
- ret = -ENOMEM;
- } else {
- size_t allocSize = size + sPadding;
- bufferFd = alloc.Alloc(heap_name, allocSize, flags);
- if (bufferFd < 0) {
- ret = bufferFd;
- }
- }
+ bufferFd = alloc.Alloc(heap_name, size, flags);
+ if (bufferFd < 0) ret = bufferFd;
- // this may be a non-working handle if bufferFd is negative
mHandle = C2HandleBuf(bufferFd, size);
mId = id;
mInit = c2_status_t(c2_map_errno<ENOMEM, EACCES, EINVAL>(ret));
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
new file mode 100644
index 0000000..9c5183e
--- /dev/null
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2FenceFactory"
+#include <utils/Log.h>
+
+#include <C2FenceFactory.h>
+#include <C2SurfaceSyncObj.h>
+
+class C2Fence::Impl {
+public:
+ virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0;
+
+ virtual bool valid() const = 0;
+
+ virtual bool ready() const = 0;
+
+ virtual int fd() const = 0;
+
+ virtual bool isHW() const = 0;
+
+ virtual ~Impl() = default;
+
+ Impl() = default;
+};
+
+c2_status_t C2Fence::wait(c2_nsecs_t timeoutNs) {
+ if (mImpl) {
+ return mImpl->wait(timeoutNs);
+ }
+ // null fence is always signalled.
+ return C2_OK;
+}
+
+bool C2Fence::valid() const {
+ if (mImpl) {
+ return mImpl->valid();
+ }
+ // null fence is always valid.
+ return true;
+}
+
+bool C2Fence::ready() const {
+ if (mImpl) {
+ return mImpl->ready();
+ }
+ // null fence is always signalled.
+ return true;
+}
+
+int C2Fence::fd() const {
+ if (mImpl) {
+ return mImpl->fd();
+ }
+ // null fence does not have fd.
+ return -1;
+}
+
+bool C2Fence::isHW() const {
+ if (mImpl) {
+ return mImpl->isHW();
+ }
+ return false;
+}
+
+/**
+ * Fence implementation for C2BufferQueueBlockPool based block allocation.
+ * The implementation supports all C2Fence interface except fd().
+ */
+class _C2FenceFactory::SurfaceFenceImpl: public C2Fence::Impl {
+public:
+ virtual c2_status_t wait(c2_nsecs_t timeoutNs) {
+ if (mPtr) {
+ return mPtr->waitForChange(mWaitId, timeoutNs);
+ }
+ return C2_OK;
+ }
+
+ virtual bool valid() const {
+ return mPtr;
+ }
+
+ virtual bool ready() const {
+ uint32_t status;
+ if (mPtr) {
+ mPtr->lock();
+ status = mPtr->getWaitIdLocked();
+ mPtr->unlock();
+
+ return status != mWaitId;
+ }
+ return true;
+ }
+
+ virtual int fd() const {
+ // does not support fd, since this is shared mem and futex based
+ return -1;
+ }
+
+ virtual bool isHW() const {
+ return false;
+ }
+
+ virtual ~SurfaceFenceImpl() {};
+
+ SurfaceFenceImpl(std::shared_ptr<C2SurfaceSyncMemory> syncMem, uint32_t waitId) :
+ mSyncMem(syncMem),
+ mPtr(syncMem ? syncMem->mem() : nullptr),
+ mWaitId(syncMem ? waitId : 0) {}
+private:
+ const std::shared_ptr<const C2SurfaceSyncMemory> mSyncMem; // This is for life-cycle guarantee
+ C2SyncVariables *const mPtr;
+ const uint32_t mWaitId;
+};
+
+C2Fence::C2Fence(std::shared_ptr<Impl> impl) : mImpl(impl) {}
+
+C2Fence _C2FenceFactory::CreateSurfaceFence(
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem,
+ uint32_t waitId) {
+ if (syncMem) {
+ C2Fence::Impl *p
+ = new _C2FenceFactory::SurfaceFenceImpl(syncMem, waitId);
+ if (p->valid()) {
+ return C2Fence(std::shared_ptr<C2Fence::Impl>(p));
+ } else {
+ delete p;
+ }
+ }
+ return C2Fence();
+}
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index 066f1e1..b2636e9 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -49,6 +49,14 @@
C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block /* nonnull */) override;
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
+ C2Fence *fence /* nonnull */) override;
+
typedef std::function<void(uint64_t producer, int32_t slot, int64_t nsecs)> OnRenderCallback;
/**
@@ -72,6 +80,27 @@
*/
virtual void configureProducer(const android::sp<HGraphicBufferProducer> &producer);
+ /**
+ * Configures an IGBP in order to create blocks. A newly created block is
+ * dequeued from the configured IGBP. Unique Id of IGBP and the slot number of
+ * blocks are passed via native_handle. Managing IGBP is responsibility of caller.
+ * When IGBP is not configured, block will be created via allocator.
+ * Since zero is not used for Unique Id of IGBP, if IGBP is not configured or producer
+ * is configured as nullptr, unique id which is bundled in native_handle is zero.
+ *
+ * \param producer the IGBP, which will be used to fetch blocks
+ * \param syncMemory Shared memory for synchronization of allocation & deallocation.
+ * \param bqId Id of IGBP
+ * \param generationId Generation Id for rendering output
+ * \param consumerUsage consumerUsage flagof the IGBP
+ */
+ virtual void configureProducer(
+ const android::sp<HGraphicBufferProducer> &producer,
+ native_handle_t *syncMemory,
+ uint64_t bqId,
+ uint32_t generationId,
+ uint64_t consumerUsage);
+
private:
const std::shared_ptr<C2Allocator> mAllocator;
const local_id_t mLocalId;
@@ -82,6 +111,7 @@
friend struct C2BufferQueueBlockPoolData;
};
+class C2SurfaceSyncMemory;
struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
public:
@@ -97,7 +127,8 @@
// Create a local BlockPoolData.
C2BufferQueueBlockPoolData(
uint32_t generation, uint64_t bqId, int32_t bqSlot,
- const android::sp<HGraphicBufferProducer>& producer);
+ const android::sp<HGraphicBufferProducer>& producer,
+ std::shared_ptr<C2SurfaceSyncMemory>, int noUse);
virtual ~C2BufferQueueBlockPoolData() override;
@@ -105,7 +136,8 @@
int migrate(const android::sp<HGraphicBufferProducer>& producer,
uint32_t toGeneration, uint64_t toUsage, uint64_t toBqId,
- android::sp<android::GraphicBuffer>& graphicBuffer, uint32_t oldGeneration);
+ android::sp<android::GraphicBuffer>& graphicBuffer, uint32_t oldGeneration,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem);
private:
friend struct _C2BlockFactory;
@@ -113,12 +145,14 @@
// Methods delegated from _C2BlockFactory.
void getBufferQueueData(uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) const;
bool holdBlockFromBufferQueue(const std::shared_ptr<int>& owner,
- const android::sp<HGraphicBufferProducer>& igbp);
+ const android::sp<HGraphicBufferProducer>& igbp,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem);
bool beginTransferBlockToClient();
bool endTransferBlockToClient(bool transfer);
bool beginAttachBlockToBufferQueue();
bool endAttachBlockToBufferQueue(const std::shared_ptr<int>& owner,
const android::sp<HGraphicBufferProducer>& igbp,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem,
uint32_t generation, uint64_t bqId, int32_t bqSlot);
bool displayBlockToBufferQueue();
@@ -141,6 +175,7 @@
bool mDisplay; // display on remote;
std::weak_ptr<int> mOwner;
android::sp<HGraphicBufferProducer> mIgbp;
+ std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
mutable std::mutex mLock;
};
diff --git a/media/codec2/vndk/include/C2FenceFactory.h b/media/codec2/vndk/include/C2FenceFactory.h
new file mode 100644
index 0000000..d4bed26
--- /dev/null
+++ b/media/codec2/vndk/include/C2FenceFactory.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_FENCE_FACTORY_H_
+#define STAGEFRIGHT_CODEC2_FENCE_FACTORY_H_
+
+
+#include <C2Buffer.h>
+
+class C2SurfaceSyncMemory;
+
+/**
+ * C2Fence implementation factory
+ */
+struct _C2FenceFactory {
+
+ class SurfaceFenceImpl;
+
+ /*
+ * Create C2Fence for BufferQueueBased blockpool.
+ *
+ * \param syncMem Shared memory object for synchronization between processes.
+ * \param waitId wait id for tracking status change for C2Fence.
+ */
+ static C2Fence CreateSurfaceFence(
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem,
+ uint32_t waitId);
+};
+
+
+#endif // STAGEFRIGHT_CODEC2_FENCE_FACTORY_H_
diff --git a/media/codec2/vndk/include/C2SurfaceSyncObj.h b/media/codec2/vndk/include/C2SurfaceSyncObj.h
new file mode 100644
index 0000000..16e9a9d
--- /dev/null
+++ b/media/codec2/vndk/include/C2SurfaceSyncObj.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_SURFACE_SYNC_OBJ_H_
+#define STAGEFRIGHT_CODEC2_SURFACE_SYNC_OBJ_H_
+
+#include <cutils/native_handle.h>
+#include <memory>
+#include <atomic>
+
+#include <C2Buffer.h>
+
+/**
+ * Futex based lock / wait implementation for sharing output buffer allocation
+ * information between Framework and HAL.
+ */
+struct C2SyncVariables {
+ enum SyncStatus : uint32_t {
+ STATUS_INIT = 0, // When surface configuration starts.
+ STATUS_ACTIVE = 1, // When surface configuration finishs.
+ // STATUS_INIT -> STATUS_ACTIVE
+ STATUS_SWITCHING = 2, // When the surface is replaced by a new surface
+ // during surface configuration.
+ // STATUS_ACTIVE -> STATUS_SWITCHING
+ };
+
+ /**
+ * Lock the memory region
+ */
+ int lock();
+
+ /**
+ * Unlock the memory region
+ */
+ int unlock();
+
+ /**
+ * Set initial dequeued buffer count.
+ *
+ * \param maxDequeueCount Initial value of # of max dequeued buffer count
+ * \param curDequeueCount Initial value of # of current dequeued buffer count
+ */
+ void setInitialDequeueCount(int32_t maxDequeueCount, int32_t curDequeueCount);
+
+ /**
+ * Get a waitId which will be used to implement fence.
+ */
+ uint32_t getWaitIdLocked();
+
+ /**
+ * Return whether the upcoming dequeue operation is not blocked.
+ * if it's blocked and waitId is non-null, waitId is returned to be used for waiting.
+ *
+ * \retval false dequeue operation is blocked now.
+ * \retval true dequeue operation is possible.
+ */
+ bool isDequeueableLocked(uint32_t *waitId = nullptr);
+
+ /**
+ * Notify a buffer is queued. Return whether the upcoming dequeue operation
+ * is not blocked. if it's blocked and waitId is non-null, waitId is returned
+ * to be used for waiting.
+ *
+ * \retval false dequeue operation is blocked now.
+ * \retval true dequeue operation is possible.
+ */
+ bool notifyQueuedLocked(uint32_t *waitId = nullptr);
+
+ /**
+ * Notify a buffer is dequeued.
+ */
+ void notifyDequeuedLocked();
+
+ /**
+ * Set sync status.
+ */
+ void setSyncStatusLocked(SyncStatus status);
+
+ /**
+ * Get sync status.
+ */
+ C2SyncVariables::SyncStatus getSyncStatusLocked();
+
+ /**
+ * Update current max dequeue count.
+ */
+ void updateMaxDequeueCountLocked(int32_t maxDequeueCount);
+
+ /**
+ * Wait until status is no longer equal to waitId, or until timeout.
+ *
+ * \param waitId internal status for waiting until it is changed.
+ * \param timeousNs nano seconds to timeout.
+ *
+ * \retval C2_TIMEDOUT change does not happen during waiting.
+ * \retval C2_BAD_VALUE invalid event waiting.
+ * \retval C2_OK change was signalled.
+ */
+ c2_status_t waitForChange(uint32_t waitId, c2_nsecs_t timeoutNs);
+
+ C2SyncVariables() {}
+
+private:
+ /**
+ * signal one waiter to wake up.
+ */
+ int signal();
+
+ /**
+ * signal all waiter to wake up.
+ */
+ int broadcast();
+
+ /**
+ * wait for signal or broadcast.
+ */
+ int wait();
+
+ std::atomic<uint32_t> mLock;
+ std::atomic<uint32_t> mCond;
+ int32_t mMaxDequeueCount;
+ int32_t mCurDequeueCount;
+ SyncStatus mStatus;
+};
+
+/**
+ * Shared memory in order to synchronize information for Surface(IGBP)
+ * based output buffer allocation.
+ */
+class C2SurfaceSyncMemory {
+public:
+ /**
+ * Shared memory handle in order to synchronize information for
+ * Surface based output buffer allocation.
+ */
+ struct HandleSyncMem : public native_handle_t {
+ HandleSyncMem(int fd, size_t size) :
+ native_handle_t(cHeader),
+ mFds{fd},
+ mInts{int(size & 0xFFFFFFFF),
+ int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic} {}
+
+ /** Returns a file descriptor of the shared memory
+ * \return a file descriptor representing the shared memory
+ */
+ int memFd() const {return mFds.mMem;}
+
+ /** Returns the size of the shared memory */
+ size_t size() const {
+ return size_t(unsigned(mInts.mSizeLo))
+ | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
+ }
+
+ /** Check whether the native handle is in the form of HandleSyncMem
+ *
+ * \return whether the native handle is compatible
+ */
+ static bool isValid(const native_handle_t * const o);
+
+ protected:
+ struct {
+ int mMem;
+ } mFds;
+ struct {
+ int mSizeLo;
+ int mSizeHi;
+ int mMagic;
+ } mInts;
+ private:
+ enum {
+ kMagic = 'ssm\x00',
+ numFds = sizeof(mFds) / sizeof(int),
+ numInts = sizeof(mInts) / sizeof(int),
+ version = sizeof(native_handle_t)
+ };
+ const static native_handle_t cHeader;
+ };
+
+ /**
+ * Imports a shared memory object from a native handle(The shared memory is already existing).
+ * This is usually used after native_handle_t is passed via RPC.
+ *
+ * \param handle handle representing shared memory for output buffer allocation.
+ */
+ static std::shared_ptr<C2SurfaceSyncMemory> Import(native_handle_t *handle);
+
+ /**
+ * Creats a shared memory object for synchronization of output buffer allocation.
+ * Shared memory creation should be done explicitly.
+ *
+ * \param fd file descriptor to shared memory
+ * \param size size of the shared memory
+ */
+ static std::shared_ptr<C2SurfaceSyncMemory> Create(int fd, size_t size);
+
+ /**
+ * Returns a handle representing the shread memory for synchronization of
+ * output buffer allocation.
+ */
+ native_handle_t *handle();
+
+ /**
+ * Returns synchronization object which will provide synchronization primitives.
+ *
+ * \return a ptr to synchronization primitive class
+ */
+ C2SyncVariables *mem();
+
+ ~C2SurfaceSyncMemory();
+
+private:
+ bool mInit;
+ HandleSyncMem *mHandle;
+ C2SyncVariables *mMem;
+
+ C2SurfaceSyncMemory();
+};
+
+#endif // STAGEFRIGHT_CODEC2_SURFACE_SYNC_OBJ_H_
diff --git a/media/codec2/vndk/internal/C2BlockInternal.h b/media/codec2/vndk/internal/C2BlockInternal.h
index 4ae946a..c510fca 100644
--- a/media/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/codec2/vndk/internal/C2BlockInternal.h
@@ -52,6 +52,8 @@
struct C2BufferQueueBlockPoolData;
+class C2SurfaceSyncMemory;
+
/**
* Internal only interface for creating blocks by block pool/buffer passing implementations.
*
@@ -279,6 +281,8 @@
* anymore.
* \param igbp \c IGraphicBufferProducer instance to be assigned to the
* block. This is not needed when the block is local.
+ * \param syncMem Memory block which will support synchronization
+ * between Framework and HAL.
*
* \return The previous held status.
*/
@@ -287,7 +291,8 @@
const std::shared_ptr<_C2BlockPoolData>& poolData,
const std::shared_ptr<int>& owner,
const ::android::sp<::android::hardware::graphics::bufferqueue::
- V2_0::IGraphicBufferProducer>& igbp = nullptr);
+ V2_0::IGraphicBufferProducer>& igbp = nullptr,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem = nullptr);
/**
* Prepare a block to be transferred to other process. This blocks
@@ -358,6 +363,7 @@
const std::shared_ptr<int>& owner,
const ::android::sp<::android::hardware::graphics::bufferqueue::
V2_0::IGraphicBufferProducer>& igbp,
+ std::shared_ptr<C2SurfaceSyncMemory>,
uint32_t generation,
uint64_t bqId,
int32_t bqSlot);
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 3f6fa7d..2944925 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -29,6 +29,8 @@
#include <C2AllocatorGralloc.h>
#include <C2BqBufferPriv.h>
#include <C2BlockInternal.h>
+#include <C2FenceFactory.h>
+#include <C2SurfaceSyncObj.h>
#include <list>
#include <map>
@@ -69,10 +71,11 @@
bool _C2BlockFactory::HoldBlockFromBufferQueue(
const std::shared_ptr<_C2BlockPoolData>& data,
const std::shared_ptr<int>& owner,
- const sp<HGraphicBufferProducer>& igbp) {
+ const sp<HGraphicBufferProducer>& igbp,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem) {
const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
- return poolData->holdBlockFromBufferQueue(owner, igbp);
+ return poolData->holdBlockFromBufferQueue(owner, igbp, syncMem);
}
bool _C2BlockFactory::BeginTransferBlockToClient(
@@ -102,12 +105,13 @@
const std::shared_ptr<_C2BlockPoolData>& data,
const std::shared_ptr<int>& owner,
const sp<HGraphicBufferProducer>& igbp,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem,
uint32_t generation,
uint64_t bqId,
int32_t bqSlot) {
const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
- return poolData->endAttachBlockToBufferQueue(owner, igbp, generation, bqId, bqSlot);
+ return poolData->endAttachBlockToBufferQueue(owner, igbp, syncMem, generation, bqId, bqSlot);
}
bool _C2BlockFactory::DisplayBlockToBufferQueue(
@@ -231,12 +235,58 @@
class C2BufferQueueBlockPool::Impl
: public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> {
private:
+ c2_status_t dequeueBuffer(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2AndroidMemoryUsage androidUsage,
+ int *slot, bool *needsRealloc, sp<Fence> *fence) {
+ status_t status{};
+ using Input = HGraphicBufferProducer::DequeueBufferInput;
+ using Output = HGraphicBufferProducer::DequeueBufferOutput;
+ Return<void> transResult = mProducer->dequeueBuffer(
+ Input{
+ width,
+ height,
+ format,
+ androidUsage.asGrallocUsage()},
+ [&status, slot, needsRealloc,
+ fence](HStatus hStatus,
+ int32_t hSlot,
+ Output const& hOutput) {
+ *slot = static_cast<int>(hSlot);
+ if (!h2b(hStatus, &status) ||
+ !h2b(hOutput.fence, fence)) {
+ status = ::android::BAD_VALUE;
+ } else {
+ *needsRealloc =
+ hOutput.bufferNeedsReallocation;
+ }
+ });
+ if (!transResult.isOk() || status != android::OK) {
+ if (transResult.isOk()) {
+ ++mDqFailure;
+ if (status == android::INVALID_OPERATION ||
+ status == android::TIMED_OUT ||
+ status == android::WOULD_BLOCK) {
+ // Dequeue buffer is blocked temporarily. Retrying is
+ // required.
+ return C2_BLOCKING;
+ }
+ }
+ ALOGD("cannot dequeue buffer %d", status);
+ return C2_BAD_VALUE;
+ }
+ return C2_OK;
+ }
+
c2_status_t fetchFromIgbp_l(
uint32_t width,
uint32_t height,
uint32_t format,
C2MemoryUsage usage,
- std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
+ C2Fence *c2Fence) {
// We have an IGBP now.
C2AndroidMemoryUsage androidUsage = usage;
status_t status{};
@@ -245,41 +295,39 @@
sp<Fence> fence = new Fence();
ALOGV("tries to dequeue buffer");
+ C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem(): nullptr;
{ // Call dequeueBuffer().
- using Input = HGraphicBufferProducer::DequeueBufferInput;
- using Output = HGraphicBufferProducer::DequeueBufferOutput;
- Return<void> transResult = mProducer->dequeueBuffer(
- Input{
- width,
- height,
- format,
- androidUsage.asGrallocUsage()},
- [&status, &slot, &bufferNeedsReallocation,
- &fence](HStatus hStatus,
- int32_t hSlot,
- Output const& hOutput) {
- slot = static_cast<int>(hSlot);
- if (!h2b(hStatus, &status) ||
- !h2b(hOutput.fence, &fence)) {
- status = ::android::BAD_VALUE;
- } else {
- bufferNeedsReallocation =
- hOutput.bufferNeedsReallocation;
- }
- });
- if (!transResult.isOk() || status != android::OK) {
- if (transResult.isOk()) {
- ++mDqFailure;
- if (status == android::INVALID_OPERATION ||
- status == android::TIMED_OUT ||
- status == android::WOULD_BLOCK) {
- // Dequeue buffer is blocked temporarily. Retrying is
- // required.
- return C2_BLOCKING;
+ c2_status_t c2Status;
+ if (syncVar) {
+ uint32_t waitId;
+ syncVar->lock();
+ if (!syncVar->isDequeueableLocked(&waitId)) {
+ syncVar->unlock();
+ if (c2Fence) {
+ *c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
}
+ return C2_BLOCKING;
}
- ALOGD("cannot dequeue buffer %d", status);
- return C2_BAD_VALUE;
+ if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_ACTIVE) {
+ waitId = syncVar->getWaitIdLocked();
+ syncVar->unlock();
+ if (c2Fence) {
+ *c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
+ }
+ return C2_BLOCKING;
+ }
+ c2Status = dequeueBuffer(width, height, format, androidUsage,
+ &slot, &bufferNeedsReallocation, &fence);
+ if (c2Status == C2_OK) {
+ syncVar->notifyDequeuedLocked();
+ }
+ syncVar->unlock();
+ } else {
+ c2Status = dequeueBuffer(width, height, format, usage,
+ &slot, &bufferNeedsReallocation, &fence);
+ }
+ if (c2Status != C2_OK) {
+ return c2Status;
}
mDqFailure = 0;
mLastDqTs = getTimestampNow();
@@ -290,18 +338,41 @@
return C2_BAD_VALUE;
}
ALOGV("dequeued a buffer successfully");
+ bool dequeueable = false;
+ uint32_t waitId;
if (fence) {
static constexpr int kFenceWaitTimeMs = 10;
status_t status = fence->wait(kFenceWaitTimeMs);
if (status == -ETIME) {
// fence is not signalled yet.
- (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ if (syncVar) {
+ syncVar->lock();
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ dequeueable = syncVar->notifyQueuedLocked(&waitId);
+ syncVar->unlock();
+ if (c2Fence) {
+ *c2Fence = dequeueable ? C2Fence() :
+ _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
+ }
+ } else {
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ }
return C2_BLOCKING;
}
if (status != android::NO_ERROR) {
ALOGD("buffer fence wait error %d", status);
- (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ if (syncVar) {
+ syncVar->lock();
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ syncVar->notifyQueuedLocked();
+ syncVar->unlock();
+ if (c2Fence) {
+ *c2Fence = C2Fence();
+ }
+ } else {
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ }
return C2_BAD_VALUE;
} else if (mRenderCallback) {
nsecs_t signalTime = fence->getSignalTime();
@@ -341,7 +412,17 @@
return C2_BAD_VALUE;
} else if (status != android::NO_ERROR) {
slotBuffer.clear();
- (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ if (syncVar) {
+ syncVar->lock();
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ syncVar->notifyQueuedLocked();
+ syncVar->unlock();
+ if (c2Fence) {
+ *c2Fence = C2Fence();
+ }
+ } else {
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ }
return C2_BAD_VALUE;
}
if (mGeneration == 0) {
@@ -372,14 +453,28 @@
std::make_shared<C2BufferQueueBlockPoolData>(
slotBuffer->getGenerationNumber(),
mProducerId, slot,
- mProducer);
+ mProducer, mSyncMem, 0);
mPoolDatas[slot] = poolData;
*block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
return C2_OK;
}
// Block was not created. call requestBuffer# again next time.
slotBuffer.clear();
- (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ if (syncVar) {
+ syncVar->lock();
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ syncVar->notifyQueuedLocked();
+ syncVar->unlock();
+ if (c2Fence) {
+ *c2Fence = C2Fence();
+ }
+ } else {
+ (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+ }
+ return C2_BAD_VALUE;
+ }
+ if (c2Fence) {
+ *c2Fence = C2Fence();
}
return C2_BAD_VALUE;
}
@@ -409,7 +504,8 @@
uint32_t height,
uint32_t format,
C2MemoryUsage usage,
- std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
+ C2Fence *fence) {
block->reset();
if (mInit != C2_OK) {
return mInit;
@@ -440,17 +536,19 @@
}
std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
std::make_shared<C2BufferQueueBlockPoolData>(
- 0, (uint64_t)0, ~0, nullptr);
+ 0, (uint64_t)0, ~0, nullptr, nullptr, 0);
*block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
ALOGV("allocated a buffer successfully");
return C2_OK;
}
- c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
+ c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block, fence);
if (status == C2_BLOCKING) {
lock.unlock();
- // in order not to drain cpu from component's spinning
- ::usleep(kMaxIgbpRetryDelayUs);
+ if (!fence) {
+ // in order not to drain cpu from component's spinning
+ ::usleep(kMaxIgbpRetryDelayUs);
+ }
}
return status;
}
@@ -460,11 +558,12 @@
mRenderCallback = renderCallback;
}
+ /* This is for Old HAL request for compatibility */
void configureProducer(const sp<HGraphicBufferProducer> &producer) {
uint64_t producerId = 0;
uint32_t generation = 0;
uint64_t usage = 0;
- bool haveGeneration = false;
+ bool bqInformation = false;
if (producer) {
Return<uint64_t> transResult = producer->getUniqueId();
if (!transResult.isOk()) {
@@ -472,14 +571,32 @@
return;
}
producerId = static_cast<uint64_t>(transResult);
- // TODO: provide gneration number from parameter.
- haveGeneration = getGenerationNumberAndUsage(producer, &generation, &usage);
- if (!haveGeneration) {
+ bqInformation = getGenerationNumberAndUsage(producer, &generation, &usage);
+ if (!bqInformation) {
ALOGW("get generationNumber failed %llu",
(unsigned long long)producerId);
}
}
+ configureProducer(producer, nullptr, producerId, generation, usage, bqInformation);
+ }
+
+ void configureProducer(const sp<HGraphicBufferProducer> &producer,
+ native_handle_t *syncHandle,
+ uint64_t producerId,
+ uint32_t generation,
+ uint64_t usage,
+ bool bqInformation) {
+ std::shared_ptr<C2SurfaceSyncMemory> c2SyncMem;
+ if (syncHandle) {
+ if (!producer) {
+ native_handle_close(syncHandle);
+ native_handle_delete(syncHandle);
+ } else {
+ c2SyncMem = C2SurfaceSyncMemory::Import(syncHandle);
+ }
+ }
int migrated = 0;
+ std::shared_ptr<C2SurfaceSyncMemory> oldMem;
// poolDatas dtor should not be called during lock is held.
std::shared_ptr<C2BufferQueueBlockPoolData>
poolDatas[NUM_BUFFER_SLOTS];
@@ -499,22 +616,30 @@
if (producer) {
mProducer = producer;
mProducerId = producerId;
- mGeneration = haveGeneration ? generation : 0;
+ mGeneration = bqInformation ? generation : 0;
} else {
mProducer = nullptr;
mProducerId = 0;
mGeneration = 0;
ALOGW("invalid producer producer(%d), generation(%d)",
- (bool)producer, haveGeneration);
+ (bool)producer, bqInformation);
}
- if (mProducer && haveGeneration) { // migrate buffers
+ oldMem = mSyncMem; // preven destruction while locked.
+ mSyncMem = c2SyncMem;
+ C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
+ if (syncVar) {
+ syncVar->lock();
+ syncVar->setSyncStatusLocked(C2SyncVariables::STATUS_ACTIVE);
+ syncVar->unlock();
+ }
+ if (mProducer && bqInformation) { // migrate buffers
for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
std::shared_ptr<C2BufferQueueBlockPoolData> data =
mPoolDatas[i].lock();
if (data) {
int slot = data->migrate(
mProducer, generation, usage,
- producerId, mBuffers[i], oldGeneration);
+ producerId, mBuffers[i], oldGeneration, mSyncMem);
if (slot >= 0) {
buffers[slot] = mBuffers[i];
poolDatas[slot] = data;
@@ -528,7 +653,7 @@
mPoolDatas[i] = poolDatas[i];
}
}
- if (producer && haveGeneration) {
+ if (producer && bqInformation) {
ALOGD("local generation change %u , "
"bqId: %llu migrated buffers # %d",
generation, (unsigned long long)producerId, migrated);
@@ -555,6 +680,8 @@
sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
+
+ std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
};
C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
@@ -570,11 +697,14 @@
C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
uint32_t generation, uint64_t bqId, int32_t bqSlot,
- const android::sp<HGraphicBufferProducer>& producer) :
+ const android::sp<HGraphicBufferProducer>& producer,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem, int noUse) :
mLocal(true), mHeld(true),
mGeneration(generation), mBqId(bqId), mBqSlot(bqSlot),
mCurrentGeneration(generation), mCurrentBqId(bqId),
- mTransfer(false), mAttach(false), mDisplay(false), mIgbp(producer) {
+ mTransfer(false), mAttach(false), mDisplay(false),
+ mIgbp(producer), mSyncMem(syncMem) {
+ (void)noUse;
}
C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
@@ -584,10 +714,30 @@
if (mLocal) {
if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId) {
- mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
+ C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
+ if (syncVar) {
+ syncVar->lock();
+ if (syncVar->getSyncStatusLocked() == C2SyncVariables::STATUS_ACTIVE) {
+ mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
+ syncVar->notifyQueuedLocked();
+ }
+ syncVar->unlock();
+ } else {
+ mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
+ }
}
} else if (!mOwner.expired()) {
- mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
+ C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
+ if (syncVar) {
+ syncVar->lock();
+ if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_SWITCHING) {
+ mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
+ syncVar->notifyQueuedLocked();
+ }
+ syncVar->unlock();
+ } else {
+ mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
+ }
}
}
@@ -598,7 +748,8 @@
int C2BufferQueueBlockPoolData::migrate(
const sp<HGraphicBufferProducer>& producer,
uint32_t toGeneration, uint64_t toUsage, uint64_t toBqId,
- sp<GraphicBuffer>& graphicBuffer, uint32_t oldGeneration) {
+ sp<GraphicBuffer>& graphicBuffer, uint32_t oldGeneration,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem) {
std::scoped_lock<std::mutex> l(mLock);
mCurrentBqId = toBqId;
@@ -626,6 +777,7 @@
}
if (oldGeneration != mGeneration) {
ALOGV("cannot migrate stale buffer");
+ return -1;
}
if (mTransfer) {
// either transferred or detached.
@@ -678,6 +830,14 @@
mGeneration = toGeneration;
mBqId = toBqId;
mBqSlot = slot;
+ mSyncMem = syncMem;
+
+ C2SyncVariables *syncVar = syncMem ? syncMem->mem() : nullptr;
+ if (syncVar) {
+ syncVar->lock();
+ syncVar->notifyDequeuedLocked();
+ syncVar->unlock();
+ }
return slot;
}
@@ -697,11 +857,13 @@
bool C2BufferQueueBlockPoolData::holdBlockFromBufferQueue(
const std::shared_ptr<int>& owner,
- const sp<HGraphicBufferProducer>& igbp) {
+ const sp<HGraphicBufferProducer>& igbp,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem) {
std::scoped_lock<std::mutex> lock(mLock);
if (!mLocal) {
mOwner = owner;
mIgbp = igbp;
+ mSyncMem = syncMem;
}
if (mHeld) {
return false;
@@ -741,6 +903,7 @@
bool C2BufferQueueBlockPoolData::endAttachBlockToBufferQueue(
const std::shared_ptr<int>& owner,
const sp<HGraphicBufferProducer>& igbp,
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem,
uint32_t generation,
uint64_t bqId,
int32_t bqSlot) {
@@ -757,6 +920,7 @@
mHeld = true;
mOwner = owner;
mIgbp = igbp;
+ mSyncMem = syncMem;
mGeneration = generation;
mBqId = bqId;
mBqSlot = bqSlot;
@@ -792,7 +956,20 @@
C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
if (mImpl) {
- return mImpl->fetchGraphicBlock(width, height, format, usage, block);
+ return mImpl->fetchGraphicBlock(width, height, format, usage, block, nullptr);
+ }
+ return C2_CORRUPTED;
+}
+
+c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
+ C2Fence *fence /* nonnull */) {
+ if (mImpl) {
+ return mImpl->fetchGraphicBlock(width, height, format, usage, block, fence);
}
return C2_CORRUPTED;
}
@@ -803,6 +980,18 @@
}
}
+void C2BufferQueueBlockPool::configureProducer(
+ const sp<HGraphicBufferProducer> &producer,
+ native_handle_t *syncMemory,
+ uint64_t bqId,
+ uint32_t generationId,
+ uint64_t consumerUsage) {
+ if (mImpl) {
+ mImpl->configureProducer(
+ producer, syncMemory, bqId, generationId, consumerUsage, true);
+ }
+}
+
void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) {
if (mImpl) {
mImpl->setRenderCallback(renderCallback);
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
new file mode 100644
index 0000000..587992e
--- /dev/null
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2SurfaceSyncObj"
+#include <limits.h>
+#include <linux/futex.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <C2SurfaceSyncObj.h>
+
+const native_handle_t C2SurfaceSyncMemory::HandleSyncMem::cHeader = {
+ C2SurfaceSyncMemory::HandleSyncMem::version,
+ C2SurfaceSyncMemory::HandleSyncMem::numFds,
+ C2SurfaceSyncMemory::HandleSyncMem::numInts,
+ {}
+};
+
+bool C2SurfaceSyncMemory::HandleSyncMem::isValid(const native_handle_t * const o) {
+ if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+ return false;
+ }
+
+ const HandleSyncMem *other = static_cast<const HandleSyncMem*>(o);
+ return other->mInts.mMagic == kMagic;
+}
+
+C2SurfaceSyncMemory::C2SurfaceSyncMemory()
+ : mInit(false), mHandle(nullptr), mMem(nullptr) {}
+
+C2SurfaceSyncMemory::~C2SurfaceSyncMemory() {
+ if (mInit) {
+ if (mMem) {
+ munmap(static_cast<void *>(mMem), mHandle->size());
+ }
+ if (mHandle) {
+ native_handle_close(mHandle);
+ native_handle_delete(mHandle);
+ }
+ }
+}
+
+std::shared_ptr<C2SurfaceSyncMemory> C2SurfaceSyncMemory::Import(
+ native_handle_t *handle) {
+ if (!HandleSyncMem::isValid(handle)) {
+ return nullptr;
+ }
+
+ HandleSyncMem *o = static_cast<HandleSyncMem*>(handle);
+ void *ptr = mmap(NULL, o->size(), PROT_READ | PROT_WRITE, MAP_SHARED, o->memFd(), 0);
+
+ if (ptr == MAP_FAILED) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ return nullptr;
+ }
+
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem(new C2SurfaceSyncMemory);
+ syncMem->mInit = true;
+ syncMem->mHandle = o;
+ syncMem->mMem = static_cast<C2SyncVariables*>(ptr);
+ return syncMem;
+}
+
+std::shared_ptr<C2SurfaceSyncMemory> C2SurfaceSyncMemory::Create(int fd, size_t size) {
+ if (fd < 0 || size == 0) {
+ return nullptr;
+ }
+ HandleSyncMem *handle = new HandleSyncMem(fd, size);
+
+ void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ return nullptr;
+ }
+ memset(ptr, 0, size);
+
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem(new C2SurfaceSyncMemory);
+ syncMem->mInit = true;
+ syncMem->mHandle = handle;
+ syncMem->mMem = static_cast<C2SyncVariables*>(ptr);
+ return syncMem;
+}
+
+native_handle_t *C2SurfaceSyncMemory::handle() {
+ return !mInit ? nullptr : mHandle;
+}
+
+C2SyncVariables *C2SurfaceSyncMemory::mem() {
+ return !mInit ? nullptr : mMem;
+}
+
+namespace {
+ constexpr int kSpinNumForLock = 100;
+ constexpr int kSpinNumForUnlock = 200;
+
+ enum : uint32_t {
+ FUTEX_UNLOCKED = 0,
+ FUTEX_LOCKED_UNCONTENDED = 1, // user-space locking
+ FUTEX_LOCKED_CONTENDED = 2, // futex locking
+ };
+}
+
+int C2SyncVariables::lock() {
+ uint32_t old;
+ for (int i = 0; i < kSpinNumForLock; i++) {
+ old = 0;
+ if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) {
+ return 0;
+ }
+ sched_yield();
+ }
+
+ if (old == FUTEX_LOCKED_UNCONTENDED)
+ old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
+
+ while (old) {
+ (void) syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0);
+ old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
+ }
+ return 0;
+}
+
+int C2SyncVariables::unlock() {
+ if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) return 0;
+
+ for (int i = 0; i < kSpinNumForUnlock; i++) {
+ if (mLock.load()) {
+ uint32_t old = FUTEX_LOCKED_UNCONTENDED;
+ mLock.compare_exchange_strong(old, FUTEX_LOCKED_CONTENDED);
+ if (old) {
+ return 0;
+ }
+ }
+ sched_yield();
+ }
+
+ (void) syscall(__NR_futex, &mLock, FUTEX_WAKE, 1, NULL, NULL, 0);
+ return 0;
+}
+
+void C2SyncVariables::setInitialDequeueCount(
+ int32_t maxDequeueCount, int32_t curDequeueCount) {
+ lock();
+ mMaxDequeueCount = maxDequeueCount;
+ mCurDequeueCount = curDequeueCount;
+ unlock();
+}
+
+uint32_t C2SyncVariables::getWaitIdLocked() {
+ return mCond.load();
+}
+
+bool C2SyncVariables::isDequeueableLocked(uint32_t *waitId) {
+ if (mMaxDequeueCount <= mCurDequeueCount) {
+ if (waitId) {
+ *waitId = getWaitIdLocked();
+ }
+ return false;
+ }
+ return true;
+}
+
+bool C2SyncVariables::notifyQueuedLocked(uint32_t *waitId) {
+ // Note. thundering herds may occur. Edge trigged signalling.
+ // But one waiter will guarantee to dequeue. others may wait again.
+ // Minimize futex syscall(trap) for the main use case(one waiter case).
+ if (mMaxDequeueCount == mCurDequeueCount--) {
+ broadcast();
+ return true;
+ }
+
+ if (mCurDequeueCount >= mMaxDequeueCount) {
+ if (waitId) {
+ *waitId = getWaitIdLocked();
+ }
+ ALOGV("dequeue blocked %d/%d", mCurDequeueCount, mMaxDequeueCount);
+ return false;
+ }
+ return true;
+}
+
+void C2SyncVariables::notifyDequeuedLocked() {
+ mCurDequeueCount++;
+ ALOGV("dequeue successful %d/%d", mCurDequeueCount, mMaxDequeueCount);
+}
+
+void C2SyncVariables::setSyncStatusLocked(SyncStatus status) {
+ mStatus = status;
+ if (mStatus == STATUS_ACTIVE) {
+ broadcast();
+ }
+}
+
+C2SyncVariables::SyncStatus C2SyncVariables::getSyncStatusLocked() {
+ return mStatus;
+}
+
+void C2SyncVariables::updateMaxDequeueCountLocked(int32_t maxDequeueCount) {
+ mMaxDequeueCount = maxDequeueCount;
+ if (mStatus == STATUS_ACTIVE) {
+ broadcast();
+ }
+}
+
+c2_status_t C2SyncVariables::waitForChange(uint32_t waitId, c2_nsecs_t timeoutNs) {
+ if (timeoutNs < 0) {
+ timeoutNs = 0;
+ }
+ struct timespec tv;
+ tv.tv_sec = timeoutNs / 1000000000;
+ tv.tv_nsec = timeoutNs % 1000000000;
+
+ int ret = syscall(__NR_futex, &mCond, FUTEX_WAIT, waitId, &tv, NULL, 0);
+ if (ret == 0 || ret == EAGAIN) {
+ return C2_OK;
+ }
+ if (ret == EINTR || ret == ETIMEDOUT) {
+ return C2_TIMED_OUT;
+ }
+ return C2_BAD_VALUE;
+}
+
+int C2SyncVariables::signal() {
+ mCond++;
+
+ (void) syscall(__NR_futex, &mCond, FUTEX_WAKE, 1, NULL, NULL, 0);
+ return 0;
+}
+
+int C2SyncVariables::broadcast() {
+ mCond++;
+
+ (void) syscall(__NR_futex, &mCond, FUTEX_REQUEUE, 1, (void *)INT_MAX, &mLock, 0);
+ return 0;
+}
+
+int C2SyncVariables::wait() {
+ uint32_t old = mCond.load();
+ unlock();
+
+ (void) syscall(__NR_futex, &mCond, FUTEX_WAIT, old, NULL, NULL, 0);
+ while (mLock.exchange(FUTEX_LOCKED_CONTENDED)) {
+ (void) syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0);
+ }
+ return 0;
+}
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 05ba55f..c77aeeb 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -1918,6 +1918,9 @@
convertRange(aidl.channelMasks.begin(), aidl.channelMasks.end(), legacy.channel_masks,
aidl2legacy_int32_t_audio_channel_mask_t));
legacy.num_channel_masks = aidl.channelMasks.size();
+
+ legacy.encapsulation_type = VALUE_OR_RETURN(
+ aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(aidl.encapsulationType));
return legacy;
}
@@ -1941,6 +1944,10 @@
convertRange(legacy.channel_masks, legacy.channel_masks + legacy.num_channel_masks,
std::back_inserter(aidl.channelMasks),
legacy2aidl_audio_channel_mask_t_int32_t));
+
+ aidl.encapsulationType = VALUE_OR_RETURN(
+ legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(
+ legacy.encapsulation_type));
return aidl;
}
@@ -1989,6 +1996,15 @@
aidl2legacy_AudioProfile_audio_profile));
legacy.num_audio_profiles = aidl.profiles.size();
+ if (aidl.extraAudioDescriptors.size() > std::size(legacy.extra_audio_descriptors)) {
+ return unexpected(BAD_VALUE);
+ }
+ RETURN_IF_ERROR(
+ convertRange(aidl.extraAudioDescriptors.begin(), aidl.extraAudioDescriptors.end(),
+ legacy.extra_audio_descriptors,
+ aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor));
+ legacy.num_extra_audio_descriptors = aidl.extraAudioDescriptors.size();
+
if (aidl.gains.size() > std::size(legacy.gains)) {
return unexpected(BAD_VALUE);
}
@@ -2018,6 +2034,15 @@
std::back_inserter(aidl.profiles),
legacy2aidl_audio_profile_AudioProfile));
+ if (legacy.num_extra_audio_descriptors > std::size(legacy.extra_audio_descriptors)) {
+ return unexpected(BAD_VALUE);
+ }
+ RETURN_IF_ERROR(
+ convertRange(legacy.extra_audio_descriptors,
+ legacy.extra_audio_descriptors + legacy.num_extra_audio_descriptors,
+ std::back_inserter(aidl.extraAudioDescriptors),
+ legacy2aidl_audio_extra_audio_descriptor_ExtraAudioDescriptor));
+
if (legacy.num_gains > std::size(legacy.gains)) {
return unexpected(BAD_VALUE);
}
@@ -2218,4 +2243,84 @@
return aidl;
}
+ConversionResult<audio_standard_t>
+aidl2legacy_AudioStandard_audio_standard_t(media::AudioStandard aidl) {
+ switch (aidl) {
+ case media::AudioStandard::NONE:
+ return AUDIO_STANDARD_NONE;
+ case media::AudioStandard::EDID:
+ return AUDIO_STANDARD_EDID;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioStandard>
+legacy2aidl_audio_standard_t_AudioStandard(audio_standard_t legacy) {
+ switch (legacy) {
+ case AUDIO_STANDARD_NONE:
+ return media::AudioStandard::NONE;
+ case AUDIO_STANDARD_EDID:
+ return media::AudioStandard::EDID;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_extra_audio_descriptor>
+aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor(
+ const media::ExtraAudioDescriptor& aidl) {
+ audio_extra_audio_descriptor legacy;
+ legacy.standard = VALUE_OR_RETURN(aidl2legacy_AudioStandard_audio_standard_t(aidl.standard));
+ if (aidl.audioDescriptor.size() > EXTRA_AUDIO_DESCRIPTOR_SIZE) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.descriptor_length = aidl.audioDescriptor.size();
+ std::copy(aidl.audioDescriptor.begin(), aidl.audioDescriptor.end(),
+ std::begin(legacy.descriptor));
+ legacy.encapsulation_type =
+ VALUE_OR_RETURN(aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
+ aidl.encapsulationType));
+ return legacy;
+}
+
+ConversionResult<media::ExtraAudioDescriptor>
+legacy2aidl_audio_extra_audio_descriptor_ExtraAudioDescriptor(
+ const audio_extra_audio_descriptor& legacy) {
+ media::ExtraAudioDescriptor aidl;
+ aidl.standard = VALUE_OR_RETURN(legacy2aidl_audio_standard_t_AudioStandard(legacy.standard));
+ if (legacy.descriptor_length > EXTRA_AUDIO_DESCRIPTOR_SIZE) {
+ return unexpected(BAD_VALUE);
+ }
+ aidl.audioDescriptor.resize(legacy.descriptor_length);
+ std::copy(legacy.descriptor, legacy.descriptor + legacy.descriptor_length,
+ aidl.audioDescriptor.begin());
+ aidl.encapsulationType =
+ VALUE_OR_RETURN(legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(
+ legacy.encapsulation_type));
+ return aidl;
+}
+
+ConversionResult<audio_encapsulation_type_t>
+aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
+ const media::AudioEncapsulationType& aidl) {
+ switch (aidl) {
+ case media::AudioEncapsulationType::NONE:
+ return AUDIO_ENCAPSULATION_TYPE_NONE;
+ case media::AudioEncapsulationType::IEC61937:
+ return AUDIO_ENCAPSULATION_TYPE_IEC61937;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioEncapsulationType>
+legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(
+ const audio_encapsulation_type_t & legacy) {
+ switch (legacy) {
+ case AUDIO_ENCAPSULATION_TYPE_NONE:
+ return media::AudioEncapsulationType::NONE;
+ case AUDIO_ENCAPSULATION_TYPE_IEC61937:
+ return media::AudioEncapsulationType::IEC61937;
+ }
+ return unexpected(BAD_VALUE);
+}
+
} // namespace android
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index d25597d..64a335a 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -311,6 +311,7 @@
"aidl/android/media/AudioDualMonoMode.aidl",
"aidl/android/media/AudioEncapsulationMode.aidl",
"aidl/android/media/AudioEncapsulationMetadataType.aidl",
+ "aidl/android/media/AudioEncapsulationType.aidl",
"aidl/android/media/AudioFlag.aidl",
"aidl/android/media/AudioGain.aidl",
"aidl/android/media/AudioGainConfig.aidl",
@@ -341,12 +342,14 @@
"aidl/android/media/AudioPortType.aidl",
"aidl/android/media/AudioProfile.aidl",
"aidl/android/media/AudioSourceType.aidl",
+ "aidl/android/media/AudioStandard.aidl",
"aidl/android/media/AudioStreamType.aidl",
"aidl/android/media/AudioTimestampInternal.aidl",
"aidl/android/media/AudioUniqueIdUse.aidl",
"aidl/android/media/AudioUsage.aidl",
"aidl/android/media/AudioUuid.aidl",
"aidl/android/media/EffectDescriptor.aidl",
+ "aidl/android/media/ExtraAudioDescriptor.aidl",
],
imports: [
"audio_common-aidl",
diff --git a/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp b/media/libaudioclient/aidl/android/media/AudioEncapsulationType.aidl
similarity index 63%
copy from media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
copy to media/libaudioclient/aidl/android/media/AudioEncapsulationType.aidl
index 65756e8..b08a604 100644
--- a/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
+++ b/media/libaudioclient/aidl/android/media/AudioEncapsulationType.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,16 @@
* limitations under the License.
*/
-#include <codec2/hidl/1.1/OutputBufferQueue.h>
+package android.media;
+
+/**
+ * Audio encapsulation type is used to describe if the audio data should be sent with a particular
+ * encapsulation type or not.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum AudioEncapsulationType {
+ NONE = 0,
+ IEC61937 = 1,
+}
\ No newline at end of file
diff --git a/media/libaudioclient/aidl/android/media/AudioPort.aidl b/media/libaudioclient/aidl/android/media/AudioPort.aidl
index 123aeb0..bf0e5b7 100644
--- a/media/libaudioclient/aidl/android/media/AudioPort.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPort.aidl
@@ -22,6 +22,7 @@
import android.media.AudioPortRole;
import android.media.AudioPortType;
import android.media.AudioProfile;
+import android.media.ExtraAudioDescriptor;
/**
* {@hide}
@@ -36,6 +37,11 @@
@utf8InCpp String name;
/** AudioProfiles supported by this port (format, Rates, Channels). */
AudioProfile[] profiles;
+ /**
+ * ExtraAudioDescriptors supported by this port. The format is not unrecognized to the
+ * platform. The audio capability is described by a hardware descriptor.
+ */
+ ExtraAudioDescriptor[] extraAudioDescriptors;
/** Gain controllers. */
AudioGain[] gains;
/** Current audio port configuration. */
diff --git a/media/libaudioclient/aidl/android/media/AudioProfile.aidl b/media/libaudioclient/aidl/android/media/AudioProfile.aidl
index e5e8812..afb288f 100644
--- a/media/libaudioclient/aidl/android/media/AudioProfile.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioProfile.aidl
@@ -16,6 +16,7 @@
package android.media;
+import android.media.AudioEncapsulationType;
import android.media.audio.common.AudioFormat;
/**
@@ -31,4 +32,5 @@
boolean isDynamicFormat;
boolean isDynamicChannels;
boolean isDynamicRate;
+ AudioEncapsulationType encapsulationType;
}
diff --git a/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp b/media/libaudioclient/aidl/android/media/AudioStandard.aidl
similarity index 69%
rename from media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
rename to media/libaudioclient/aidl/android/media/AudioStandard.aidl
index 65756e8..e131d0d 100644
--- a/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
+++ b/media/libaudioclient/aidl/android/media/AudioStandard.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,5 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.media;
-#include <codec2/hidl/1.1/OutputBufferQueue.h>
+/**
+ * The audio standard that describe audio playback/capture capabilites.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum AudioStandard {
+ NONE = 0,
+ EDID = 1,
+}
diff --git a/media/libaudioclient/aidl/android/media/ExtraAudioDescriptor.aidl b/media/libaudioclient/aidl/android/media/ExtraAudioDescriptor.aidl
new file mode 100644
index 0000000..ec5b67a
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/ExtraAudioDescriptor.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.AudioEncapsulationType;
+import android.media.AudioStandard;
+
+/**
+ * The audio descriptor that descibes playback/capture capabilities according to
+ * a particular standard.
+ *
+ * {@hide}
+ */
+parcelable ExtraAudioDescriptor {
+ AudioStandard standard;
+ byte[] audioDescriptor;
+ AudioEncapsulationType encapsulationType;
+}
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index fd87dc2..1dd9d60 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -28,6 +28,7 @@
#include <android/media/AudioDualMonoMode.h>
#include <android/media/AudioEncapsulationMode.h>
#include <android/media/AudioEncapsulationMetadataType.h>
+#include <android/media/AudioEncapsulationType.h>
#include <android/media/AudioFlag.h>
#include <android/media/AudioGain.h>
#include <android/media/AudioGainMode.h>
@@ -48,6 +49,7 @@
#include <android/media/AudioTimestampInternal.h>
#include <android/media/AudioUniqueIdUse.h>
#include <android/media/EffectDescriptor.h>
+#include <android/media/ExtraAudioDescriptor.h>
#include <android/media/SharedFileRegion.h>
#include <binder/IMemory.h>
@@ -386,4 +388,25 @@
ConversionResult<media::AudioPlaybackRate>
legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(const audio_playback_rate_t& legacy);
+ConversionResult<audio_standard_t>
+aidl2legacy_AudioStandard_audio_standard_t(media::AudioStandard aidl);
+ConversionResult<media::AudioStandard>
+legacy2aidl_audio_standard_t_AudioStandard(audio_standard_t legacy);
+
+ConversionResult<audio_extra_audio_descriptor>
+aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor(
+ const media::ExtraAudioDescriptor& aidl);
+ConversionResult<media::ExtraAudioDescriptor>
+legacy2aidl_audio_extra_audio_descriptor_ExtraAudioDescriptor(
+ const audio_extra_audio_descriptor& legacy);
+
+ConversionResult<audio_encapsulation_type_t>
+aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
+ const media::AudioEncapsulationType& aidl);
+ConversionResult<media::AudioEncapsulationType>
+legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(
+ const audio_encapsulation_type_t & legacy);
+
+
+
} // namespace android
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
index 20d8632..fafabd9 100644
--- a/media/libaudiofoundation/AudioPort.cpp
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -16,7 +16,9 @@
#define LOG_TAG "AudioPort"
#include <algorithm>
+#include <utility>
+#include <android/media/ExtraAudioDescriptor.h>
#include <android-base/stringprintf.h>
#include <media/AudioPort.h>
#include <utils/Log.h>
@@ -46,11 +48,26 @@
port.audio_profiles->num_channel_masks),
SampleRateSet(port.audio_profiles[i].sample_rates,
port.audio_profiles[i].sample_rates +
- port.audio_profiles[i].num_sample_rates));
+ port.audio_profiles[i].num_sample_rates),
+ port.audio_profiles[i].encapsulation_type);
if (!mProfiles.contains(profile)) {
addAudioProfile(profile);
}
}
+
+ for (size_t i = 0; i < port.num_extra_audio_descriptors; ++i) {
+ auto convertedResult = legacy2aidl_audio_extra_audio_descriptor_ExtraAudioDescriptor(
+ port.extra_audio_descriptors[i]);
+ if (!convertedResult.ok()) {
+ ALOGE("%s, failed to convert extra audio descriptor", __func__);
+ continue;
+ }
+ if (std::find(mExtraAudioDescriptors.begin(),
+ mExtraAudioDescriptors.end(),
+ convertedResult.value()) == mExtraAudioDescriptors.end()) {
+ mExtraAudioDescriptors.push_back(std::move(convertedResult.value()));
+ }
+ }
}
void AudioPort::toAudioPort(struct audio_port *port) const {
@@ -98,7 +115,7 @@
channelMasks.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
port->num_audio_profiles >= AUDIO_PORT_MAX_AUDIO_PROFILES) {
ALOGE("%s: bailing out: cannot export profiles to port config", __func__);
- return;
+ break;
}
auto& dstProfile = port->audio_profiles[port->num_audio_profiles++];
@@ -109,8 +126,25 @@
dstProfile.num_channel_masks = channelMasks.size();
std::copy(channelMasks.begin(), channelMasks.end(),
std::begin(dstProfile.channel_masks));
+ dstProfile.encapsulation_type = profile->getEncapsulationType();
}
}
+
+ port->num_extra_audio_descriptors = 0;
+ for (const auto& desc : mExtraAudioDescriptors) {
+ if (port->num_extra_audio_descriptors >= AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS) {
+ ALOGE("%s: bailing out: cannot export extra audio descriptor to port config", __func__);
+ return;
+ }
+
+ auto convertedResult = aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor(desc);
+ if (!convertedResult.ok()) {
+ ALOGE("%s: failed to convert extra audio descriptor", __func__);
+ continue;
+ }
+ port->extra_audio_descriptors[port->num_extra_audio_descriptors++] =
+ std::move(convertedResult.value());
+ }
}
void AudioPort::dump(std::string *dst, int spaces, bool verbose) const {
@@ -121,6 +155,22 @@
std::string profilesStr;
mProfiles.dump(&profilesStr, spaces);
dst->append(profilesStr);
+ if (!mExtraAudioDescriptors.empty()) {
+ dst->append(base::StringPrintf("%*s- extra audio descriptors: \n", spaces, ""));
+ const int eadSpaces = spaces + 4;
+ const int descSpaces = eadSpaces + 4;
+ for (size_t i = 0; i < mExtraAudioDescriptors.size(); i++) {
+ dst->append(
+ base::StringPrintf("%*s extra audio descriptor %zu:\n", eadSpaces, "", i));
+ dst->append(base::StringPrintf(
+ "%*s- standard: %u\n", descSpaces, "", mExtraAudioDescriptors[i].standard));
+ dst->append(base::StringPrintf("%*s- descriptor:", descSpaces, ""));
+ for (auto v : mExtraAudioDescriptors[i].audioDescriptor) {
+ dst->append(base::StringPrintf(" %02x", v));
+ }
+ dst->append("\n");
+ }
+ }
if (mGains.size() != 0) {
dst->append(base::StringPrintf("%*s- gains:\n", spaces, ""));
@@ -145,7 +195,8 @@
mName.compare(other->getName()) == 0 &&
mType == other->getType() &&
mRole == other->getRole() &&
- mProfiles.equals(other->getAudioProfiles());
+ mProfiles.equals(other->getAudioProfiles()) &&
+ mExtraAudioDescriptors == other->getExtraAudioDescriptors();
}
status_t AudioPort::writeToParcel(Parcel *parcel) const
@@ -160,6 +211,7 @@
parcelable->type = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_type_t_AudioPortType(mType));
parcelable->role = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_role_t_AudioPortRole(mRole));
parcelable->profiles = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioProfileVector(mProfiles));
+ parcelable->extraAudioDescriptors = mExtraAudioDescriptors;
parcelable->gains = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioGains(mGains));
return OK;
}
@@ -175,6 +227,7 @@
mType = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPortType_audio_port_type_t(parcelable.type));
mRole = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPortRole_audio_port_role_t(parcelable.role));
mProfiles = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioProfileVector(parcelable.profiles));
+ mExtraAudioDescriptors = parcelable.extraAudioDescriptors;
mGains = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioGains(parcelable.gains));
return OK;
}
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
index 65f7388..8ac3f73 100644
--- a/media/libaudiofoundation/AudioProfile.cpp
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -58,10 +58,18 @@
AudioProfile::AudioProfile(audio_format_t format,
const ChannelMaskSet &channelMasks,
const SampleRateSet &samplingRateCollection) :
+ AudioProfile(format, channelMasks, samplingRateCollection,
+ AUDIO_ENCAPSULATION_TYPE_NONE) {}
+
+AudioProfile::AudioProfile(audio_format_t format,
+ const ChannelMaskSet &channelMasks,
+ const SampleRateSet &samplingRateCollection,
+ audio_encapsulation_type_t encapsulationType) :
mName(""),
mFormat(format),
mChannelMasks(channelMasks),
- mSamplingRates(samplingRateCollection) {}
+ mSamplingRates(samplingRateCollection),
+ mEncapsulationType(encapsulationType) {}
void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
{
@@ -116,6 +124,9 @@
}
dst->append("\n");
}
+
+ dst->append(base::StringPrintf(
+ "%*s- encapsulation type: %#x\n", spaces, "", mEncapsulationType));
}
bool AudioProfile::equals(const sp<AudioProfile>& other) const
@@ -127,7 +138,8 @@
mSamplingRates == other->getSampleRates() &&
mIsDynamicFormat == other->isDynamicFormat() &&
mIsDynamicChannels == other->isDynamicChannels() &&
- mIsDynamicRate == other->isDynamicRate();
+ mIsDynamicRate == other->isDynamicRate() &&
+ mEncapsulationType == other->getEncapsulationType();
}
AudioProfile& AudioProfile::operator=(const AudioProfile& other) {
@@ -135,6 +147,7 @@
mFormat = other.mFormat;
mChannelMasks = other.mChannelMasks;
mSamplingRates = other.mSamplingRates;
+ mEncapsulationType = other.mEncapsulationType;
mIsDynamicFormat = other.mIsDynamicFormat;
mIsDynamicChannels = other.mIsDynamicChannels;
mIsDynamicRate = other.mIsDynamicRate;
@@ -160,6 +173,8 @@
parcelable.isDynamicFormat = mIsDynamicFormat;
parcelable.isDynamicChannels = mIsDynamicChannels;
parcelable.isDynamicRate = mIsDynamicRate;
+ parcelable.encapsulationType = VALUE_OR_RETURN(
+ legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(mEncapsulationType));
return parcelable;
}
@@ -186,6 +201,9 @@
legacy->mIsDynamicFormat = parcelable.isDynamicFormat;
legacy->mIsDynamicChannels = parcelable.isDynamicChannels;
legacy->mIsDynamicRate = parcelable.isDynamicRate;
+ legacy->mEncapsulationType = VALUE_OR_RETURN(
+ aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
+ parcelable.encapsulationType));
return legacy;
}
diff --git a/media/libaudiofoundation/include/media/AudioPort.h b/media/libaudiofoundation/include/media/AudioPort.h
index 633e4e3..1cee1c9 100644
--- a/media/libaudiofoundation/include/media/AudioPort.h
+++ b/media/libaudiofoundation/include/media/AudioPort.h
@@ -21,6 +21,7 @@
#include <android/media/AudioPort.h>
#include <android/media/AudioPortConfig.h>
+#include <android/media/ExtraAudioDescriptor.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <media/AudioGain.h>
@@ -67,6 +68,14 @@
void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
AudioProfileVector &getAudioProfiles() { return mProfiles; }
+ void setExtraAudioDescriptors(
+ const std::vector<media::ExtraAudioDescriptor> extraAudioDescriptors) {
+ mExtraAudioDescriptors = extraAudioDescriptors;
+ }
+ std::vector<media::ExtraAudioDescriptor> &getExtraAudioDescriptors() {
+ return mExtraAudioDescriptors;
+ }
+
virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
virtual void importAudioPort(const audio_port_v7& port);
@@ -102,6 +111,10 @@
audio_port_type_t mType;
audio_port_role_t mRole;
AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+
+ // Audio capabilities that are defined by hardware descriptors when the format is unrecognized
+ // by the platform, e.g. short audio descriptor in EDID for HDMI.
+ std::vector<media::ExtraAudioDescriptor> mExtraAudioDescriptors;
private:
template <typename T, std::enable_if_t<std::is_same<T, struct audio_port>::value
|| std::is_same<T, struct audio_port_v7>::value, int> = 0>
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
index 5051233..20c7ab9 100644
--- a/media/libaudiofoundation/include/media/AudioProfile.h
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -38,6 +38,10 @@
AudioProfile(audio_format_t format,
const ChannelMaskSet &channelMasks,
const SampleRateSet &samplingRateCollection);
+ AudioProfile(audio_format_t format,
+ const ChannelMaskSet &channelMasks,
+ const SampleRateSet &samplingRateCollection,
+ audio_encapsulation_type_t encapsulationType);
audio_format_t getFormat() const { return mFormat; }
const ChannelMaskSet &getChannels() const { return mChannelMasks; }
@@ -68,6 +72,11 @@
bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+ audio_encapsulation_type_t getEncapsulationType() const { return mEncapsulationType; }
+ void setEncapsulationType(audio_encapsulation_type_t encapsulationType) {
+ mEncapsulationType = encapsulationType;
+ }
+
void dump(std::string *dst, int spaces) const;
bool equals(const sp<AudioProfile>& other) const;
@@ -79,6 +88,7 @@
static ConversionResult<sp<AudioProfile>> fromParcelable(const media::AudioProfile& parcelable);
private:
+
std::string mName;
audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
ChannelMaskSet mChannelMasks;
@@ -88,6 +98,8 @@
bool mIsDynamicChannels = false;
bool mIsDynamicRate = false;
+ audio_encapsulation_type_t mEncapsulationType;
+
AudioProfile() = default;
AudioProfile& operator=(const AudioProfile& other);
};
diff --git a/media/libmedia/tests/fuzzer/Android.bp b/media/libmedia/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..c03b5b1
--- /dev/null
+++ b/media/libmedia/tests/fuzzer/Android.bp
@@ -0,0 +1,19 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_media_libmedia_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_media_libmedia_license"],
+}
+
+cc_fuzz {
+ name: "libmedia_metadata_fuzzer",
+ srcs: [
+ "libmedia_metadata_fuzzer.cpp",
+ ],
+ shared_libs: [
+ "libmedia",
+ "libbinder",
+ ],
+}
diff --git a/media/libmedia/tests/fuzzer/libmedia_metadata_fuzzer.cpp b/media/libmedia/tests/fuzzer/libmedia_metadata_fuzzer.cpp
new file mode 100644
index 0000000..058e4e5
--- /dev/null
+++ b/media/libmedia/tests/fuzzer/libmedia_metadata_fuzzer.cpp
@@ -0,0 +1,52 @@
+//This program fuzzes Metadata.cpp
+
+#include <stddef.h>
+#include <stdint.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/Metadata.h>
+#include <binder/Parcel.h>
+
+using namespace android;
+using namespace media;
+
+static const float want_prob = 0.5;
+
+bool bytesRemain(FuzzedDataProvider *fdp);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ Parcel p;
+ Metadata md = Metadata(&p);
+
+ md.appendHeader();
+ while (bytesRemain(&fdp)) {
+
+ float got_prob = fdp.ConsumeProbability<float>();
+ if (!bytesRemain(&fdp)) {
+ break;
+ }
+
+ if (got_prob < want_prob) {
+ int32_t key_bool = fdp.ConsumeIntegral<int32_t>();
+ if (!bytesRemain(&fdp)) {
+ break;
+ }
+ bool val_bool = fdp.ConsumeBool();
+ md.appendBool(key_bool, val_bool);
+ } else {
+ int32_t key_int32 = fdp.ConsumeIntegral<int32_t>();
+ if (!bytesRemain(&fdp)) {
+ break;
+ }
+ bool val_int32 = fdp.ConsumeIntegral<int32_t>();
+ md.appendInt32(key_int32, val_int32);
+ }
+ md.updateLength();
+ }
+ md.resetParcel();
+ return 0;
+}
+
+bool bytesRemain(FuzzedDataProvider *fdp){
+ return fdp -> remaining_bytes() > 0;
+}
\ No newline at end of file
diff --git a/media/libmediaformatshaper/Android.bp b/media/libmediaformatshaper/Android.bp
index 731ff4c..3107e12 100644
--- a/media/libmediaformatshaper/Android.bp
+++ b/media/libmediaformatshaper/Android.bp
@@ -16,6 +16,15 @@
// these headers include the structure of needed function pointers
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
cc_library_headers {
name: "libmediaformatshaper_headers",
export_include_dirs: ["include"],
@@ -36,6 +45,7 @@
name: "libmediaformatshaper_defaults",
srcs: [
"CodecProperties.cpp",
+ "CodecSeeding.cpp",
"FormatShaper.cpp",
"ManageShapingCodecs.cpp",
"VideoShaper.cpp",
diff --git a/media/libmediaformatshaper/CodecProperties.cpp b/media/libmediaformatshaper/CodecProperties.cpp
index dccfd95..d733c57 100644
--- a/media/libmediaformatshaper/CodecProperties.cpp
+++ b/media/libmediaformatshaper/CodecProperties.cpp
@@ -26,6 +26,7 @@
namespace mediaformatshaper {
CodecProperties::CodecProperties(std::string name, std::string mediaType) {
+ ALOGV("CodecProperties(%s, %s)", name.c_str(), mediaType.c_str());
mName = name;
mMediaType = mediaType;
}
@@ -58,6 +59,38 @@
return mApi;
}
+void CodecProperties::setFeatureValue(std::string key, int32_t value) {
+ ALOGD("setFeatureValue(%s,%d)", key.c_str(), value);
+ mFeatures.insert({key, value});
+
+ if (!strcmp(key.c_str(), "vq-minimum-quality")) {
+ setSupportedMinimumQuality(value);
+ } else if (!strcmp(key.c_str(), "vq-supports-qp")) { // key from prototyping
+ setSupportsQp(1);
+ } else if (!strcmp(key.c_str(), "qp-bounds")) { // official key
+ setSupportsQp(1);
+ } else if (!strcmp(key.c_str(), "vq-target-qpmax")) {
+ setTargetQpMax(value);
+ } else if (!strcmp(key.c_str(), "vq-target-bppx100")) {
+ double bpp = value / 100.0;
+ setBpp(bpp);
+ }
+}
+
+bool CodecProperties::getFeatureValue(std::string key, int32_t *valuep) {
+ ALOGV("getFeatureValue(%s)", key.c_str());
+ if (valuep == nullptr) {
+ return false;
+ }
+ auto mapped = mFeatures.find(key);
+ if (mapped != mFeatures.end()) {
+ *valuep = mapped->second;
+ return true;
+ }
+ return false;
+}
+
+
std::string CodecProperties::getMapping(std::string key, std::string kind) {
ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str());
//play with mMappings
diff --git a/media/libmediaformatshaper/CodecSeeding.cpp b/media/libmediaformatshaper/CodecSeeding.cpp
new file mode 100644
index 0000000..629b405
--- /dev/null
+++ b/media/libmediaformatshaper/CodecSeeding.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CodecSeeding"
+#include <utils/Log.h>
+
+#include <string>
+
+#include <media/formatshaper/CodecProperties.h>
+
+namespace android {
+namespace mediaformatshaper {
+
+/*
+ * a block of pre-loads; things the library seeds into the codecproperties based
+ * on the mediaType.
+ * XXX: parsing from a file is likely better than embedding in code.
+ */
+typedef struct {
+ const char *key;
+ int32_t value;
+} preloadFeature_t;
+
+typedef struct {
+ const char *mediaType;
+ preloadFeature_t *features;
+} preloadProperties_t;
+
+/*
+ * 240 = 2.4 bits per pixel-per-second == 5mbps@1080, 2.3mbps@720p, which is about where
+ * we want our initial floor for now.
+ */
+
+static preloadFeature_t featuresAvc[] = {
+ {"vq-target-bppx100", 240},
+ {nullptr, 0}
+};
+
+static preloadFeature_t featuresHevc[] = {
+ {"vq-target-bppx100", 240},
+ {nullptr, 0}
+};
+
+static preloadFeature_t featuresGenericVideo[] = {
+ {"vq-target-bppx100", 240},
+ {nullptr, 0}
+};
+
+static preloadProperties_t preloadProperties[] = {
+ { "video/avc", featuresAvc},
+ { "video/hevc", &featuresHevc[0]},
+
+ // wildcard for any video format not already captured
+ { "video/*", &featuresGenericVideo[0]},
+ { nullptr, nullptr}
+};
+
+void CodecProperties::Seed() {
+ ALOGV("Seed: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str());
+
+ // load me up with initial configuration data
+ int count = 0;
+ for (int i=0;; i++) {
+ preloadProperties_t *p = &preloadProperties[i];
+ if (p->mediaType == nullptr) {
+ break;
+ }
+ bool found = false;
+ if (strcmp(p->mediaType, mMediaType.c_str()) == 0) {
+ found = true;
+ }
+ const char *r;
+ if (!found && (r = strchr(p->mediaType, '*')) != NULL) {
+ // wildcard; check the prefix
+ size_t len = r - p->mediaType;
+ if (strncmp(p->mediaType, mMediaType.c_str(), len) == 0) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ continue;
+ }
+ ALOGV("seeding from mediaType '%s'", p->mediaType);
+
+ // walk through, filling things
+ if (p->features != nullptr) {
+ for (int j=0;; j++) {
+ preloadFeature_t *q = &p->features[j];
+ if (q->key == nullptr) {
+ break;
+ }
+ setFeatureValue(q->key, q->value);
+ count++;
+ }
+ break;
+ }
+ }
+ ALOGV("loaded %d preset values", count);
+}
+
+// a chance, as we register the codec and accept no further updates, to
+// override any poor configuration that arrived from the device's XML files.
+//
+void CodecProperties::Finish() {
+ ALOGV("Finish: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str());
+
+ // currently a no-op
+}
+
+} // namespace mediaformatshaper
+} // namespace android
+
diff --git a/media/libmediaformatshaper/FormatShaper.cpp b/media/libmediaformatshaper/FormatShaper.cpp
index ca4dc72..a52edc2 100644
--- a/media/libmediaformatshaper/FormatShaper.cpp
+++ b/media/libmediaformatshaper/FormatShaper.cpp
@@ -93,19 +93,9 @@
return -1;
}
- if (!strcmp(feature, "vq-minimum-quality")) {
- codec->setSupportedMinimumQuality(value);
- } else if (!strcmp(feature, "vq-supports-qp")) {
- codec->setSupportsQp(value != 0);
- } else if (!strcmp(feature, "vq-target-qpmax")) {
- codec->setTargetQpMax(value);
- } else if (!strcmp(feature, "vq-target-bppx100")) {
- double bpp = value / 100.0;
- codec->setBpp(bpp);
- } else {
- // changed nothing, don't mark as configured
- return 0;
- }
+ // save a map of all features
+ codec->setFeatureValue(feature, value);
+
return 0;
}
@@ -120,6 +110,9 @@
shaperHandle_t createShaper(const char *codecName, const char *mediaType) {
CodecProperties *codec = new CodecProperties(codecName, mediaType);
+ if (codec != nullptr) {
+ codec->Seed();
+ }
return (shaperHandle_t) codec;
}
@@ -134,6 +127,12 @@
return nullptr;
}
+ // any final cleanup for the parameters. This allows us to override
+ // bad parameters from a devices XML file.
+ codec->Finish();
+
+ // may return a different codec, if we lost a race.
+ // if so, registerCodec() reclaims the one we tried to register for us.
codec = registerCodec(codec, codecName, mediaType);
return (shaperHandle_t) codec;
}
diff --git a/media/libmediaformatshaper/VQApply.cpp b/media/libmediaformatshaper/VQApply.cpp
index 6f6f33c..39a5e19 100644
--- a/media/libmediaformatshaper/VQApply.cpp
+++ b/media/libmediaformatshaper/VQApply.cpp
@@ -44,42 +44,60 @@
#define AMEDIAFORMAT_VIDEO_QP_P_MAX "video-qp-p-max"
#define AMEDIAFORMAT_VIDEO_QP_P_MIN "video-qp-p-min"
+// defined in the SDK, but not in the NDK
+//
+static const int BITRATE_MODE_VBR = 1;
+
//
// Caller retains ownership of and responsibility for inFormat
//
int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) {
ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags);
- if (codec->supportedMinimumQuality() > 0) {
- // allow the codec provided minimum quality behavior to work at it
- ALOGD("minquality(codec): codec says %d", codec->supportedMinimumQuality());
+ int32_t bitRateMode = -1;
+ if (AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_KEY_BITRATE_MODE, &bitRateMode)
+ && bitRateMode != BITRATE_MODE_VBR) {
+ ALOGD("minquality: applies only to VBR encoding");
return 0;
}
- ALOGD("considering other ways to improve quality...");
+ if (codec->supportedMinimumQuality() > 0) {
+ // allow the codec provided minimum quality behavior to work at it
+ ALOGD("minquality: codec claims to implement minquality=%d",
+ codec->supportedMinimumQuality());
+ return 0;
+ }
//
// apply any and all tools that we have.
// -- qp
// -- minimum bits-per-pixel
//
- if (codec->supportsQp()) {
+ if (!codec->supportsQp()) {
+ ALOGD("minquality: no qp bounding in codec %s", codec->getName().c_str());
+ } else {
// use a (configurable) QP value to force better quality
//
- // XXX: augment this so that we don't lower an existing QP setting
- // (e.g. if user set it to 40, we don't want to set it back to 45)
- int qpmax = codec->targetQpMax();
- if (qpmax <= 0) {
- qpmax = 45;
- ALOGD("use default substitute QpMax == %d", qpmax);
+ int32_t qpmax = codec->targetQpMax();
+ int32_t qpmaxUser = INT32_MAX;
+ if (hasQp(inFormat)) {
+ (void) AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, &qpmaxUser);
+ ALOGD("minquality by QP: format already sets QP");
}
- ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);
- AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);
- // force spreading the QP across frame types, since we imposing a value
- qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true);
- } else {
- ALOGD("codec %s: no qp bounding", codec->getName().c_str());
+ // if the system didn't do one, use what the user provided
+ if (qpmax == 0 && qpmaxUser != INT32_MAX) {
+ qpmax = qpmaxUser;
+ }
+ // XXX: if both said something, how do we want to reconcile that
+
+ if (qpmax > 0) {
+ ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);
+ AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);
+
+ // force spreading the QP across frame types, since we imposing a value
+ qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true);
+ }
}
double bpp = codec->getBpp();
@@ -108,7 +126,7 @@
bitrateConfigured, bitrateFloor, codec->getBpp(), height, width);
if (bitrateConfigured < bitrateFloor) {
- ALOGD("minquality/target bitrate raised from %d to %" PRId64 " to maintain quality",
+ ALOGD("minquality/target bitrate raised from %d to %" PRId64 " bps",
bitrateConfigured, bitrateFloor);
AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateFloor);
}
@@ -121,16 +139,16 @@
bool hasQpPerFrameType(AMediaFormat *format) {
int32_t value;
- if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value)
- || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) {
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value)
+ || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) {
return true;
}
- if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value)
- || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) {
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value)
+ || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) {
return true;
}
- if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value)
- || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) {
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value)
+ || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) {
return true;
}
return false;
@@ -138,8 +156,8 @@
bool hasQp(AMediaFormat *format) {
int32_t value;
- if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value)
- || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) {
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value)
+ || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) {
return true;
}
return hasQpPerFrameType(format);
diff --git a/media/libmediaformatshaper/VideoShaper.cpp b/media/libmediaformatshaper/VideoShaper.cpp
index fecd3a1..f772a66 100644
--- a/media/libmediaformatshaper/VideoShaper.cpp
+++ b/media/libmediaformatshaper/VideoShaper.cpp
@@ -83,7 +83,7 @@
// apply any quality transforms in here..
(void) VQApply(codec, info, inFormat, flags);
- // We must always spread and map any QP parameters.
+ // We must always spread any QP parameters.
// Sometimes it's something we inserted here, sometimes it's a value that the user injected.
//
qpSpreadPerFrameType(inFormat, info->qpDelta, info->qpMin, info->qpMax, /* override */ false);
diff --git a/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h b/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
index f7177a4..e5cc9cf 100644
--- a/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
+++ b/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
@@ -31,6 +31,12 @@
public:
CodecProperties(std::string name, std::string mediaType);
+ // seed the codec with some preconfigured values
+ // (e.g. mediaType-granularity defaults)
+ // runs from the constructor
+ void Seed();
+ void Finish();
+
std::string getName();
std::string getMediaType();
@@ -46,8 +52,9 @@
// and 'reverse' describes which strings are to be on which side.
const char **getMappings(std::string kind, bool reverse);
- // debugging of what's in the mapping dictionary
- void showMappings();
+ // keep a map of all features and their parameters
+ void setFeatureValue(std::string key, int32_t value);
+ bool getFeatureValue(std::string key, int32_t *valuep);
// does the codec support the Android S minimum quality rules
void setSupportedMinimumQuality(int vmaf);
@@ -88,10 +95,14 @@
std::mutex mMappingLock;
// XXX figure out why I'm having problems getting compiler to like GUARDED_BY
std::map<std::string, std::string> mMappings /*GUARDED_BY(mMappingLock)*/ ;
- std::map<std::string, std::string> mUnMappings /*GUARDED_BY(mMappingLock)*/ ;
+
+ std::map<std::string, int32_t> mFeatures /*GUARDED_BY(mMappingLock)*/ ;
bool mIsRegistered = false;
+ // debugging of what's in the mapping dictionary
+ void showMappings();
+
// DISALLOW_EVIL_CONSTRUCTORS(CodecProperties);
};
diff --git a/media/libmediaplayerservice/nuplayer/AWakeLock.cpp b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
index 7bee002..af9cf45 100644
--- a/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
+++ b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
@@ -62,7 +62,7 @@
binder::Status status = mPowerManager->acquireWakeLock(
binder, POWERMANAGER_PARTIAL_WAKE_LOCK,
String16("AWakeLock"), String16("media"),
- {} /* workSource */, {} /* historyTag */);
+ {} /* workSource */, {} /* historyTag */, -1 /* displayId */);
IPCThreadState::self()->restoreCallingIdentity(token);
if (status.isOk()) {
mWakeLockToken = binder;
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index a063565..b19e711 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -366,6 +366,12 @@
return AMEDIA_ERROR_INVALID_OPERATION;
}
+ // Unwrap the callback and send heartbeats to the client after each operation during setup.
+ auto callback = mCallback.lock();
+ if (callback == nullptr) {
+ return AMEDIA_ERROR_INVALID_OPERATION;
+ }
+
Status status;
::ndk::ScopedFileDescriptor srcFd, dstFd;
int srcFdInt = request.sourceFd.get();
@@ -379,6 +385,8 @@
srcFdInt = srcFd.get();
}
+ callback->onHeartBeat(clientId, sessionId);
+
int dstFdInt = request.destinationFd.get();
if (dstFdInt < 0) {
// Open dest file with "rw", as the transcoder could potentially reuse part of it
@@ -393,6 +401,8 @@
dstFdInt = dstFd.get();
}
+ callback->onHeartBeat(clientId, sessionId);
+
mCurrentClientId = clientId;
mCurrentSessionId = sessionId;
mCurrentCallingUid = callingUid;
@@ -405,6 +415,8 @@
return AMEDIA_ERROR_UNKNOWN;
}
+ callback->onHeartBeat(clientId, sessionId);
+
media_status_t err = mTranscoder->configureSource(srcFdInt);
if (err != AMEDIA_OK) {
ALOGE("failed to configure source: %d", err);
@@ -412,6 +424,8 @@
return err;
}
+ callback->onHeartBeat(clientId, sessionId);
+
std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
if (trackFormats.size() == 0) {
ALOGE("failed to get track formats!");
@@ -419,6 +433,8 @@
return AMEDIA_ERROR_MALFORMED;
}
+ callback->onHeartBeat(clientId, sessionId);
+
for (int i = 0; i < trackFormats.size(); ++i) {
std::shared_ptr<AMediaFormat> format;
const char* mime = nullptr;
@@ -437,6 +453,8 @@
*failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
return err;
}
+
+ callback->onHeartBeat(clientId, sessionId);
}
err = mTranscoder->configureDestination(dstFdInt);
@@ -446,6 +464,8 @@
return err;
}
+ callback->onHeartBeat(clientId, sessionId);
+
return AMEDIA_OK;
}
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index 88c1c42..10b2e80 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -328,8 +328,8 @@
}
lastProgressUpdate = progress;
}
- progressSinceLastReport = true;
}
+ progressSinceLastReport = true;
}
return AMEDIA_OK;
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index 413f049..879241e 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -158,6 +158,11 @@
return;
}
+ // The sample writer is not yet started so notify the caller that progress is still made.
+ if (mHeartBeatIntervalUs > 0) {
+ mCallbacks->onHeartBeat(this);
+ }
+
MediaTrackTranscoder* mutableTranscoder = const_cast<MediaTrackTranscoder*>(transcoder);
mutableTranscoder->setSampleConsumer(consumer);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index be21a5d..26cdec8 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1390,6 +1390,11 @@
return msg->post();
}
+/*
+ * MediaFormat Shaping forward declarations
+ * including the property name we use for control.
+ */
+static const char enableMediaFormatShapingProperty[] = "debug.stagefright.enableshaping";
static void mapFormat(AString componentName, const sp<AMessage> &format, const char *kind,
bool reverse);
@@ -1463,15 +1468,13 @@
}
}
- // apply framework level modifications to the mediaformat for encoding
- // XXX: default off for a while during dogfooding
- static const char *enable_property = "debug.stagefright.enableshaping";
- int8_t enableShaping = property_get_bool(enable_property, 0);
- if (!enableShaping) {
- ALOGD("format shaping disabled via property '%s'", enable_property);
- } else {
- if (flags & CONFIGURE_FLAG_ENCODE) {
+ if (flags & CONFIGURE_FLAG_ENCODE) {
+ int8_t enableShaping = property_get_bool(enableMediaFormatShapingProperty, 0);
+ if (!enableShaping) {
+ ALOGI("format shaping disabled, property '%s'", enableMediaFormatShapingProperty);
+ } else {
(void) shapeMediaFormat(format, flags);
+ // XXX: do we want to do this regardless of shaping enablement?
mapFormat(mComponentName, format, nullptr, false);
}
}
@@ -1552,10 +1555,25 @@
static bool connectFormatShaper() {
static std::once_flag sCheckOnce;
- static void *libHandle = NULL;
+
+#if 0
+ // an early return if the property says disabled means we skip loading.
+ // that saves memory.
+
+ // apply framework level modifications to the mediaformat for encoding
+ // XXX: default off for a while during dogfooding
+ int8_t enableShaping = property_get_bool(enableMediaFormatShapingProperty, 0);
+
+ if (!enableShaping) {
+ return true;
+ }
+#endif
std::call_once(sCheckOnce, [&](){
+ void *libHandle = NULL;
+ nsecs_t loading_started = systemTime(SYSTEM_TIME_MONOTONIC);
+
// prefer any copy in the mainline module
//
android_namespace_t *mediaNs = android_get_exported_namespace("com_android_media");
@@ -1614,44 +1632,33 @@
ALOGV("connectFormatShaper: connected to library %s", libraryName.c_str());
}
+ nsecs_t loading_finished = systemTime(SYSTEM_TIME_MONOTONIC);
+ ALOGV("connectFormatShaper: loaded libraries: %" PRId64 " us",
+ (loading_finished - loading_started)/1000);
+
});
return true;
}
+
+#if 0
// a construct to force the above dlopen() to run very early.
// goal: so the dlopen() doesn't happen on critical path of latency sensitive apps
// failure of this means that cold start of those apps is slower by the time to dlopen()
+// TODO(b/183454066): tradeoffs between memory of early loading vs latency of late loading
//
static bool forceEarlyLoadingShaper = connectFormatShaper();
+#endif
// parse the codec's properties: mapping, whether it meets min quality, etc
// and pass them into the video quality code
//
-status_t MediaCodec::setupFormatShaper(AString mediaType) {
- ALOGV("setupFormatShaper: initializing shaper data for codec %s mediaType %s",
- mComponentName.c_str(), mediaType.c_str());
-
- nsecs_t mapping_started = systemTime(SYSTEM_TIME_MONOTONIC);
-
- // see if the shaper is already present, if so return
- mediaformatshaper::shaperHandle_t shaperHandle;
- shaperHandle = sShaperOps->findShaper(mComponentName.c_str(), mediaType.c_str());
- if (shaperHandle != nullptr) {
- ALOGV("shaperhandle %p -- no initialization needed", shaperHandle);
- return OK;
- }
-
- // not there, so we get to build & register one
- shaperHandle = sShaperOps->createShaper(mComponentName.c_str(), mediaType.c_str());
- if (shaperHandle == nullptr) {
- ALOGW("unable to create a shaper for cocodec %s mediaType %s",
- mComponentName.c_str(), mediaType.c_str());
- return OK;
- }
+static void loadCodecProperties(mediaformatshaper::shaperHandle_t shaperHandle,
+ sp<MediaCodecInfo> codecInfo, AString mediaType) {
sp<MediaCodecInfo::Capabilities> capabilities =
- mCodecInfo->getCapabilitiesFor(mediaType.c_str());
+ codecInfo->getCapabilitiesFor(mediaType.c_str());
if (capabilities == nullptr) {
ALOGI("no capabilities as part of the codec?");
} else {
@@ -1697,11 +1704,37 @@
}
}
}
+}
+
+status_t MediaCodec::setupFormatShaper(AString mediaType) {
+ ALOGV("setupFormatShaper: initializing shaper data for codec %s mediaType %s",
+ mComponentName.c_str(), mediaType.c_str());
+
+ nsecs_t mapping_started = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // someone might have beaten us to it.
+ mediaformatshaper::shaperHandle_t shaperHandle;
+ shaperHandle = sShaperOps->findShaper(mComponentName.c_str(), mediaType.c_str());
+ if (shaperHandle != nullptr) {
+ ALOGV("shaperhandle %p -- no initialization needed", shaperHandle);
+ return OK;
+ }
+
+ // we get to build & register one
+ shaperHandle = sShaperOps->createShaper(mComponentName.c_str(), mediaType.c_str());
+ if (shaperHandle == nullptr) {
+ ALOGW("unable to create a shaper for cocodec %s mediaType %s",
+ mComponentName.c_str(), mediaType.c_str());
+ return OK;
+ }
+
+ (void) loadCodecProperties(shaperHandle, mCodecInfo, mediaType);
+
shaperHandle = sShaperOps->registerShaper(shaperHandle,
mComponentName.c_str(), mediaType.c_str());
nsecs_t mapping_finished = systemTime(SYSTEM_TIME_MONOTONIC);
- ALOGD("setupFormatShaper: populated shaper node for codec %s: %" PRId64 " us",
+ ALOGV("setupFormatShaper: populated shaper node for codec %s: %" PRId64 " us",
mComponentName.c_str(), (mapping_finished - mapping_started)/1000);
return OK;
@@ -1791,9 +1824,12 @@
// make sure we have the function entry points for the shaper library
//
+#if 0
+ // let's play the faster "only do mapping if we've already loaded the library
connectFormatShaper();
+#endif
if (sShaperOps == nullptr) {
- ALOGW("mapFormat: no MediaFormatShaper hooks available");
+ ALOGV("mapFormat: no MediaFormatShaper hooks available");
return;
}
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index d77845f..2520e2a 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -253,6 +253,7 @@
(GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
if (getDef == nullptr) {
ALOGI("no sniffer found in %s", libPath.string());
+ dlclose(libHandle);
continue;
}
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index dd2eed3..a15a988 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -274,6 +274,9 @@
<Limit name="bitrate" range="1-2000000" />
</Variant>
<Feature name="intra-refresh" />
+ <!-- Video Quality control -->
+ <!-- supports QP bounding with standard keys -->
+ <Feature name="qp-bounds" />
</MediaCodec>
<MediaCodec name="c2.android.vp8.encoder" type="video/x-vnd.on2.vp8" variant="slow-cpu,!slow-cpu">
<Alias name="OMX.google.vp8.encoder" />
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 6678287..7a89805 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -199,10 +199,21 @@
mDeviceEffectManager(this),
mSystemReady(false)
{
+ // Move the audio session unique ID generator start base as time passes to limit risk of
+ // generating the same ID again after an audioserver restart.
+ // This is important because clients will reuse previously allocated audio session IDs
+ // when reconnecting after an audioserver restart and newly allocated IDs may conflict with
+ // active clients.
+ // Moving the base by 1 for each elapsed second is a good compromise between avoiding overlap
+ // between allocation ranges and not reaching wrap around too soon.
+ timespec ts{};
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ // zero ID has a special meaning, so start allocation at least at AUDIO_UNIQUE_ID_USE_MAX
+ uint32_t sessionBase = (uint32_t)std::max((long)1, ts.tv_sec);
// unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use < AUDIO_UNIQUE_ID_USE_MAX; use++) {
- // zero ID has a special meaning, so unavailable
- mNextUniqueIds[use] = AUDIO_UNIQUE_ID_USE_MAX;
+ mNextUniqueIds[use] =
+ ((use == AUDIO_UNIQUE_ID_USE_SESSION) ? sessionBase : 1) * AUDIO_UNIQUE_ID_USE_MAX;
}
#if 1
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index ca9b747..2e59baa 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -336,7 +336,7 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
- android::media::permission::Identity& identity);
+ const android::media::permission::Identity& identity);
virtual ~OutputTrack();
virtual status_t start(AudioSystem::sync_event_t event =
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 4d03441..5f248e1 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -147,7 +147,6 @@
// used to enforce OP_RECORD_AUDIO
uid_t mUid;
- media::permission::Identity mIdentity;
sp<OpRecordAudioMonitor> mOpRecordAudioMonitor;
};
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index efcdb51..db7528d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -239,9 +239,10 @@
}
// TODO b/182392769: use identity util
-Identity audioServerIdentity() {
- Identity i = Identity();
+static Identity audioServerIdentity(pid_t pid) {
+ Identity i{};
i.uid = AID_AUDIOSERVER;
+ i.pid = pid;
return i;
}
@@ -1846,7 +1847,7 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
- Identity& identity)
+ const Identity& identity)
: Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
audio_attributes_t{} /* currently unused for output track */,
sampleRate, format, channelMask, frameCount,
@@ -2081,7 +2082,7 @@
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, nullptr /* sharedBuffer */,
- AUDIO_SESSION_NONE, getpid(), audioServerIdentity(), flags,
+ AUDIO_SESSION_NONE, getpid(), audioServerIdentity(getpid()), flags,
TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true),
*playbackThread, timeout)
@@ -2414,7 +2415,7 @@
mRecordBufferConverter(NULL),
mFlags(flags),
mSilenced(false),
- mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(mIdentity, attr))
+ mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(identity, attr))
{
if (mCblk == NULL) {
return;
@@ -2455,9 +2456,7 @@
#endif
// Once this item is logged by the server, the client can add properties.
- pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mIdentity.pid));
- uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mIdentity.uid));
- mTrackMetrics.logConstructor(pid, uid, id());
+ mTrackMetrics.logConstructor(creatorPid, uid(), id());
}
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
@@ -2729,11 +2728,10 @@
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, AUDIO_SESSION_NONE, getpid(),
- audioServerIdentity(), flags, TYPE_PATCH),
+ audioServerIdentity(getpid()), flags, TYPE_PATCH),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true),
*recordThread, timeout)
{
- mIdentity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
ALOGV("%s(%d): sampleRate %d mPeerTimeout %d.%03d sec",
__func__, mId, sampleRate,
(int)mPeerTimeout.tv_sec,
@@ -3023,8 +3021,7 @@
mSilenced(false), mSilencedNotified(false)
{
// Once this item is logged by the server, the client can add properties.
- mTrackMetrics.logConstructor(creatorPid,
- VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)), id());
+ mTrackMetrics.logConstructor(creatorPid, uid(), id());
}
AudioFlinger::MmapThread::MmapTrack::~MmapTrack()
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 380bf6b..1a903a6 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -144,9 +144,10 @@
void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
DeviceVector& availableOutputDevices,
- const DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs) const
{
+ DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+
switch (strategy) {
case STRATEGY_SONIFICATION_RESPECTFUL: {
if (!(isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
@@ -204,9 +205,49 @@
}
}
+product_strategy_t Engine::remapStrategyFromContext(product_strategy_t strategy,
+ const SwAudioOutputCollection &outputs) const {
+ auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
+ mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
+
+ if (isInCall()) {
+ switch (legacyStrategy) {
+ case STRATEGY_ACCESSIBILITY:
+ case STRATEGY_DTMF:
+ case STRATEGY_MEDIA:
+ case STRATEGY_SONIFICATION:
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ legacyStrategy = STRATEGY_PHONE;
+ break;
+
+ default:
+ return strategy;
+ }
+ } else {
+ switch (legacyStrategy) {
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ case STRATEGY_SONIFICATION:
+ if (outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
+ legacyStrategy = STRATEGY_PHONE;
+ }
+ break;
+
+ case STRATEGY_ACCESSIBILITY:
+ if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
+ outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
+ legacyStrategy = STRATEGY_SONIFICATION;
+ }
+ break;
+
+ default:
+ return strategy;
+ }
+ }
+ return getProductStrategyFromLegacy(legacyStrategy);
+}
+
DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
- DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs) const
{
DeviceVector devices;
@@ -217,32 +258,6 @@
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
break;
- case STRATEGY_SONIFICATION_RESPECTFUL:
- if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
- devices = getDevicesForStrategyInt(
- STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
- } else {
- bool media_active_locally =
- outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
- SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
- || outputs.isActiveLocally(
- toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
- SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
- devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
- availableOutputDevices,
- availableInputDevices, outputs);
- // if no media is playing on the device, check for mandatory use of "safe" speaker
- // when media would have played on speaker, and the safe speaker path is available
- if (!media_active_locally) {
- devices.replaceDevicesByType(
- AUDIO_DEVICE_OUT_SPEAKER,
- availableOutputDevices.getDevicesFromType(
- AUDIO_DEVICE_OUT_SPEAKER_SAFE));
- }
- }
- break;
-
- case STRATEGY_DTMF:
case STRATEGY_PHONE: {
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
if (!devices.isEmpty()) break;
@@ -257,16 +272,6 @@
} break;
case STRATEGY_SONIFICATION:
-
- // If incall, just select the STRATEGY_PHONE device
- if (isInCall() ||
- outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
- devices = getDevicesForStrategyInt(
- STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
- break;
- }
- FALLTHROUGH_INTENDED;
-
case STRATEGY_ENFORCED_AUDIBLE:
// strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
// except:
@@ -314,22 +319,9 @@
// The second device used for sonification is the same as the device used by media strategy
FALLTHROUGH_INTENDED;
+ case STRATEGY_DTMF:
case STRATEGY_ACCESSIBILITY:
- if (strategy == STRATEGY_ACCESSIBILITY) {
- if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
- outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
- return getDevicesForStrategyInt(
- STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
- }
- if (isInCall()) {
- return getDevicesForStrategyInt(
- STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
- }
- }
- // For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
- FALLTHROUGH_INTENDED;
-
- // FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
+ case STRATEGY_SONIFICATION_RESPECTFUL:
case STRATEGY_REROUTING:
case STRATEGY_MEDIA: {
DeviceVector devices2;
@@ -342,11 +334,6 @@
devices2.add(remoteSubmix);
}
}
- if (isInCall() && (strategy == STRATEGY_MEDIA)) {
- devices = getDevicesForStrategyInt(
- STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
- break;
- }
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
@@ -394,9 +381,19 @@
devices.remove(devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
}
- // for STRATEGY_SONIFICATION:
+ bool mediaActiveLocally =
+ outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
+ || outputs.isActiveLocally(
+ toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
+ // - for STRATEGY_SONIFICATION:
// if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
- if (strategy == STRATEGY_SONIFICATION) {
+ // - for STRATEGY_SONIFICATION_RESPECTFUL:
+ // if no media is playing on the device, check for mandatory use of "safe" speaker
+ // when media would have played on speaker, and the safe speaker path is available
+ if (strategy == STRATEGY_SONIFICATION
+ || (strategy == STRATEGY_SONIFICATION_RESPECTFUL && !mediaActiveLocally)) {
devices.replaceDevicesByType(
AUDIO_DEVICE_OUT_SPEAKER,
availableOutputDevices.getDevicesFromType(
@@ -649,22 +646,20 @@
return preferredAvailableDevVec;
}
+
DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const {
- DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
+ const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
+
+ // Take context into account to remap product strategy before
+ // checking preferred device for strategy and applying default routing rules
+ strategy = remapStrategyFromContext(strategy, outputs);
+
auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
- // When not in call, STRATEGY_DTMF follows STRATEGY_MEDIA
- if (!isInCall() && legacyStrategy == STRATEGY_DTMF) {
- legacyStrategy = STRATEGY_MEDIA;
- strategy = getProductStrategyFromLegacy(STRATEGY_MEDIA);
- }
+ DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
- DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
- const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
-
- filterOutputDevicesForStrategy(legacyStrategy, availableOutputDevices,
- availableInputDevices, outputs);
+ filterOutputDevicesForStrategy(legacyStrategy, availableOutputDevices, outputs);
// check if this strategy has a preferred device that is available,
// if yes, give priority to it.
@@ -676,7 +671,7 @@
return getDevicesForStrategyInt(legacyStrategy,
availableOutputDevices,
- availableInputDevices, outputs);
+ outputs);
}
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 6dc6cd0..98f59d3 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -76,12 +76,13 @@
void filterOutputDevicesForStrategy(legacy_strategy strategy,
DeviceVector& availableOutputDevices,
- const DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs) const;
+
+ product_strategy_t remapStrategyFromContext(product_strategy_t strategy,
const SwAudioOutputCollection &outputs) const;
DeviceVector getDevicesForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
- DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs) const;
DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 99d10d2..6cd20a1 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -743,7 +743,7 @@
return Status::ok();
}
-int CameraService::getDeviceVersion(const String8& cameraId, int* facing) {
+int CameraService::getDeviceVersion(const String8& cameraId, int* facing, int* orientation) {
ATRACE_CALL();
int deviceVersion = 0;
@@ -760,6 +760,9 @@
res = mCameraProviderManager->getCameraInfo(cameraId.string(), &info);
if (res != OK) return -1;
*facing = info.facing;
+ if (orientation) {
+ *orientation = info.orientation;
+ }
}
return deviceVersion;
@@ -1555,6 +1558,7 @@
sp<CLIENT> client = nullptr;
int facing = -1;
+ int orientation = 0;
bool isNdk = (clientPackageName.size() == 0);
{
// Acquire mServiceLock and prevent other clients from connecting
@@ -1620,7 +1624,7 @@
// give flashlight a chance to close devices if necessary.
mFlashlight->prepareDeviceOpen(cameraId);
- int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing);
+ int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing, /*out*/&orientation);
if (facing == -1) {
ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.string());
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
@@ -1688,6 +1692,9 @@
// Set rotate-and-crop override behavior
if (mOverrideRotateAndCropMode != ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
client->setRotateAndCropOverride(mOverrideRotateAndCropMode);
+ } else if (CameraServiceProxyWrapper::isRotateAndCropOverrideNeeded(clientPackageName,
+ orientation, facing)) {
+ client->setRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_90);
}
// Set camera muting behavior
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index dbfc6c3..092d916 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -213,7 +213,8 @@
/////////////////////////////////////////////////////////////////////
// CameraDeviceFactory functionality
- int getDeviceVersion(const String8& cameraId, int* facing = NULL);
+ int getDeviceVersion(const String8& cameraId, int* facing = nullptr,
+ int* orientation = nullptr);
/////////////////////////////////////////////////////////////////////
// Shared utilities
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index 4c3ded6..ee764ec 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -158,7 +158,7 @@
res = device->createStream(mCallbackWindow,
params.previewWidth, params.previewHeight, callbackFormat,
HAL_DATASPACE_V0_JFIF, CAMERA_STREAM_ROTATION_0, &mCallbackStreamId,
- String8());
+ String8(), std::unordered_set<int32_t>{ANDROID_SENSOR_PIXEL_MODE_DEFAULT});
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index ff2e398..eed2654 100755
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -151,7 +151,7 @@
params.pictureWidth, params.pictureHeight,
HAL_PIXEL_FORMAT_BLOB, HAL_DATASPACE_V0_JFIF,
CAMERA_STREAM_ROTATION_0, &mCaptureStreamId,
- String8());
+ String8(), std::unordered_set<int32_t>{ANDROID_SENSOR_PIXEL_MODE_DEFAULT});
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for capture: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 3a709c9..02ac638 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -56,7 +56,7 @@
int previewTransform; // set by CAMERA_CMD_SET_DISPLAY_ORIENTATION
int pictureWidth, pictureHeight;
- // Store the picture size before they are overriden by video snapshot
+ // Store the picture size before they are overridden by video snapshot
int pictureWidthLastSet, pictureHeightLastSet;
bool pictureSizeOverriden;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 8b1eb28..2d3597c 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -198,7 +198,8 @@
res = device->createStream(mPreviewWindow,
params.previewWidth, params.previewHeight,
CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_UNKNOWN,
- CAMERA_STREAM_ROTATION_0, &mPreviewStreamId, String8());
+ CAMERA_STREAM_ROTATION_0, &mPreviewStreamId, String8(),
+ std::unordered_set<int32_t>{ANDROID_SENSOR_PIXEL_MODE_DEFAULT});
if (res != OK) {
ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -384,7 +385,7 @@
params.videoWidth, params.videoHeight,
params.videoFormat, params.videoDataSpace,
CAMERA_STREAM_ROTATION_0, &mRecordingStreamId,
- String8());
+ String8(), std::unordered_set<int32_t>{ANDROID_SENSOR_PIXEL_MODE_DEFAULT});
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for recording: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 9fdc727..8e598f1 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -261,7 +261,7 @@
res = device->createStream(outSurface, params.fastInfo.maxZslSize.width,
params.fastInfo.maxZslSize.height, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
HAL_DATASPACE_UNKNOWN, CAMERA_STREAM_ROTATION_0, &mZslStreamId,
- String8());
+ String8(), std::unordered_set<int32_t>{ANDROID_SENSOR_PIXEL_MODE_DEFAULT});
if (res != OK) {
ALOGE("%s: Camera %d: Can't create ZSL stream: "
"%s (%d)", __FUNCTION__, client->getCameraId(),
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 8cccbb1..1b65d1a 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -125,8 +125,8 @@
/*listener*/this,
/*sendPartials*/true);
- auto deviceInfo = mDevice->info();
- camera_metadata_entry_t physicalKeysEntry = deviceInfo.find(
+ const CameraMetadata &deviceInfo = mDevice->info();
+ camera_metadata_ro_entry_t physicalKeysEntry = deviceInfo.find(
ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
if (physicalKeysEntry.count > 0) {
mSupportedPhysicalRequestKeys.insert(mSupportedPhysicalRequestKeys.begin(),
@@ -135,6 +135,17 @@
}
mProviderManager = providerPtr;
+ // Cache physical camera ids corresponding to this device and also the high
+ // resolution sensors in this device + physical camera ids
+ mProviderManager->isLogicalCamera(mCameraIdStr.string(), &mPhysicalCameraIds);
+ if (isUltraHighResolutionSensor(mCameraIdStr)) {
+ mHighResolutionSensors.insert(mCameraIdStr.string());
+ }
+ for (auto &physicalId : mPhysicalCameraIds) {
+ if (isUltraHighResolutionSensor(String8(physicalId.c_str()))) {
+ mHighResolutionSensors.insert(physicalId.c_str());
+ }
+ }
return OK;
}
@@ -186,6 +197,17 @@
return binder::Status::ok();
}
+static std::list<int> getIntersection(const std::unordered_set<int> &streamIdsForThisCamera,
+ const Vector<int> &streamIdsForThisRequest) {
+ std::list<int> intersection;
+ for (auto &streamId : streamIdsForThisRequest) {
+ if (streamIdsForThisCamera.find(streamId) != streamIdsForThisCamera.end()) {
+ intersection.emplace_back(streamId);
+ }
+ }
+ return intersection;
+}
+
binder::Status CameraDeviceClient::submitRequestList(
const std::vector<hardware::camera2::CaptureRequest>& requests,
bool streaming,
@@ -332,6 +354,24 @@
"Request settings are empty");
}
+ // Check whether the physical / logical stream has settings
+ // consistent with the sensor pixel mode(s) it was configured with.
+ // mCameraIdToStreamSet will only have ids that are high resolution
+ const auto streamIdSetIt = mHighResolutionCameraIdToStreamIdSet.find(it.id);
+ if (streamIdSetIt != mHighResolutionCameraIdToStreamIdSet.end()) {
+ std::list<int> streamIdsUsedInRequest = getIntersection(streamIdSetIt->second,
+ outputStreamIds);
+ if (!request.mIsReprocess &&
+ !isSensorPixelModeConsistent(streamIdsUsedInRequest, it.settings)) {
+ ALOGE("%s: Camera %s: Request settings CONTROL_SENSOR_PIXEL_MODE not "
+ "consistent with configured streams. Rejecting request.",
+ __FUNCTION__, it.id.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Request settings CONTROL_SENSOR_PIXEL_MODE are not consistent with "
+ "streams configured");
+ }
+ }
+
String8 physicalId(it.id.c_str());
if (physicalId != mDevice->getId()) {
auto found = std::find(requestedPhysicalIds.begin(), requestedPhysicalIds.end(),
@@ -494,7 +534,7 @@
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- res = SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
+ res = camera3::SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
mCameraIdStr);
if (!res.isOk()) {
return res;
@@ -560,8 +600,8 @@
binder::Status CameraDeviceClient::isSessionConfigurationSupported(
const SessionConfiguration& sessionConfiguration, bool *status /*out*/) {
- ATRACE_CALL();
+ ATRACE_CALL();
binder::Status res;
status_t ret = OK;
if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
@@ -573,7 +613,7 @@
}
auto operatingMode = sessionConfiguration.getOperatingMode();
- res = SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
+ res = camera3::SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
mCameraIdStr);
if (!res.isOk()) {
return res;
@@ -589,7 +629,7 @@
metadataGetter getMetadata = [this](const String8 &id) {return mDevice->infoPhysical(id);};
std::vector<std::string> physicalCameraIds;
mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
- res = SessionConfigurationUtils::convertToHALStreamCombination(sessionConfiguration,
+ res = camera3::SessionConfigurationUtils::convertToHALStreamCombination(sessionConfiguration,
mCameraIdStr, mDevice->info(), getMetadata, physicalCameraIds, streamConfiguration,
&earlyExit);
if (!res.isOk()) {
@@ -714,6 +754,13 @@
}
mCompositeStreamMap.removeItemsAt(compositeIndex);
}
+ for (auto &mapIt: mHighResolutionCameraIdToStreamIdSet) {
+ auto &streamSet = mapIt.second;
+ if (streamSet.find(streamId) != streamSet.end()) {
+ streamSet.erase(streamId);
+ break;
+ }
+ }
}
}
@@ -740,7 +787,7 @@
bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
bool isMultiResolution = outputConfiguration.isMultiResolution();
- res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
+ res = camera3::SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
outputConfiguration.getSurfaceType());
if (!res.isOk()) {
return res;
@@ -749,10 +796,8 @@
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- std::vector<std::string> physicalCameraIds;
- mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
- res = SessionConfigurationUtils::checkPhysicalCameraId(physicalCameraIds, physicalCameraId,
- mCameraIdStr);
+ res = camera3::SessionConfigurationUtils::checkPhysicalCameraId(mPhysicalCameraIds,
+ physicalCameraId, mCameraIdStr);
if (!res.isOk()) {
return res;
}
@@ -768,6 +813,8 @@
OutputStreamInfo streamInfo;
bool isStreamInfoValid = false;
+ const std::vector<int32_t> &sensorPixelModesUsed =
+ outputConfiguration.getSensorPixelModesUsed();
for (auto& bufferProducer : bufferProducers) {
// Don't create multiple streams for the same target surface
sp<IBinder> binder = IInterface::asBinder(bufferProducer);
@@ -780,8 +827,9 @@
}
sp<Surface> surface;
- res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo, isStreamInfoValid,
- surface, bufferProducer, mCameraIdStr, mDevice->infoPhysical(physicalCameraId));
+ res = camera3::SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
+ isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
+ mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed);
if (!res.isOk())
return res;
@@ -793,10 +841,10 @@
binders.push_back(IInterface::asBinder(bufferProducer));
surfaces.push_back(surface);
}
-
int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
std::vector<int> surfaceIds;
- bool isDepthCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]);
+ bool isDepthCompositeStream =
+ camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]);
bool isHeicCompisiteStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]);
if (isDepthCompositeStream || isHeicCompisiteStream) {
sp<CompositeStream> compositeStream;
@@ -809,8 +857,8 @@
err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width,
streamInfo.height, streamInfo.format,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
- &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
- isShared, isMultiResolution);
+ &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
+ outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution);
if (err == OK) {
mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
compositeStream);
@@ -819,8 +867,8 @@
err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
streamInfo.height, streamInfo.format, streamInfo.dataSpace,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
- &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
- isShared, isMultiResolution);
+ &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
+ outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution);
}
if (err != OK) {
@@ -848,6 +896,16 @@
// Set transform flags to ensure preview to be rotated correctly.
res = setStreamTransformLocked(streamId);
+ // Fill in mHighResolutionCameraIdToStreamIdSet map
+ const String8 &cameraIdUsed =
+ physicalCameraId.size() != 0 ? physicalCameraId : mCameraIdStr;
+ const char *cameraIdUsedCStr = cameraIdUsed.string();
+ // Only needed for high resolution sensors
+ if (mHighResolutionSensors.find(cameraIdUsedCStr) !=
+ mHighResolutionSensors.end()) {
+ mHighResolutionCameraIdToStreamIdSet[cameraIdUsedCStr].insert(streamId);
+ }
+
*newStreamId = streamId;
}
@@ -884,10 +942,25 @@
std::vector<sp<Surface>> noSurface;
std::vector<int> surfaceIds;
String8 physicalCameraId(outputConfiguration.getPhysicalCameraId());
+ const String8 &cameraIdUsed =
+ physicalCameraId.size() != 0 ? physicalCameraId : mCameraIdStr;
+ // Here, we override sensor pixel modes
+ std::unordered_set<int32_t> overriddenSensorPixelModesUsed;
+ const std::vector<int32_t> &sensorPixelModesUsed =
+ outputConfiguration.getSensorPixelModesUsed();
+ if (camera3::SessionConfigurationUtils::checkAndOverrideSensorPixelModesUsed(
+ sensorPixelModesUsed, format, width, height, getStaticInfo(cameraIdUsed),
+ /*allowRounding*/ false, &overriddenSensorPixelModesUsed) != OK) {
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "sensor pixel modes used not valid for deferred stream");
+ }
+
err = mDevice->createStream(noSurface, /*hasDeferredConsumer*/true, width,
height, format, dataSpace,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
- &streamId, physicalCameraId, &surfaceIds,
+ &streamId, physicalCameraId,
+ overriddenSensorPixelModesUsed,
+ &surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared,
outputConfiguration.isMultiResolution(), consumerUsage);
@@ -900,9 +973,9 @@
// a separate list to track. Once the deferred surface is set, this id will be
// relocated to mStreamMap.
mDeferredStreams.push_back(streamId);
-
mStreamInfoMap.emplace(std::piecewise_construct, std::forward_as_tuple(streamId),
- std::forward_as_tuple(width, height, format, dataSpace, consumerUsage));
+ std::forward_as_tuple(width, height, format, dataSpace, consumerUsage,
+ overriddenSensorPixelModesUsed));
ALOGV("%s: Camera %s: Successfully created a new stream ID %d for a deferred surface"
" (%d x %d) stream with format 0x%x.",
@@ -912,6 +985,13 @@
res = setStreamTransformLocked(streamId);
*newStreamId = streamId;
+ // Fill in mHighResolutionCameraIdToStreamIdSet
+ const char *cameraIdUsedCStr = cameraIdUsed.string();
+ // Only needed for high resolution sensors
+ if (mHighResolutionSensors.find(cameraIdUsedCStr) !=
+ mHighResolutionSensors.end()) {
+ mHighResolutionCameraIdToStreamIdSet[cameraIdUsed.string()].insert(streamId);
+ }
}
return res;
}
@@ -1081,13 +1161,15 @@
newOutputsMap.removeItemsAt(idx);
}
}
+ const std::vector<int32_t> &sensorPixelModesUsed =
+ outputConfiguration.getSensorPixelModesUsed();
for (size_t i = 0; i < newOutputsMap.size(); i++) {
OutputStreamInfo outInfo;
sp<Surface> surface;
- res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo, /*isStreamInfoValid*/ false,
- surface, newOutputsMap.valueAt(i), mCameraIdStr,
- mDevice->infoPhysical(physicalCameraId));
+ res = camera3::SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
+ /*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
+ mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed);
if (!res.isOk())
return res;
@@ -1442,6 +1524,8 @@
}
std::vector<sp<Surface>> consumerSurfaces;
+ const std::vector<int32_t> &sensorPixelModesUsed =
+ outputConfiguration.getSensorPixelModesUsed();
for (auto& bufferProducer : bufferProducers) {
// Don't create multiple streams for the same target surface
ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
@@ -1452,9 +1536,9 @@
}
sp<Surface> surface;
- res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
+ res = camera3::SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
- mDevice->infoPhysical(physicalId));
+ mDevice->infoPhysical(physicalId), sensorPixelModesUsed);
if (!res.isOk())
return res;
@@ -1936,4 +2020,54 @@
return ret;
}
+
+const CameraMetadata &CameraDeviceClient::getStaticInfo(const String8 &cameraId) {
+ if (mDevice->getId() == cameraId) {
+ return mDevice->info();
+ }
+ return mDevice->infoPhysical(cameraId);
+}
+
+bool CameraDeviceClient::isUltraHighResolutionSensor(const String8 &cameraId) {
+ const CameraMetadata &deviceInfo = getStaticInfo(cameraId);
+ return camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(deviceInfo);
+}
+
+bool CameraDeviceClient::isSensorPixelModeConsistent(
+ const std::list<int> &streamIdList, const CameraMetadata &settings) {
+ // First we get the sensorPixelMode from the settings metadata.
+ int32_t sensorPixelMode = ANDROID_SENSOR_PIXEL_MODE_DEFAULT;
+ camera_metadata_ro_entry sensorPixelModeEntry = settings.find(ANDROID_SENSOR_PIXEL_MODE);
+ if (sensorPixelModeEntry.count != 0) {
+ sensorPixelMode = sensorPixelModeEntry.data.u8[0];
+ if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_DEFAULT &&
+ sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
+ ALOGE("%s: Request sensor pixel mode not is not one of the valid values %d",
+ __FUNCTION__, sensorPixelMode);
+ return false;
+ }
+ }
+ // Check whether each stream has max resolution allowed.
+ bool consistent = true;
+ for (auto it : streamIdList) {
+ auto const streamInfoIt = mStreamInfoMap.find(it);
+ if (streamInfoIt == mStreamInfoMap.end()) {
+ ALOGE("%s: stream id %d not created, skipping", __FUNCTION__, it);
+ return false;
+ }
+ consistent =
+ streamInfoIt->second.sensorPixelModesUsed.find(sensorPixelMode) !=
+ streamInfoIt->second.sensorPixelModesUsed.end();
+ if (!consistent) {
+ ALOGE("sensorPixelMode used %i not consistent with configured modes", sensorPixelMode);
+ for (auto m : streamInfoIt->second.sensorPixelModesUsed) {
+ ALOGE("sensor pixel mode used list: %i", m);
+ }
+ break;
+ }
+ }
+
+ return consistent;
+}
+
} // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 9f7a4af..adedf92 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -28,6 +28,7 @@
#include "common/FrameProcessorBase.h"
#include "common/Camera2ClientBase.h"
#include "CompositeStream.h"
+#include "utils/SessionConfigurationUtils.h"
using android::camera3::OutputStreamInfo;
using android::camera3::CompositeStream;
@@ -222,6 +223,13 @@
// Calculate the ANativeWindow transform from android.sensor.orientation
status_t getRotationTransformLocked(/*out*/int32_t* transform);
+ bool isUltraHighResolutionSensor(const String8 &cameraId);
+
+ bool isSensorPixelModeConsistent(const std::list<int> &streamIdList,
+ const CameraMetadata &settings);
+
+ const CameraMetadata &getStaticInfo(const String8 &cameraId);
+
private:
// StreamSurfaceId encapsulates streamId + surfaceId for a particular surface.
// streamId specifies the index of the stream the surface belongs to, and the
@@ -305,6 +313,8 @@
int32_t mRequestIdCounter;
+ std::vector<std::string> mPhysicalCameraIds;
+
// The list of output streams whose surfaces are deferred. We have to track them separately
// as there are no surfaces available and can not be put into mStreamMap. Once the deferred
// Surface is configured, the stream id will be moved to mStreamMap.
@@ -313,6 +323,12 @@
// stream ID -> outputStreamInfo mapping
std::unordered_map<int32_t, OutputStreamInfo> mStreamInfoMap;
+ // map high resolution camera id (logical / physical) -> list of stream ids configured
+ std::unordered_map<std::string, std::unordered_set<int>> mHighResolutionCameraIdToStreamIdSet;
+
+ // set of high resolution camera id (logical / physical)
+ std::unordered_set<std::string> mHighResolutionSensors;
+
KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
sp<CameraProviderManager> mProviderManager;
diff --git a/services/camera/libcameraservice/api2/CompositeStream.cpp b/services/camera/libcameraservice/api2/CompositeStream.cpp
index 515b7f2..4b840fc 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/CompositeStream.cpp
@@ -47,7 +47,9 @@
status_t CompositeStream::createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int * id, const String8& physicalCameraId,
- std::vector<int> * surfaceIds, int streamSetId, bool isShared, bool isMultiResolution) {
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> * surfaceIds,
+ int streamSetId, bool isShared, bool isMultiResolution) {
if (hasDeferredConsumer) {
ALOGE("%s: Deferred consumers not supported in case of composite streams!",
__FUNCTION__);
@@ -72,8 +74,8 @@
return BAD_VALUE;
}
- return createInternalStreams(consumers, hasDeferredConsumer, width, height, format, rotation, id,
- physicalCameraId, surfaceIds, streamSetId, isShared);
+ return createInternalStreams(consumers, hasDeferredConsumer, width, height, format, rotation,
+ id, physicalCameraId, sensorPixelModesUsed, surfaceIds, streamSetId, isShared);
}
status_t CompositeStream::deleteStream() {
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
index 1bf137a..600bd28 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.h
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -44,7 +44,9 @@
status_t createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution);
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int streamSetId, bool isShared, bool isMultiResolution);
status_t deleteStream();
@@ -55,7 +57,9 @@
virtual status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared) = 0;
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int streamSetId, bool isShared) = 0;
// Release all internal streams and corresponding resources.
virtual status_t deleteInternalStreams() = 0;
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 2c553f3..19b54e0 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -20,6 +20,7 @@
#include "api1/client2/JpegProcessor.h"
#include "common/CameraProviderManager.h"
+#include "utils/SessionConfigurationUtils.h"
#include <gui/Surface.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -78,7 +79,10 @@
}
}
- getSupportedDepthSizes(staticInfo, &mSupportedDepthSizes);
+ getSupportedDepthSizes(staticInfo, /*maxResolution*/false, &mSupportedDepthSizes);
+ if (SessionConfigurationUtils::isUltraHighResolutionSensor(staticInfo)) {
+ getSupportedDepthSizes(staticInfo, true, &mSupportedDepthSizesMaximumResolution);
+ }
}
}
@@ -484,17 +488,82 @@
return false;
}
+static bool setContains(std::unordered_set<int32_t> containerSet, int32_t value) {
+ return containerSet.find(value) != containerSet.end();
+}
+
+status_t DepthCompositeStream::checkAndGetMatchingDepthSize(size_t width, size_t height,
+ const std::vector<std::tuple<size_t, size_t>> &depthSizes,
+ const std::vector<std::tuple<size_t, size_t>> &depthSizesMaximumResolution,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ size_t *depthWidth, size_t *depthHeight) {
+ if (depthWidth == nullptr || depthHeight == nullptr) {
+ return BAD_VALUE;
+ }
+ size_t chosenDepthWidth = 0, chosenDepthHeight = 0;
+ bool hasDefaultSensorPixelMode =
+ setContains(sensorPixelModesUsed, ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
+
+ bool hasMaximumResolutionSensorPixelMode =
+ setContains(sensorPixelModesUsed, ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
+
+ if (!hasDefaultSensorPixelMode && !hasMaximumResolutionSensorPixelMode) {
+ ALOGE("%s: sensor pixel modes don't contain either maximum resolution or default modes",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (hasDefaultSensorPixelMode) {
+ auto ret = getMatchingDepthSize(width, height, depthSizes, &chosenDepthWidth,
+ &chosenDepthHeight);
+ if (ret != OK) {
+ ALOGE("%s: No matching depth stream size found", __FUNCTION__);
+ return ret;
+ }
+ }
+
+ if (hasMaximumResolutionSensorPixelMode) {
+ size_t depthWidth = 0, depthHeight = 0;
+ auto ret = getMatchingDepthSize(width, height,
+ depthSizesMaximumResolution, &depthWidth, &depthHeight);
+ if (ret != OK) {
+ ALOGE("%s: No matching max resolution depth stream size found", __FUNCTION__);
+ return ret;
+ }
+ // Both matching depth sizes should be the same.
+ if (chosenDepthWidth != 0 && chosenDepthWidth != depthWidth &&
+ chosenDepthHeight != depthHeight) {
+ ALOGE("%s: Maximum resolution sensor pixel mode and default sensor pixel mode don't"
+ " have matching depth sizes", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ if (chosenDepthWidth == 0) {
+ chosenDepthWidth = depthWidth;
+ chosenDepthHeight = depthHeight;
+ }
+ }
+ *depthWidth = chosenDepthWidth;
+ *depthHeight = chosenDepthHeight;
+ return OK;
+}
+
+
status_t DepthCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int /*streamSetId*/, bool /*isShared*/) {
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int /*streamSetId*/, bool /*isShared*/) {
if (mSupportedDepthSizes.empty()) {
ALOGE("%s: This camera device doesn't support any depth map streams!", __FUNCTION__);
return INVALID_OPERATION;
}
size_t depthWidth, depthHeight;
- auto ret = getMatchingDepthSize(width, height, mSupportedDepthSizes, &depthWidth, &depthHeight);
+ auto ret =
+ checkAndGetMatchingDepthSize(width, height, mSupportedDepthSizes,
+ mSupportedDepthSizesMaximumResolution, sensorPixelModesUsed, &depthWidth,
+ &depthHeight);
if (ret != OK) {
ALOGE("%s: Failed to find an appropriate depth stream size!", __FUNCTION__);
return ret;
@@ -515,7 +584,7 @@
mBlobSurface = new Surface(producer);
ret = device->createStream(mBlobSurface, width, height, format, kJpegDataSpace, rotation,
- id, physicalCameraId, surfaceIds);
+ id, physicalCameraId, sensorPixelModesUsed, surfaceIds);
if (ret == OK) {
mBlobStreamId = *id;
mBlobSurfaceId = (*surfaceIds)[0];
@@ -531,7 +600,8 @@
mDepthSurface = new Surface(producer);
std::vector<int> depthSurfaceId;
ret = device->createStream(mDepthSurface, depthWidth, depthHeight, kDepthMapPixelFormat,
- kDepthMapDataSpace, rotation, &mDepthStreamId, physicalCameraId, &depthSurfaceId);
+ kDepthMapDataSpace, rotation, &mDepthStreamId, physicalCameraId, sensorPixelModesUsed,
+ &depthSurfaceId);
if (ret == OK) {
mDepthSurfaceId = depthSurfaceId[0];
} else {
@@ -749,13 +819,15 @@
return ((*depthWidth > 0) && (*depthHeight > 0)) ? OK : BAD_VALUE;
}
-void DepthCompositeStream::getSupportedDepthSizes(const CameraMetadata& ch,
+void DepthCompositeStream::getSupportedDepthSizes(const CameraMetadata& ch, bool maxResolution,
std::vector<std::tuple<size_t, size_t>>* depthSizes /*out*/) {
if (depthSizes == nullptr) {
return;
}
- auto entry = ch.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+ auto entry = ch.find(
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, maxResolution));
if (entry.count > 0) {
// Depth stream dimensions have four int32_t components
// (pixelformat, width, height, type)
@@ -779,30 +851,43 @@
}
std::vector<std::tuple<size_t, size_t>> depthSizes;
- getSupportedDepthSizes(ch, &depthSizes);
+ std::vector<std::tuple<size_t, size_t>> depthSizesMaximumResolution;
+ getSupportedDepthSizes(ch, /*maxResolution*/false, &depthSizes);
if (depthSizes.empty()) {
ALOGE("%s: No depth stream configurations present", __FUNCTION__);
return BAD_VALUE;
}
- size_t depthWidth, depthHeight;
- auto ret = getMatchingDepthSize(streamInfo.width, streamInfo.height, depthSizes, &depthWidth,
- &depthHeight);
+ if (SessionConfigurationUtils::isUltraHighResolutionSensor(ch)) {
+ getSupportedDepthSizes(ch, /*maxResolution*/true, &depthSizesMaximumResolution);
+ if (depthSizesMaximumResolution.empty()) {
+ ALOGE("%s: No depth stream configurations for maximum resolution present",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ }
+
+ size_t chosenDepthWidth = 0, chosenDepthHeight = 0;
+ auto ret = checkAndGetMatchingDepthSize(streamInfo.width, streamInfo.height, depthSizes,
+ depthSizesMaximumResolution, streamInfo.sensorPixelModesUsed, &chosenDepthWidth,
+ &chosenDepthHeight);
+
if (ret != OK) {
- ALOGE("%s: No matching depth stream size found", __FUNCTION__);
+ ALOGE("%s: Couldn't get matching depth sizes", __FUNCTION__);
return ret;
}
compositeOutput->clear();
compositeOutput->insert(compositeOutput->end(), 2, streamInfo);
+ // Sensor pixel modes should stay the same here. They're already overridden.
// Jpeg/Blob stream info
(*compositeOutput)[0].dataSpace = kJpegDataSpace;
(*compositeOutput)[0].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
// Depth stream info
- (*compositeOutput)[1].width = depthWidth;
- (*compositeOutput)[1].height = depthHeight;
+ (*compositeOutput)[1].width = chosenDepthWidth;
+ (*compositeOutput)[1].height = chosenDepthHeight;
(*compositeOutput)[1].format = kDepthMapPixelFormat;
(*compositeOutput)[1].dataSpace = kDepthMapDataSpace;
(*compositeOutput)[1].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index 05bc504..a520bbf 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -51,7 +51,9 @@
status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared) override;
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int streamSetId, bool isShared) override;
status_t deleteInternalStreams() override;
status_t configureStream() override;
status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
@@ -86,11 +88,17 @@
};
// Helper methods
- static void getSupportedDepthSizes(const CameraMetadata& ch,
+ static void getSupportedDepthSizes(const CameraMetadata& ch, bool maxResolution,
std::vector<std::tuple<size_t, size_t>>* depthSizes /*out*/);
static status_t getMatchingDepthSize(size_t width, size_t height,
const std::vector<std::tuple<size_t, size_t>>& supporedDepthSizes,
size_t *depthWidth /*out*/, size_t *depthHeight /*out*/);
+ static status_t checkAndGetMatchingDepthSize(size_t width, size_t height,
+ const std::vector<std::tuple<size_t, size_t>> &depthSizes,
+ const std::vector<std::tuple<size_t, size_t>> &depthSizesMaximumResolution,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ size_t *depthWidth /*out*/, size_t *depthHeight /*out*/);
+
// Dynamic depth processing
status_t encodeGrayscaleJpeg(size_t width, size_t height, uint8_t *in, void *out,
@@ -126,6 +134,7 @@
ssize_t mMaxJpegSize;
std::vector<std::tuple<size_t, size_t>> mSupportedDepthSizes;
+ std::vector<std::tuple<size_t, size_t>> mSupportedDepthSizesMaximumResolution;
std::vector<float> mIntrinsicCalibration, mLensDistortion;
bool mIsLogicalCamera;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 7d68485..582001d 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -36,6 +36,7 @@
#include "common/CameraDeviceBase.h"
#include "utils/ExifUtils.h"
+#include "utils/SessionConfigurationUtils.h"
#include "HeicEncoderInfoManager.h"
#include "HeicCompositeStream.h"
@@ -115,7 +116,9 @@
status_t HeicCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int /*streamSetId*/, bool /*isShared*/) {
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int /*streamSetId*/, bool /*isShared*/) {
sp<CameraDeviceBase> device = mDevice.promote();
if (!device.get()) {
@@ -141,7 +144,8 @@
mStaticInfo = device->info();
res = device->createStream(mAppSegmentSurface, mAppSegmentMaxSize, 1, format,
- kAppSegmentDataSpace, rotation, &mAppSegmentStreamId, physicalCameraId, surfaceIds);
+ kAppSegmentDataSpace, rotation, &mAppSegmentStreamId, physicalCameraId,
+ sensorPixelModesUsed,surfaceIds);
if (res == OK) {
mAppSegmentSurfaceId = (*surfaceIds)[0];
} else {
@@ -177,7 +181,7 @@
int srcStreamFmt = mUseGrid ? HAL_PIXEL_FORMAT_YCbCr_420_888 :
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
res = device->createStream(mMainImageSurface, width, height, srcStreamFmt, kHeifDataSpace,
- rotation, id, physicalCameraId, &sourceSurfaceId);
+ rotation, id, physicalCameraId, sensorPixelModesUsed, &sourceSurfaceId);
if (res == OK) {
mMainImageSurfaceId = sourceSurfaceId[0];
mMainImageStreamId = *id;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index cbd9d21..1077a1f 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -46,7 +46,9 @@
status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared) override;
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int streamSetId, bool isShared) override;
status_t deleteInternalStreams() override;
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 5acbb99..85b0cc2 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -164,6 +164,7 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
@@ -180,6 +181,7 @@
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index dfe2409..62fc18f 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -686,9 +686,39 @@
}
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addDynamicDepthTags() {
- uint32_t depthExclTag = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE;
- uint32_t depthSizesTag = ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS;
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addDynamicDepthTags(
+ bool maxResolution) {
+ const int32_t depthExclTag = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE;
+
+ const int32_t scalerSizesTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxResolution);
+ const int32_t scalerMinFrameDurationsTag =
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+ const int32_t scalerStallDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, maxResolution);
+
+ const int32_t depthSizesTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, maxResolution);
+ const int32_t depthStallDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS, maxResolution);
+ const int32_t depthMinFrameDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS, maxResolution);
+
+ const int32_t dynamicDepthSizesTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, maxResolution);
+ const int32_t dynamicDepthStallDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, maxResolution);
+ const int32_t dynamicDepthMinFrameDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, maxResolution);
+
auto& c = mCameraCharacteristics;
std::vector<std::tuple<size_t, size_t>> supportedBlobSizes, supportedDepthSizes,
supportedDynamicDepthSizes, internalDepthSizes;
@@ -718,7 +748,7 @@
return BAD_VALUE;
}
- getSupportedSizes(c, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, HAL_PIXEL_FORMAT_BLOB,
+ getSupportedSizes(c, scalerSizesTag, HAL_PIXEL_FORMAT_BLOB,
&supportedBlobSizes);
getSupportedSizes(c, depthSizesTag, HAL_PIXEL_FORMAT_Y16, &supportedDepthSizes);
if (supportedBlobSizes.empty() || supportedDepthSizes.empty()) {
@@ -745,10 +775,10 @@
std::vector<int64_t> blobMinDurations, blobStallDurations;
std::vector<int64_t> dynamicDepthMinDurations, dynamicDepthStallDurations;
- getSupportedDurations(c, ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
- HAL_PIXEL_FORMAT_Y16, internalDepthSizes, &depthMinDurations);
- getSupportedDurations(c, ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
- HAL_PIXEL_FORMAT_BLOB, supportedDynamicDepthSizes, &blobMinDurations);
+ getSupportedDurations(c, depthMinFrameDurationsTag, HAL_PIXEL_FORMAT_Y16, internalDepthSizes,
+ &depthMinDurations);
+ getSupportedDurations(c, scalerMinFrameDurationsTag, HAL_PIXEL_FORMAT_BLOB,
+ supportedDynamicDepthSizes, &blobMinDurations);
if (blobMinDurations.empty() || depthMinDurations.empty() ||
(depthMinDurations.size() != blobMinDurations.size())) {
ALOGE("%s: Unexpected number of available depth min durations! %zu vs. %zu",
@@ -756,10 +786,10 @@
return BAD_VALUE;
}
- getSupportedDurations(c, ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS,
- HAL_PIXEL_FORMAT_Y16, internalDepthSizes, &depthStallDurations);
- getSupportedDurations(c, ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
- HAL_PIXEL_FORMAT_BLOB, supportedDynamicDepthSizes, &blobStallDurations);
+ getSupportedDurations(c, depthStallDurationsTag, HAL_PIXEL_FORMAT_Y16, internalDepthSizes,
+ &depthStallDurations);
+ getSupportedDurations(c, scalerStallDurationsTag, HAL_PIXEL_FORMAT_BLOB,
+ supportedDynamicDepthSizes, &blobStallDurations);
if (blobStallDurations.empty() || depthStallDurations.empty() ||
(depthStallDurations.size() != blobStallDurations.size())) {
ALOGE("%s: Unexpected number of available depth stall durations! %zu vs. %zu",
@@ -804,15 +834,14 @@
supportedChTags.reserve(chTags.count + 3);
supportedChTags.insert(supportedChTags.end(), chTags.data.i32,
chTags.data.i32 + chTags.count);
- supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
- supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
- supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
- c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
- dynamicDepthEntries.data(), dynamicDepthEntries.size());
- c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS,
- dynamicDepthMinDurationEntries.data(), dynamicDepthMinDurationEntries.size());
- c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS,
- dynamicDepthStallDurationEntries.data(), dynamicDepthStallDurationEntries.size());
+ supportedChTags.push_back(dynamicDepthSizesTag);
+ supportedChTags.push_back(dynamicDepthMinFrameDurationsTag);
+ supportedChTags.push_back(dynamicDepthStallDurationsTag);
+ c.update(dynamicDepthSizesTag, dynamicDepthEntries.data(), dynamicDepthEntries.size());
+ c.update(dynamicDepthMinFrameDurationsTag, dynamicDepthMinDurationEntries.data(),
+ dynamicDepthMinDurationEntries.size());
+ c.update(dynamicDepthStallDurationsTag, dynamicDepthStallDurationEntries.data(),
+ dynamicDepthStallDurationEntries.size());
c.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, supportedChTags.data(),
supportedChTags.size());
@@ -1046,7 +1075,24 @@
return OK;
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::deriveHeicTags() {
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::deriveHeicTags(bool maxResolution) {
+ int32_t scalerStreamSizesTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxResolution);
+ int32_t scalerMinFrameDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, maxResolution);
+
+ int32_t heicStreamSizesTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, maxResolution);
+ int32_t heicMinFrameDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS, maxResolution);
+ int32_t heicStallDurationsTag =
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS, maxResolution);
+
auto& c = mCameraCharacteristics;
camera_metadata_entry halHeicSupport = c.find(ANDROID_HEIC_INFO_SUPPORTED);
@@ -1075,10 +1121,8 @@
std::vector<int64_t> heicDurations;
std::vector<int64_t> heicStallDurations;
- camera_metadata_entry halStreamConfigs =
- c.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
- camera_metadata_entry minFrameDurations =
- c.find(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ camera_metadata_entry halStreamConfigs = c.find(scalerStreamSizesTag);
+ camera_metadata_entry minFrameDurations = c.find(scalerMinFrameDurationsTag);
status_t res = fillHeicStreamCombinations(&heicOutputs, &heicDurations, &heicStallDurations,
halStreamConfigs, minFrameDurations);
@@ -1088,12 +1132,9 @@
return res;
}
- c.update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS,
- heicOutputs.data(), heicOutputs.size());
- c.update(ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS,
- heicDurations.data(), heicDurations.size());
- c.update(ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS,
- heicStallDurations.data(), heicStallDurations.size());
+ c.update(heicStreamSizesTag, heicOutputs.data(), heicOutputs.size());
+ c.update(heicMinFrameDurationsTag, heicDurations.data(), heicDurations.size());
+ c.update(heicStallDurationsTag, heicStallDurations.data(), heicStallDurations.size());
return OK;
}
@@ -2005,16 +2046,20 @@
size_t numStreams = halCameraIdsAndStreamCombinations.size();
halCameraIdsAndStreamCombinations_2_6.resize(numStreams);
for (size_t i = 0; i < numStreams; i++) {
+ using namespace camera3;
auto const& combination = halCameraIdsAndStreamCombinations[i];
halCameraIdsAndStreamCombinations_2_6[i].cameraId = combination.cameraId;
bool success =
SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
- halCameraIdsAndStreamCombinations_2_6[i].streamConfiguration,
- combination.streamConfiguration);
+ halCameraIdsAndStreamCombinations_2_6[i].streamConfiguration,
+ combination.streamConfiguration);
if (!success) {
*isSupported = false;
return OK;
}
+ camera3::SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ halCameraIdsAndStreamCombinations_2_6[i].streamConfiguration,
+ combination.streamConfiguration);
}
ret = interface_2_6->isConcurrentStreamCombinationSupported(
halCameraIdsAndStreamCombinations_2_6, cb);
@@ -2220,6 +2265,21 @@
ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
__FUNCTION__, strerror(-res), res);
}
+
+ if (camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
+ status_t status = addDynamicDepthTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)",
+ __FUNCTION__, strerror(-status), status);
+ }
+
+ status = deriveHeicTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for"
+ "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
+ }
+ }
+
res = addRotateCropTags();
if (OK != res) {
ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
@@ -2426,26 +2486,22 @@
status_t res;
Status callStatus;
::android::hardware::Return<void> ret;
- if (interface_3_7 != nullptr) {
- ret = interface_3_7->isStreamCombinationSupported_3_7(configuration,
+ auto halCb =
[&callStatus, &status] (Status s, bool combStatus) {
callStatus = s;
*status = combStatus;
- });
+ };
+ if (interface_3_7 != nullptr) {
+ ret = interface_3_7->isStreamCombinationSupported_3_7(configuration, halCb);
} else if (interface_3_5 != nullptr) {
hardware::camera::device::V3_4::StreamConfiguration configuration_3_4;
- bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ bool success = camera3::SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
configuration_3_4, configuration);
if (!success) {
*status = false;
return OK;
}
-
- ret = interface_3_5->isStreamCombinationSupported(configuration_3_4,
- [&callStatus, &status] (Status s, bool combStatus) {
- callStatus = s;
- *status = combStatus;
- });
+ ret = interface_3_5->isStreamCombinationSupported(configuration_3_4, halCb);
} else {
return INVALID_OPERATION;
}
@@ -2829,7 +2885,7 @@
if (res != OK) {
return res;
}
- metadataGetter getMetadata =
+ camera3::metadataGetter getMetadata =
[this](const String8 &id) {
CameraMetadata physicalDeviceInfo;
getCameraCharacteristicsLocked(id.string(), &physicalDeviceInfo);
@@ -2838,7 +2894,7 @@
std::vector<std::string> physicalCameraIds;
isLogicalCameraLocked(cameraIdAndSessionConfig.mCameraId, &physicalCameraIds);
bStatus =
- SessionConfigurationUtils::convertToHALStreamCombination(
+ camera3::SessionConfigurationUtils::convertToHALStreamCombination(
cameraIdAndSessionConfig.mSessionConfiguration,
String8(cameraIdAndSessionConfig.mCameraId.c_str()), deviceInfo, getMetadata,
physicalCameraIds, streamConfiguration, &shouldExit);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index fa9cc1c..12bda9b 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -556,8 +556,8 @@
void queryPhysicalCameraIds();
SystemCameraKind getSystemCameraKind();
status_t fixupMonochromeTags();
- status_t addDynamicDepthTags();
- status_t deriveHeicTags();
+ status_t addDynamicDepthTags(bool maxResolution = false);
+ status_t deriveHeicTags(bool maxResolution = false);
status_t addRotateCropTags();
status_t addPreCorrectionActiveArraySize();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 24d4611..bf7e597 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -60,6 +60,7 @@
#include "device3/Camera3SharedOutputStream.h"
#include "CameraService.h"
#include "utils/CameraThreadState.h"
+#include "utils/SessionConfigurationUtils.h"
#include "utils/TraceHFR.h"
#include "utils/CameraServiceProxyWrapper.h"
@@ -69,6 +70,7 @@
using namespace android::camera3;
using namespace android::hardware::camera;
using namespace android::hardware::camera::device::V3_2;
+using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
namespace android {
@@ -489,8 +491,13 @@
const int STREAM_WIDTH_OFFSET = 1;
const int STREAM_HEIGHT_OFFSET = 2;
const int STREAM_IS_INPUT_OFFSET = 3;
+ bool isHighResolutionSensor =
+ camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(mDeviceInfo);
+ int32_t scalerSizesTag = isHighResolutionSensor ?
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION :
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
camera_metadata_ro_entry_t availableStreamConfigs =
- mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ mDeviceInfo.find(scalerSizesTag);
if (availableStreamConfigs.count == 0 ||
availableStreamConfigs.count % STREAM_CONFIGURATION_SIZE != 0) {
return camera3::Size(0, 0);
@@ -628,6 +635,8 @@
ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) +
kMinJpegBufferSize;
if (jpegBufferSize > maxJpegBufferSize) {
+ ALOGI("%s: jpeg buffer size calculated is > maxJpeg bufferSize(%zd), clamping",
+ __FUNCTION__, maxJpegBufferSize);
jpegBufferSize = maxJpegBufferSize;
}
@@ -647,13 +656,17 @@
return maxBytesForPointCloud;
}
-ssize_t Camera3Device::getRawOpaqueBufferSize(int32_t width, int32_t height) const {
+ssize_t Camera3Device::getRawOpaqueBufferSize(int32_t width, int32_t height,
+ bool maxResolution) const {
const int PER_CONFIGURATION_SIZE = 3;
const int WIDTH_OFFSET = 0;
const int HEIGHT_OFFSET = 1;
const int SIZE_OFFSET = 2;
camera_metadata_ro_entry rawOpaqueSizes =
- mDeviceInfo.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ mDeviceInfo.find(
+ camera3::SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SENSOR_OPAQUE_RAW_SIZE,
+ maxResolution));
size_t count = rawOpaqueSizes.count;
if (count == 0 || (count % PER_CONFIGURATION_SIZE)) {
ALOGE("%s: Camera %s: bad opaque RAW size static metadata length(%zu)!",
@@ -1325,8 +1338,9 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared,
- bool isMultiResolution, uint64_t consumerUsage) {
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
+ uint64_t consumerUsage) {
ATRACE_CALL();
if (consumer == nullptr) {
@@ -1338,14 +1352,26 @@
consumers.push_back(consumer);
return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
- format, dataSpace, rotation, id, physicalCameraId, surfaceIds, streamSetId,
- isShared, isMultiResolution, consumerUsage);
+ format, dataSpace, rotation, id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
+ streamSetId, isShared, isMultiResolution, consumerUsage);
+}
+
+static bool isRawFormat(int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RAW12:
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ return true;
+ default:
+ return false;
+ }
}
status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
- const String8& physicalCameraId,
+ const String8& physicalCameraId, const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
uint64_t consumerUsage) {
ATRACE_CALL();
@@ -1399,6 +1425,12 @@
return BAD_VALUE;
}
+ if (isRawFormat(format) && sensorPixelModesUsed.size() > 1) {
+ // We can't use one stream with a raw format in both sensor pixel modes since its going to
+ // be found in only one sensor pixel mode.
+ ALOGE("%s: RAW opaque stream cannot be used with > 1 sensor pixel modes", __FUNCTION__);
+ return BAD_VALUE;
+ }
if (format == HAL_PIXEL_FORMAT_BLOB) {
ssize_t blobBufferSize;
if (dataSpace == HAL_DATASPACE_DEPTH) {
@@ -1418,28 +1450,36 @@
}
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, blobBufferSize, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ isMultiResolution);
} else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
- ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height);
+ bool maxResolution =
+ sensorPixelModesUsed.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
+ sensorPixelModesUsed.end();
+ ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height, maxResolution);
if (rawOpaqueBufferSize <= 0) {
SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
return BAD_VALUE;
}
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ isMultiResolution);
} else if (isShared) {
newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
width, height, format, consumerUsage, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId, mUseHalBufManager);
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ mUseHalBufManager);
} else if (consumers.size() == 0 && hasDeferredConsumer) {
newStream = new Camera3OutputStream(mNextStreamId,
width, height, format, consumerUsage, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ isMultiResolution);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ isMultiResolution);
}
size_t consumerCount = consumers.size();
@@ -3221,7 +3261,7 @@
dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation);
// For HidlSession version 3.5 or newer, the format and dataSpace sent
- // to HAL are original, not the overriden ones.
+ // to HAL are original, not the overridden ones.
if (mHidlSession_3_5 != nullptr) {
dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ?
cam3stream->getOriginalFormat() : src->format);
@@ -3238,7 +3278,12 @@
}
dst3_7.v3_4 = dst3_4;
dst3_7.groupId = cam3stream->getHalStreamGroupId();
-
+ dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+ size_t j = 0;
+ for (int mode : src->sensor_pixel_modes_used) {
+ dst3_7.sensorPixelModesUsed[j++] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ }
activeStreams.insert(streamId);
// Create Buffer ID map if necessary
mBufferRecords.tryCreateBufferCache(streamId);
@@ -3255,13 +3300,15 @@
}
requestedConfiguration3_2.operationMode = operationMode;
requestedConfiguration3_4.operationMode = operationMode;
+ requestedConfiguration3_7.operationMode = operationMode;
+ size_t sessionParamSize = get_camera_metadata_size(sessionParams);
requestedConfiguration3_4.sessionParams.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- get_camera_metadata_size(sessionParams));
+ sessionParamSize);
requestedConfiguration3_7.operationMode = operationMode;
requestedConfiguration3_7.sessionParams.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- get_camera_metadata_size(sessionParams));
+ sessionParamSize);
// Invoke configureStreams
device::V3_3::HalStreamConfiguration finalConfiguration;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 855d2e3..d9e89fd 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -132,14 +132,17 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
uint64_t consumerUsage = 0) override;
+
status_t createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
@@ -190,7 +193,7 @@
ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
ssize_t getPointCloudBufferSize() const;
- ssize_t getRawOpaqueBufferSize(int32_t width, int32_t height) const;
+ ssize_t getRawOpaqueBufferSize(int32_t width, int32_t height, bool maxResolution) const;
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
index 2196c7d..8cc6833 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
@@ -31,7 +31,7 @@
Camera3FakeStream::Camera3FakeStream(int id) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, FAKE_WIDTH, FAKE_HEIGHT,
/*maxSize*/0, FAKE_FORMAT, FAKE_DATASPACE, FAKE_ROTATION,
- FAKE_ID) {
+ FAKE_ID, std::unordered_set<int32_t>{ANDROID_SENSOR_PIXEL_MODE_DEFAULT}) {
}
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index a837900..0204d49 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -32,10 +32,12 @@
Camera3IOStreamBase::Camera3IOStreamBase(int id, camera_stream_type_t type,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- const String8& physicalCameraId, int setId, bool isMultiResolution) :
+ const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ int setId, bool isMultiResolution) :
Camera3Stream(id, type,
width, height, maxSize, format, dataSpace, rotation,
- physicalCameraId, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
mTotalBufferCount(0),
mHandoutTotalBufferCount(0),
mHandoutOutputBufferCount(0),
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 2e744ee..90c8a7b 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -36,6 +36,7 @@
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
public:
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index b00a963..6d8317b 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -33,7 +33,8 @@
uint32_t width, uint32_t height, int format) :
Camera3IOStreamBase(id, CAMERA_STREAM_INPUT, width, height, /*maxSize*/0,
format, HAL_DATASPACE_UNKNOWN, CAMERA_STREAM_ROTATION_0,
- FAKE_ID) {
+ FAKE_ID,
+ std::unordered_set<int32_t>{ANDROID_SENSOR_PIXEL_MODE_DEFAULT}) {
if (format == HAL_PIXEL_FORMAT_BLOB) {
ALOGE("%s: Bad format, BLOB not supported", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 3ec3b6b..221bebb 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -44,10 +44,11 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId, bool isMultiResolution) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
- physicalCameraId, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
@@ -70,11 +71,12 @@
sp<Surface> consumer,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- nsecs_t timestampOffset, const String8& physicalCameraId, int setId,
- bool isMultiResolution) :
+ nsecs_t timestampOffset, const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ int setId, bool isMultiResolution) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height, maxSize,
- format, dataSpace, rotation, physicalCameraId, setId,
- isMultiResolution),
+ format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
+ setId, isMultiResolution),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
@@ -104,10 +106,12 @@
uint32_t width, uint32_t height, int format,
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
- const String8& physicalCameraId, int setId, bool isMultiResolution) :
+ const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ int setId, bool isMultiResolution) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
- physicalCameraId, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
mConsumer(nullptr),
mTransform(0),
mTraceFirstBuffer(true),
@@ -142,12 +146,13 @@
android_dataspace dataSpace,
camera_stream_rotation_t rotation,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
uint64_t consumerUsage, nsecs_t timestampOffset,
int setId, bool isMultiResolution) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
format, dataSpace, rotation,
- physicalCameraId, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
mTransform(0),
mTraceFirstBuffer(true),
mUseMonoTimestamp(false),
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index c82f2a6..00e4854 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -87,8 +87,8 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
-
/**
* Set up a stream for formats that have a variable buffer size for the same
* dimensions, such as compressed JPEG.
@@ -99,8 +99,8 @@
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
-
/**
* Set up a stream with deferred consumer for formats that have 2 dimensions, such as
* RAW and YUV. The consumer must be set before using this stream for output. A valid
@@ -110,6 +110,7 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
virtual ~Camera3OutputStream();
@@ -234,6 +235,7 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
uint64_t consumerUsage = 0, nsecs_t timestampOffset = 0,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 8aa5f1a..15cf7f4 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -32,9 +32,10 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId, bool useHalBufManager) :
Camera3OutputStream(id, CAMERA_STREAM_OUTPUT, width, height,
- format, dataSpace, rotation, physicalCameraId,
+ format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
consumerUsage, timestampOffset, setId),
mUseHalBufManager(useHalBufManager) {
size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index a61316c..4b6341b 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -38,6 +38,7 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID,
bool useHalBufManager = false);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index c6e7002..02b6585 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -49,7 +49,9 @@
camera_stream_type type,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- const String8& physicalCameraId, int setId, bool isMultiResolution) :
+ const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ int setId, bool isMultiResolution) :
camera_stream(),
mId(id),
mSetId(setId),
@@ -84,6 +86,7 @@
camera_stream::rotation = rotation;
camera_stream::max_buffers = 0;
camera_stream::physical_camera_id = mPhysicalCameraId.string();
+ camera_stream::sensor_pixel_modes_used = sensorPixelModesUsed;
if ((format == HAL_PIXEL_FORMAT_BLOB || format == HAL_PIXEL_FORMAT_RAW_OPAQUE) &&
maxSize == 0) {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 45d8478..5a364ab 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -498,7 +498,9 @@
Camera3Stream(int id, camera_stream_type type,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- const String8& physicalCameraId, int setId, bool isMultiResolution);
+ const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ int setId, bool isMultiResolution);
wp<Camera3StreamBufferFreedListener> mBufferFreedListener;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 7e6a077..2d3397c 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -62,6 +62,8 @@
android_dataspace_t data_space;
camera_stream_rotation_t rotation;
const char* physical_camera_id;
+
+ std::unordered_set<int32_t> sensor_pixel_modes_used;
} camera_stream_t;
typedef struct camera_stream_buffer {
@@ -104,13 +106,15 @@
uint64_t consumerUsage;
bool finalized = false;
bool supportsOffline = false;
+ std::unordered_set<int32_t> sensorPixelModesUsed;
OutputStreamInfo() :
width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
consumerUsage(0) {}
OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
- uint64_t _consumerUsage) :
+ uint64_t _consumerUsage, const std::unordered_set<int32_t>& _sensorPixelModesUsed) :
width(_width), height(_height), format(_format),
- dataSpace(_dataSpace), consumerUsage(_consumerUsage) {}
+ dataSpace(_dataSpace), consumerUsage(_consumerUsage),
+ sensorPixelModesUsed(_sensorPixelModesUsed) {}
};
/**
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index 316303e..89dd115 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -22,13 +22,14 @@
#include <cmath>
#include "device3/DistortionMapper.h"
+#include "utils/SessionConfigurationUtils.h"
namespace android {
namespace camera3 {
-DistortionMapper::DistortionMapper() : mValidMapping(false), mValidGrids(false) {
+DistortionMapper::DistortionMapper() {
initRemappedKeys();
}
@@ -61,41 +62,81 @@
status_t DistortionMapper::setupStaticInfo(const CameraMetadata &deviceInfo) {
std::lock_guard<std::mutex> lock(mMutex);
+ status_t res = setupStaticInfoLocked(deviceInfo, /*maxResolution*/false);
+ if (res != OK) {
+ return res;
+ }
+
+ bool mMaxResolution = SessionConfigurationUtils::isUltraHighResolutionSensor(deviceInfo);
+ if (mMaxResolution) {
+ res = setupStaticInfoLocked(deviceInfo, /*maxResolution*/true);
+ }
+ return res;
+}
+
+status_t DistortionMapper::setupStaticInfoLocked(const CameraMetadata &deviceInfo,
+ bool maxResolution) {
+ DistortionMapperInfo *mapperInfo = maxResolution ? &mDistortionMapperInfoMaximumResolution :
+ &mDistortionMapperInfo;
+
camera_metadata_ro_entry_t array;
- array = deviceInfo.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ array = deviceInfo.find(
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, maxResolution));
if (array.count != 4) return BAD_VALUE;
float arrayX = static_cast<float>(array.data.i32[0]);
float arrayY = static_cast<float>(array.data.i32[1]);
- mArrayWidth = static_cast<float>(array.data.i32[2]);
- mArrayHeight = static_cast<float>(array.data.i32[3]);
+ mapperInfo->mArrayWidth = static_cast<float>(array.data.i32[2]);
+ mapperInfo->mArrayHeight = static_cast<float>(array.data.i32[3]);
- array = deviceInfo.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ array = deviceInfo.find(
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, maxResolution));
if (array.count != 4) return BAD_VALUE;
float activeX = static_cast<float>(array.data.i32[0]);
float activeY = static_cast<float>(array.data.i32[1]);
- mActiveWidth = static_cast<float>(array.data.i32[2]);
- mActiveHeight = static_cast<float>(array.data.i32[3]);
+ mapperInfo->mActiveWidth = static_cast<float>(array.data.i32[2]);
+ mapperInfo->mActiveHeight = static_cast<float>(array.data.i32[3]);
- mArrayDiffX = activeX - arrayX;
- mArrayDiffY = activeY - arrayY;
+ mapperInfo->mArrayDiffX = activeX - arrayX;
+ mapperInfo->mArrayDiffY = activeY - arrayY;
- return updateCalibration(deviceInfo);
+ return updateCalibration(deviceInfo, /*isStatic*/ true, maxResolution);
+}
+
+static bool doesSettingsHaveMaxResolution(const CameraMetadata *settings) {
+ if (settings == nullptr) {
+ return false;
+ }
+ // First we get the sensorPixelMode from the settings metadata.
+ camera_metadata_ro_entry sensorPixelModeEntry = settings->find(ANDROID_SENSOR_PIXEL_MODE);
+ if (sensorPixelModeEntry.count != 0) {
+ return (sensorPixelModeEntry.data.u8[0] == ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
+ }
+ return false;
}
bool DistortionMapper::calibrationValid() const {
std::lock_guard<std::mutex> lock(mMutex);
-
- return mValidMapping;
+ bool isValid = mDistortionMapperInfo.mValidMapping;
+ if (mMaxResolution) {
+ isValid = isValid && mDistortionMapperInfoMaximumResolution.mValidMapping;
+ }
+ return isValid;
}
status_t DistortionMapper::correctCaptureRequest(CameraMetadata *request) {
std::lock_guard<std::mutex> lock(mMutex);
status_t res;
- if (!mValidMapping) return OK;
+ bool maxResolution = doesSettingsHaveMaxResolution(request);
+ DistortionMapperInfo *mapperInfo = maxResolution ? &mDistortionMapperInfoMaximumResolution :
+ &mDistortionMapperInfo;
+
+ if (!mapperInfo->mValidMapping) return OK;
camera_metadata_entry_t e;
e = request->find(ANDROID_DISTORTION_CORRECTION_MODE);
@@ -107,27 +148,30 @@
if (weight == 0) {
continue;
}
- res = mapCorrectedToRaw(e.data.i32 + j, 2, /*clamp*/true);
+ res = mapCorrectedToRaw(e.data.i32 + j, 2, mapperInfo, /*clamp*/true);
if (res != OK) return res;
}
}
for (auto rect : kRectsToCorrect) {
e = request->find(rect);
- res = mapCorrectedRectToRaw(e.data.i32, e.count / 4, /*clamp*/true);
+ res = mapCorrectedRectToRaw(e.data.i32, e.count / 4, mapperInfo, /*clamp*/true);
if (res != OK) return res;
}
}
-
return OK;
}
status_t DistortionMapper::correctCaptureResult(CameraMetadata *result) {
std::lock_guard<std::mutex> lock(mMutex);
+
+ bool maxResolution = doesSettingsHaveMaxResolution(result);
+ DistortionMapperInfo *mapperInfo = maxResolution ? &mDistortionMapperInfoMaximumResolution :
+ &mDistortionMapperInfo;
status_t res;
- if (!mValidMapping) return OK;
+ if (!mapperInfo->mValidMapping) return OK;
- res = updateCalibration(*result);
+ res = updateCalibration(*result, /*isStatic*/ false, maxResolution);
if (res != OK) {
ALOGE("Failure to update lens calibration information");
return INVALID_OPERATION;
@@ -143,18 +187,18 @@
if (weight == 0) {
continue;
}
- res = mapRawToCorrected(e.data.i32 + j, 2, /*clamp*/true);
+ res = mapRawToCorrected(e.data.i32 + j, 2, mapperInfo, /*clamp*/true);
if (res != OK) return res;
}
}
for (auto rect : kRectsToCorrect) {
e = result->find(rect);
- res = mapRawRectToCorrected(e.data.i32, e.count / 4, /*clamp*/true);
+ res = mapRawRectToCorrected(e.data.i32, e.count / 4, mapperInfo, /*clamp*/true);
if (res != OK) return res;
}
for (auto pts : kResultPointsToCorrectNoClamp) {
e = result->find(pts);
- res = mapRawToCorrected(e.data.i32, e.count / 2, /*clamp*/false);
+ res = mapRawToCorrected(e.data.i32, e.count / 2, mapperInfo, /*clamp*/false);
if (res != OK) return res;
}
}
@@ -164,25 +208,37 @@
// Utility methods; not guarded by mutex
-status_t DistortionMapper::updateCalibration(const CameraMetadata &result) {
+status_t DistortionMapper::updateCalibration(const CameraMetadata &result, bool isStatic,
+ bool maxResolution) {
camera_metadata_ro_entry_t calib, distortion;
+ DistortionMapperInfo *mapperInfo =
+ maxResolution ? &mDistortionMapperInfoMaximumResolution : &mDistortionMapperInfo;
+ // We only need maximum resolution version of LENS_INTRINSIC_CALIBRATION and
+ // LENS_DISTORTION since CaptureResults would still use the same key
+ // regardless of sensor pixel mode.
+ int calibrationKey =
+ SessionConfigurationUtils::getAppropriateModeTag(ANDROID_LENS_INTRINSIC_CALIBRATION,
+ maxResolution && isStatic);
+ int distortionKey =
+ SessionConfigurationUtils::getAppropriateModeTag(ANDROID_LENS_DISTORTION,
+ maxResolution && isStatic);
- calib = result.find(ANDROID_LENS_INTRINSIC_CALIBRATION);
- distortion = result.find(ANDROID_LENS_DISTORTION);
+ calib = result.find(calibrationKey);
+ distortion = result.find(distortionKey);
if (calib.count != 5) return BAD_VALUE;
if (distortion.count != 5) return BAD_VALUE;
// Skip redoing work if no change to calibration fields
- if (mValidMapping &&
- mFx == calib.data.f[0] &&
- mFy == calib.data.f[1] &&
- mCx == calib.data.f[2] &&
- mCy == calib.data.f[3] &&
- mS == calib.data.f[4]) {
+ if (mapperInfo->mValidMapping &&
+ mapperInfo->mFx == calib.data.f[0] &&
+ mapperInfo->mFy == calib.data.f[1] &&
+ mapperInfo->mCx == calib.data.f[2] &&
+ mapperInfo->mCy == calib.data.f[3] &&
+ mapperInfo->mS == calib.data.f[4]) {
bool noChange = true;
for (size_t i = 0; i < distortion.count; i++) {
- if (mK[i] != distortion.data.f[i]) {
+ if (mapperInfo->mK[i] != distortion.data.f[i]) {
noChange = false;
break;
}
@@ -190,39 +246,39 @@
if (noChange) return OK;
}
- mFx = calib.data.f[0];
- mFy = calib.data.f[1];
- mCx = calib.data.f[2];
- mCy = calib.data.f[3];
- mS = calib.data.f[4];
+ mapperInfo->mFx = calib.data.f[0];
+ mapperInfo->mFy = calib.data.f[1];
+ mapperInfo->mCx = calib.data.f[2];
+ mapperInfo->mCy = calib.data.f[3];
+ mapperInfo->mS = calib.data.f[4];
- mInvFx = 1 / mFx;
- mInvFy = 1 / mFy;
+ mapperInfo->mInvFx = 1 / mapperInfo->mFx;
+ mapperInfo->mInvFy = 1 / mapperInfo->mFy;
for (size_t i = 0; i < distortion.count; i++) {
- mK[i] = distortion.data.f[i];
+ mapperInfo->mK[i] = distortion.data.f[i];
}
- mValidMapping = true;
+ mapperInfo->mValidMapping = true;
// Need to recalculate grid
- mValidGrids = false;
+ mapperInfo->mValidGrids = false;
return OK;
}
status_t DistortionMapper::mapRawToCorrected(int32_t *coordPairs, int coordCount,
- bool clamp, bool simple) {
- if (!mValidMapping) return INVALID_OPERATION;
+ DistortionMapperInfo *mapperInfo, bool clamp, bool simple) {
+ if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
- if (simple) return mapRawToCorrectedSimple(coordPairs, coordCount, clamp);
+ if (simple) return mapRawToCorrectedSimple(coordPairs, coordCount, mapperInfo, clamp);
- if (!mValidGrids) {
- status_t res = buildGrids();
+ if (!mapperInfo->mValidGrids) {
+ status_t res = buildGrids(mapperInfo);
if (res != OK) return res;
}
for (int i = 0; i < coordCount * 2; i += 2) {
- const GridQuad *quad = findEnclosingQuad(coordPairs + i, mDistortedGrid);
+ const GridQuad *quad = findEnclosingQuad(coordPairs + i, mapperInfo->mDistortedGrid);
if (quad == nullptr) {
ALOGE("Raw to corrected mapping failure: No quad found for (%d, %d)",
*(coordPairs + i), *(coordPairs + i + 1));
@@ -258,8 +314,8 @@
// Clamp to within active array
if (clamp) {
- corrX = std::min(mActiveWidth - 1, std::max(0.f, corrX));
- corrY = std::min(mActiveHeight - 1, std::max(0.f, corrY));
+ corrX = std::min(mapperInfo->mActiveWidth - 1, std::max(0.f, corrX));
+ corrY = std::min(mapperInfo->mActiveHeight - 1, std::max(0.f, corrY));
}
coordPairs[i] = static_cast<int32_t>(std::round(corrX));
@@ -270,19 +326,19 @@
}
status_t DistortionMapper::mapRawToCorrectedSimple(int32_t *coordPairs, int coordCount,
- bool clamp) const {
- if (!mValidMapping) return INVALID_OPERATION;
+ const DistortionMapperInfo *mapperInfo, bool clamp) const {
+ if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
- float scaleX = mActiveWidth / mArrayWidth;
- float scaleY = mActiveHeight / mArrayHeight;
+ float scaleX = mapperInfo->mActiveWidth / mapperInfo->mArrayWidth;
+ float scaleY = mapperInfo->mActiveHeight / mapperInfo->mArrayHeight;
for (int i = 0; i < coordCount * 2; i += 2) {
float x = coordPairs[i];
float y = coordPairs[i + 1];
float corrX = x * scaleX;
float corrY = y * scaleY;
if (clamp) {
- corrX = std::min(mActiveWidth - 1, std::max(0.f, corrX));
- corrY = std::min(mActiveHeight - 1, std::max(0.f, corrY));
+ corrX = std::min(mapperInfo->mActiveWidth - 1, std::max(0.f, corrX));
+ corrY = std::min(mapperInfo->mActiveHeight - 1, std::max(0.f, corrY));
}
coordPairs[i] = static_cast<int32_t>(std::round(corrX));
coordPairs[i + 1] = static_cast<int32_t>(std::round(corrY));
@@ -291,9 +347,9 @@
return OK;
}
-status_t DistortionMapper::mapRawRectToCorrected(int32_t *rects, int rectCount, bool clamp,
- bool simple) {
- if (!mValidMapping) return INVALID_OPERATION;
+status_t DistortionMapper::mapRawRectToCorrected(int32_t *rects, int rectCount,
+ DistortionMapperInfo *mapperInfo, bool clamp, bool simple) {
+ if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
for (int i = 0; i < rectCount * 4; i += 4) {
// Map from (l, t, width, height) to (l, t, r, b)
int32_t coords[4] = {
@@ -303,7 +359,7 @@
rects[i + 1] + rects[i + 3] - 1
};
- mapRawToCorrected(coords, 2, clamp, simple);
+ mapRawToCorrected(coords, 2, mapperInfo, clamp, simple);
// Map back to (l, t, width, height)
rects[i] = coords[0];
@@ -315,60 +371,60 @@
return OK;
}
-status_t DistortionMapper::mapCorrectedToRaw(int32_t *coordPairs, int coordCount, bool clamp,
- bool simple) const {
- return mapCorrectedToRawImpl(coordPairs, coordCount, clamp, simple);
+status_t DistortionMapper::mapCorrectedToRaw(int32_t *coordPairs, int coordCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const {
+ return mapCorrectedToRawImpl(coordPairs, coordCount, mapperInfo, clamp, simple);
}
template<typename T>
-status_t DistortionMapper::mapCorrectedToRawImpl(T *coordPairs, int coordCount, bool clamp,
- bool simple) const {
- if (!mValidMapping) return INVALID_OPERATION;
+status_t DistortionMapper::mapCorrectedToRawImpl(T *coordPairs, int coordCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const {
+ if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
- if (simple) return mapCorrectedToRawImplSimple(coordPairs, coordCount, clamp);
+ if (simple) return mapCorrectedToRawImplSimple(coordPairs, coordCount, mapperInfo, clamp);
- float activeCx = mCx - mArrayDiffX;
- float activeCy = mCy - mArrayDiffY;
+ float activeCx = mapperInfo->mCx - mapperInfo->mArrayDiffX;
+ float activeCy = mapperInfo->mCy - mapperInfo->mArrayDiffY;
for (int i = 0; i < coordCount * 2; i += 2) {
// Move to normalized space from active array space
- float ywi = (coordPairs[i + 1] - activeCy) * mInvFy;
- float xwi = (coordPairs[i] - activeCx - mS * ywi) * mInvFx;
+ float ywi = (coordPairs[i + 1] - activeCy) * mapperInfo->mInvFy;
+ float xwi = (coordPairs[i] - activeCx - mapperInfo->mS * ywi) * mapperInfo->mInvFx;
// Apply distortion model to calculate raw image coordinates
+ const std::array<float, 5> &kK = mapperInfo->mK;
float rSq = xwi * xwi + ywi * ywi;
- float Fr = 1.f + (mK[0] * rSq) + (mK[1] * rSq * rSq) + (mK[2] * rSq * rSq * rSq);
- float xc = xwi * Fr + (mK[3] * 2 * xwi * ywi) + mK[4] * (rSq + 2 * xwi * xwi);
- float yc = ywi * Fr + (mK[4] * 2 * xwi * ywi) + mK[3] * (rSq + 2 * ywi * ywi);
+ float Fr = 1.f + (kK[0] * rSq) + (kK[1] * rSq * rSq) + (kK[2] * rSq * rSq * rSq);
+ float xc = xwi * Fr + (kK[3] * 2 * xwi * ywi) + kK[4] * (rSq + 2 * xwi * xwi);
+ float yc = ywi * Fr + (kK[4] * 2 * xwi * ywi) + kK[3] * (rSq + 2 * ywi * ywi);
// Move back to image space
- float xr = mFx * xc + mS * yc + mCx;
- float yr = mFy * yc + mCy;
+ float xr = mapperInfo->mFx * xc + mapperInfo->mS * yc + mapperInfo->mCx;
+ float yr = mapperInfo->mFy * yc + mapperInfo->mCy;
// Clamp to within pre-correction active array
if (clamp) {
- xr = std::min(mArrayWidth - 1, std::max(0.f, xr));
- yr = std::min(mArrayHeight - 1, std::max(0.f, yr));
+ xr = std::min(mapperInfo->mArrayWidth - 1, std::max(0.f, xr));
+ yr = std::min(mapperInfo->mArrayHeight - 1, std::max(0.f, yr));
}
coordPairs[i] = static_cast<T>(std::round(xr));
coordPairs[i + 1] = static_cast<T>(std::round(yr));
}
-
return OK;
}
template<typename T>
status_t DistortionMapper::mapCorrectedToRawImplSimple(T *coordPairs, int coordCount,
- bool clamp) const {
- if (!mValidMapping) return INVALID_OPERATION;
+ const DistortionMapperInfo *mapperInfo, bool clamp) const {
+ if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
- float scaleX = mArrayWidth / mActiveWidth;
- float scaleY = mArrayHeight / mActiveHeight;
+ float scaleX = mapperInfo->mArrayWidth / mapperInfo->mActiveWidth;
+ float scaleY = mapperInfo->mArrayHeight / mapperInfo->mActiveHeight;
for (int i = 0; i < coordCount * 2; i += 2) {
float x = coordPairs[i];
float y = coordPairs[i + 1];
float rawX = x * scaleX;
float rawY = y * scaleY;
if (clamp) {
- rawX = std::min(mArrayWidth - 1, std::max(0.f, rawX));
- rawY = std::min(mArrayHeight - 1, std::max(0.f, rawY));
+ rawX = std::min(mapperInfo->mArrayWidth - 1, std::max(0.f, rawX));
+ rawY = std::min(mapperInfo->mArrayHeight - 1, std::max(0.f, rawY));
}
coordPairs[i] = static_cast<T>(std::round(rawX));
coordPairs[i + 1] = static_cast<T>(std::round(rawY));
@@ -377,9 +433,9 @@
return OK;
}
-status_t DistortionMapper::mapCorrectedRectToRaw(int32_t *rects, int rectCount, bool clamp,
- bool simple) const {
- if (!mValidMapping) return INVALID_OPERATION;
+status_t DistortionMapper::mapCorrectedRectToRaw(int32_t *rects, int rectCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const {
+ if (!mapperInfo->mValidMapping) return INVALID_OPERATION;
for (int i = 0; i < rectCount * 4; i += 4) {
// Map from (l, t, width, height) to (l, t, r, b)
@@ -390,7 +446,7 @@
rects[i + 1] + rects[i + 3] - 1
};
- mapCorrectedToRaw(coords, 2, clamp, simple);
+ mapCorrectedToRaw(coords, 2, mapperInfo, clamp, simple);
// Map back to (l, t, width, height)
rects[i] = coords[0];
@@ -402,37 +458,37 @@
return OK;
}
-status_t DistortionMapper::buildGrids() {
- if (mCorrectedGrid.size() != kGridSize * kGridSize) {
- mCorrectedGrid.resize(kGridSize * kGridSize);
- mDistortedGrid.resize(kGridSize * kGridSize);
+status_t DistortionMapper::buildGrids(DistortionMapperInfo *mapperInfo) {
+ if (mapperInfo->mCorrectedGrid.size() != kGridSize * kGridSize) {
+ mapperInfo->mCorrectedGrid.resize(kGridSize * kGridSize);
+ mapperInfo->mDistortedGrid.resize(kGridSize * kGridSize);
}
- float gridMargin = mArrayWidth * kGridMargin;
- float gridSpacingX = (mArrayWidth + 2 * gridMargin) / kGridSize;
- float gridSpacingY = (mArrayHeight + 2 * gridMargin) / kGridSize;
+ float gridMargin = mapperInfo->mArrayWidth * kGridMargin;
+ float gridSpacingX = (mapperInfo->mArrayWidth + 2 * gridMargin) / kGridSize;
+ float gridSpacingY = (mapperInfo->mArrayHeight + 2 * gridMargin) / kGridSize;
size_t index = 0;
float x = -gridMargin;
for (size_t i = 0; i < kGridSize; i++, x += gridSpacingX) {
float y = -gridMargin;
for (size_t j = 0; j < kGridSize; j++, y += gridSpacingY, index++) {
- mCorrectedGrid[index].src = nullptr;
- mCorrectedGrid[index].coords = {
+ mapperInfo->mCorrectedGrid[index].src = nullptr;
+ mapperInfo->mCorrectedGrid[index].coords = {
x, y,
x + gridSpacingX, y,
x + gridSpacingX, y + gridSpacingY,
x, y + gridSpacingY
};
- mDistortedGrid[index].src = &mCorrectedGrid[index];
- mDistortedGrid[index].coords = mCorrectedGrid[index].coords;
- status_t res = mapCorrectedToRawImpl(mDistortedGrid[index].coords.data(), 4,
- /*clamp*/false, /*simple*/false);
+ mapperInfo->mDistortedGrid[index].src = &(mapperInfo->mCorrectedGrid[index]);
+ mapperInfo->mDistortedGrid[index].coords = mapperInfo->mCorrectedGrid[index].coords;
+ status_t res = mapCorrectedToRawImpl(mapperInfo->mDistortedGrid[index].coords.data(), 4,
+ mapperInfo, /*clamp*/false, /*simple*/false);
if (res != OK) return res;
}
}
- mValidGrids = true;
+ mapperInfo->mValidGrids = true;
return OK;
}
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.h b/services/camera/libcameraservice/device3/DistortionMapper.h
index 5027bd0..96f4fda 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.h
+++ b/services/camera/libcameraservice/device3/DistortionMapper.h
@@ -37,13 +37,8 @@
DistortionMapper();
DistortionMapper(const DistortionMapper& other) :
- mValidMapping(other.mValidMapping), mValidGrids(other.mValidGrids),
- mFx(other.mFx), mFy(other.mFy), mCx(other.mCx), mCy(other.mCy), mS(other.mS),
- mInvFx(other.mInvFx), mInvFy(other.mInvFy), mK(other.mK),
- mArrayWidth(other.mArrayWidth), mArrayHeight(other.mArrayHeight),
- mActiveWidth(other.mActiveWidth), mActiveHeight(other.mActiveHeight),
- mArrayDiffX(other.mArrayDiffX), mArrayDiffY(other.mArrayDiffY),
- mCorrectedGrid(other.mCorrectedGrid), mDistortedGrid(other.mDistortedGrid) {
+ mDistortionMapperInfo(other.mDistortionMapperInfo),
+ mDistortionMapperInfoMaximumResolution(other.mDistortionMapperInfoMaximumResolution) {
initRemappedKeys(); }
void initRemappedKeys() override;
@@ -75,10 +70,14 @@
public: // Visible for testing. Not guarded by mutex; do not use concurrently
+
+ struct DistortionMapperInfo;
+
/**
* Update lens calibration from capture results or equivalent
*/
- status_t updateCalibration(const CameraMetadata &result);
+ status_t updateCalibration(const CameraMetadata &result, bool isStatic = false,
+ bool maxResolution = false);
/**
* Transform from distorted (original) to corrected (warped) coordinates.
@@ -89,8 +88,8 @@
* clamp: Whether to clamp the result to the bounds of the active array
* simple: Whether to do complex correction or just a simple linear map
*/
- status_t mapRawToCorrected(int32_t *coordPairs, int coordCount, bool clamp,
- bool simple = true);
+ status_t mapRawToCorrected(int32_t *coordPairs, int coordCount,
+ DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true);
/**
* Transform from distorted (original) to corrected (warped) coordinates.
@@ -101,8 +100,8 @@
* clamp: Whether to clamp the result to the bounds of the active array
* simple: Whether to do complex correction or just a simple linear map
*/
- status_t mapRawRectToCorrected(int32_t *rects, int rectCount, bool clamp,
- bool simple = true);
+ status_t mapRawRectToCorrected(int32_t *rects, int rectCount,
+ DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true);
/**
* Transform from corrected (warped) to distorted (original) coordinates.
@@ -113,8 +112,8 @@
* clamp: Whether to clamp the result to the bounds of the precorrection active array
* simple: Whether to do complex correction or just a simple linear map
*/
- status_t mapCorrectedToRaw(int32_t* coordPairs, int coordCount, bool clamp,
- bool simple = true) const;
+ status_t mapCorrectedToRaw(int32_t* coordPairs, int coordCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true) const;
/**
* Transform from corrected (warped) to distorted (original) coordinates.
@@ -125,8 +124,8 @@
* clamp: Whether to clamp the result to the bounds of the precorrection active array
* simple: Whether to do complex correction or just a simple linear map
*/
- status_t mapCorrectedRectToRaw(int32_t *rects, int rectCount, bool clamp,
- bool simple = true) const;
+ status_t mapCorrectedRectToRaw(int32_t *rects, int rectCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp, bool simple = true) const;
struct GridQuad {
// Source grid quad, or null
@@ -136,6 +135,28 @@
std::array<float, 8> coords;
};
+ struct DistortionMapperInfo {
+ bool mValidMapping = false;
+ bool mValidGrids = false;
+
+ // intrisic parameters, in pixels
+ float mFx, mFy, mCx, mCy, mS;
+ // pre-calculated inverses for speed
+ float mInvFx, mInvFy;
+ // radial/tangential distortion parameters
+ std::array<float, 5> mK;
+
+ // pre-correction active array dimensions
+ float mArrayWidth, mArrayHeight;
+ // active array dimensions
+ float mActiveWidth, mActiveHeight;
+ // corner offsets between pre-correction and active arrays
+ float mArrayDiffX, mArrayDiffY;
+
+ std::vector<GridQuad> mCorrectedGrid;
+ std::vector<GridQuad> mDistortedGrid;
+ };
+
// Find which grid quad encloses the point; returns null if none do
static const GridQuad* findEnclosingQuad(
const int32_t pt[2], const std::vector<GridQuad>& grid);
@@ -153,6 +174,11 @@
// if it is false, then an interpolation coordinate for edges E14 and E23 is found.
static float calculateUorV(const int32_t pt[2], const GridQuad& quad, bool calculateU);
+ DistortionMapperInfo *getMapperInfo(bool maxResolution = false) {
+ return maxResolution ? &mDistortionMapperInfoMaximumResolution :
+ &mDistortionMapperInfo;
+ };
+
private:
mutable std::mutex mMutex;
@@ -163,39 +189,28 @@
// Fuzziness for float inequality tests
constexpr static float kFloatFuzz = 1e-4;
+ bool mMaxResolution = false;
+
+ status_t setupStaticInfoLocked(const CameraMetadata &deviceInfo, bool maxResolution);
+
// Single implementation for various mapCorrectedToRaw methods
template<typename T>
- status_t mapCorrectedToRawImpl(T* coordPairs, int coordCount, bool clamp, bool simple) const;
+ status_t mapCorrectedToRawImpl(T* coordPairs, int coordCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp, bool simple) const;
// Simple linear interpolation option
template<typename T>
- status_t mapCorrectedToRawImplSimple(T* coordPairs, int coordCount, bool clamp) const;
+ status_t mapCorrectedToRawImplSimple(T* coordPairs, int coordCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp) const;
- status_t mapRawToCorrectedSimple(int32_t *coordPairs, int coordCount, bool clamp) const;
+ status_t mapRawToCorrectedSimple(int32_t *coordPairs, int coordCount,
+ const DistortionMapperInfo *mapperInfo, bool clamp) const;
// Utility to create reverse mapping grids
- status_t buildGrids();
+ status_t buildGrids(DistortionMapperInfo *mapperInfo);
-
- bool mValidMapping;
- bool mValidGrids;
-
- // intrisic parameters, in pixels
- float mFx, mFy, mCx, mCy, mS;
- // pre-calculated inverses for speed
- float mInvFx, mInvFy;
- // radial/tangential distortion parameters
- std::array<float, 5> mK;
-
- // pre-correction active array dimensions
- float mArrayWidth, mArrayHeight;
- // active array dimensions
- float mActiveWidth, mActiveHeight;
- // corner offsets between pre-correction and active arrays
- float mArrayDiffX, mArrayDiffY;
-
- std::vector<GridQuad> mCorrectedGrid;
- std::vector<GridQuad> mDistortedGrid;
+ DistortionMapperInfo mDistortionMapperInfo;
+ DistortionMapperInfo mDistortionMapperInfoMaximumResolution;
}; // class DistortionMapper
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 1bc2081..1a39510 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
#include "device3/ZoomRatioMapper.h"
+#include "utils/SessionConfigurationUtils.h"
namespace android {
@@ -128,43 +129,120 @@
return OK;
}
+static bool getArrayWidthAndHeight(const CameraMetadata *deviceInfo,
+ int32_t arrayTag, int32_t *width, int32_t *height) {
+ if (width == nullptr || height == nullptr) {
+ ALOGE("%s: width / height nullptr", __FUNCTION__);
+ return false;
+ }
+ camera_metadata_ro_entry_t entry;
+ entry = deviceInfo->find(arrayTag);
+ if (entry.count != 4) return false;
+ *width = entry.data.i32[2];
+ *height = entry.data.i32[3];
+ return true;
+}
+
ZoomRatioMapper::ZoomRatioMapper(const CameraMetadata* deviceInfo,
bool supportNativeZoomRatio, bool usePrecorrectArray) {
initRemappedKeys();
- camera_metadata_ro_entry_t entry;
+ int32_t arrayW = 0;
+ int32_t arrayH = 0;
+ int32_t arrayMaximumResolutionW = 0;
+ int32_t arrayMaximumResolutionH = 0;
+ int32_t activeW = 0;
+ int32_t activeH = 0;
+ int32_t activeMaximumResolutionW = 0;
+ int32_t activeMaximumResolutionH = 0;
- entry = deviceInfo->find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- if (entry.count != 4) return;
- int32_t arrayW = entry.data.i32[2];
- int32_t arrayH = entry.data.i32[3];
+ if (!getArrayWidthAndHeight(deviceInfo, ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+ &arrayW, &arrayH)) {
+ ALOGE("%s: Couldn't get pre correction active array size", __FUNCTION__);
+ return;
+ }
+ if (!getArrayWidthAndHeight(deviceInfo, ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ &activeW, &activeH)) {
+ ALOGE("%s: Couldn't get active array size", __FUNCTION__);
+ return;
+ }
- entry = deviceInfo->find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- if (entry.count != 4) return;
- int32_t activeW = entry.data.i32[2];
- int32_t activeH = entry.data.i32[3];
+ bool isUltraHighResolutionSensor =
+ camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(*deviceInfo);
+ if (isUltraHighResolutionSensor) {
+ if (!getArrayWidthAndHeight(deviceInfo,
+ ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+ &arrayMaximumResolutionW, &arrayMaximumResolutionH)) {
+ ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
+ __FUNCTION__);
+ return;
+ }
+ if (!getArrayWidthAndHeight(deviceInfo,
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+ &activeMaximumResolutionW, &activeMaximumResolutionH)) {
+ ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
+ __FUNCTION__);
+ return;
+ }
+ }
if (usePrecorrectArray) {
mArrayWidth = arrayW;
mArrayHeight = arrayH;
+ mArrayWidthMaximumResolution = arrayMaximumResolutionW;
+ mArrayHeightMaximumResolution = arrayMaximumResolutionH;
} else {
mArrayWidth = activeW;
mArrayHeight = activeH;
+ mArrayWidthMaximumResolution = activeMaximumResolutionW;
+ mArrayHeightMaximumResolution = activeMaximumResolutionH;
}
mHalSupportsZoomRatio = supportNativeZoomRatio;
- ALOGV("%s: array size: %d x %d, mHalSupportsZoomRatio %d",
- __FUNCTION__, mArrayWidth, mArrayHeight, mHalSupportsZoomRatio);
+ ALOGV("%s: array size: %d x %d, full res array size: %d x %d, mHalSupportsZoomRatio %d",
+ __FUNCTION__, mArrayWidth, mArrayHeight, mArrayWidthMaximumResolution,
+ mArrayHeightMaximumResolution, mHalSupportsZoomRatio);
mIsValid = true;
}
+status_t ZoomRatioMapper::getArrayDimensionsToBeUsed(const CameraMetadata *settings,
+ int32_t *arrayWidth, int32_t *arrayHeight) {
+ if (settings == nullptr || arrayWidth == nullptr || arrayHeight == nullptr) {
+ return BAD_VALUE;
+ }
+ // First we get the sensorPixelMode from the settings metadata.
+ int32_t sensorPixelMode = ANDROID_SENSOR_PIXEL_MODE_DEFAULT;
+ camera_metadata_ro_entry sensorPixelModeEntry = settings->find(ANDROID_SENSOR_PIXEL_MODE);
+ if (sensorPixelModeEntry.count != 0) {
+ sensorPixelMode = sensorPixelModeEntry.data.u8[0];
+ if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_DEFAULT &&
+ sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
+ ALOGE("%s: Request sensor pixel mode is not one of the valid values %d",
+ __FUNCTION__, sensorPixelMode);
+ return BAD_VALUE;
+ }
+ }
+ if (sensorPixelMode == ANDROID_SENSOR_PIXEL_MODE_DEFAULT) {
+ *arrayWidth = mArrayWidth;
+ *arrayHeight = mArrayHeight;
+ } else {
+ *arrayWidth = mArrayWidthMaximumResolution;
+ *arrayHeight = mArrayHeightMaximumResolution;
+ }
+ return OK;
+}
+
status_t ZoomRatioMapper::updateCaptureRequest(CameraMetadata* request) {
if (!mIsValid) return INVALID_OPERATION;
status_t res = OK;
bool zoomRatioIs1 = true;
camera_metadata_entry_t entry;
-
+ int arrayHeight, arrayWidth = 0;
+ res = getArrayDimensionsToBeUsed(request, &arrayWidth, &arrayHeight);
+ if (res != OK) {
+ return res;
+ }
entry = request->find(ANDROID_CONTROL_ZOOM_RATIO);
if (entry.count == 1 && entry.data.f[0] != 1.0f) {
zoomRatioIs1 = false;
@@ -174,19 +252,19 @@
if (cropRegionEntry.count == 4) {
int cropWidth = cropRegionEntry.data.i32[2];
int cropHeight = cropRegionEntry.data.i32[3];
- if (cropWidth < mArrayWidth && cropHeight < mArrayHeight) {
+ if (cropWidth < arrayWidth && cropHeight < arrayHeight) {
cropRegionEntry.data.i32[0] = 0;
cropRegionEntry.data.i32[1] = 0;
- cropRegionEntry.data.i32[2] = mArrayWidth;
- cropRegionEntry.data.i32[3] = mArrayHeight;
+ cropRegionEntry.data.i32[2] = arrayWidth;
+ cropRegionEntry.data.i32[3] = arrayHeight;
}
}
}
if (mHalSupportsZoomRatio && zoomRatioIs1) {
- res = separateZoomFromCropLocked(request, false/*isResult*/);
+ res = separateZoomFromCropLocked(request, false/*isResult*/, arrayWidth, arrayHeight);
} else if (!mHalSupportsZoomRatio && !zoomRatioIs1) {
- res = combineZoomAndCropLocked(request, false/*isResult*/);
+ res = combineZoomAndCropLocked(request, false/*isResult*/, arrayWidth, arrayHeight);
}
// If CONTROL_ZOOM_RATIO is in request, but HAL doesn't support
@@ -203,10 +281,15 @@
status_t res = OK;
+ int arrayHeight, arrayWidth = 0;
+ res = getArrayDimensionsToBeUsed(result, &arrayWidth, &arrayHeight);
+ if (res != OK) {
+ return res;
+ }
if (mHalSupportsZoomRatio && requestedZoomRatioIs1) {
- res = combineZoomAndCropLocked(result, true/*isResult*/);
+ res = combineZoomAndCropLocked(result, true/*isResult*/, arrayWidth, arrayHeight);
} else if (!mHalSupportsZoomRatio && !requestedZoomRatioIs1) {
- res = separateZoomFromCropLocked(result, true/*isResult*/);
+ res = separateZoomFromCropLocked(result, true/*isResult*/, arrayWidth, arrayHeight);
} else {
camera_metadata_entry_t entry = result->find(ANDROID_CONTROL_ZOOM_RATIO);
if (entry.count == 0) {
@@ -218,16 +301,22 @@
return res;
}
-float ZoomRatioMapper::deriveZoomRatio(const CameraMetadata* metadata) {
+status_t ZoomRatioMapper::deriveZoomRatio(const CameraMetadata* metadata, float *zoomRatioRet,
+ int arrayWidth, int arrayHeight) {
+ if (metadata == nullptr || zoomRatioRet == nullptr) {
+ return BAD_VALUE;
+ }
float zoomRatio = 1.0;
camera_metadata_ro_entry_t entry;
entry = metadata->find(ANDROID_SCALER_CROP_REGION);
- if (entry.count != 4) return zoomRatio;
-
+ if (entry.count != 4) {
+ *zoomRatioRet = 1;
+ return OK;
+ }
// Center of the preCorrection/active size
- float arrayCenterX = mArrayWidth / 2.0;
- float arrayCenterY = mArrayHeight / 2.0;
+ float arrayCenterX = arrayWidth / 2.0;
+ float arrayCenterY = arrayHeight / 2.0;
// Re-map crop region to coordinate system centered to (arrayCenterX,
// arrayCenterY).
@@ -237,22 +326,30 @@
float cropRegionBottom = entry.data.i32[1] + entry.data.i32[3] - arrayCenterY;
// Calculate the scaling factor for left, top, bottom, right
- float zoomRatioLeft = std::max(mArrayWidth / (2 * cropRegionLeft), 1.0f);
- float zoomRatioTop = std::max(mArrayHeight / (2 * cropRegionTop), 1.0f);
- float zoomRatioRight = std::max(mArrayWidth / (2 * cropRegionRight), 1.0f);
- float zoomRatioBottom = std::max(mArrayHeight / (2 * cropRegionBottom), 1.0f);
+ float zoomRatioLeft = std::max(arrayWidth / (2 * cropRegionLeft), 1.0f);
+ float zoomRatioTop = std::max(arrayHeight / (2 * cropRegionTop), 1.0f);
+ float zoomRatioRight = std::max(arrayWidth / (2 * cropRegionRight), 1.0f);
+ float zoomRatioBottom = std::max(arrayHeight / (2 * cropRegionBottom), 1.0f);
// Use minimum scaling factor to handle letterboxing or pillarboxing
zoomRatio = std::min(std::min(zoomRatioLeft, zoomRatioRight),
std::min(zoomRatioTop, zoomRatioBottom));
ALOGV("%s: derived zoomRatio is %f", __FUNCTION__, zoomRatio);
- return zoomRatio;
+ *zoomRatioRet = zoomRatio;
+ return OK;
}
-status_t ZoomRatioMapper::separateZoomFromCropLocked(CameraMetadata* metadata, bool isResult) {
- status_t res;
- float zoomRatio = deriveZoomRatio(metadata);
+status_t ZoomRatioMapper::separateZoomFromCropLocked(CameraMetadata* metadata, bool isResult,
+ int arrayWidth, int arrayHeight) {
+ float zoomRatio = 1.0;
+ status_t res = deriveZoomRatio(metadata, &zoomRatio, arrayWidth, arrayHeight);
+
+ if (res != OK) {
+ ALOGE("%s: Failed to derive zoom ratio: %s(%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
// Update zoomRatio metadata tag
res = metadata->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
@@ -272,12 +369,14 @@
continue;
}
// Top left (inclusive)
- scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, true /*clamp*/);
+ scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, true /*clamp*/, arrayWidth,
+ arrayHeight);
// Bottom right (exclusive): Use adjacent inclusive pixel to
// calculate.
entry.data.i32[j+2] -= 1;
entry.data.i32[j+3] -= 1;
- scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, true /*clamp*/);
+ scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, true /*clamp*/, arrayWidth,
+ arrayHeight);
entry.data.i32[j+2] += 1;
entry.data.i32[j+3] += 1;
}
@@ -285,20 +384,22 @@
for (auto rect : kRectsToCorrect) {
entry = metadata->find(rect);
- scaleRects(entry.data.i32, entry.count / 4, zoomRatio);
+ scaleRects(entry.data.i32, entry.count / 4, zoomRatio, arrayWidth, arrayHeight);
}
if (isResult) {
for (auto pts : kResultPointsToCorrectNoClamp) {
entry = metadata->find(pts);
- scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, false /*clamp*/);
+ scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, false /*clamp*/,
+ arrayWidth, arrayHeight);
}
}
return OK;
}
-status_t ZoomRatioMapper::combineZoomAndCropLocked(CameraMetadata* metadata, bool isResult) {
+status_t ZoomRatioMapper::combineZoomAndCropLocked(CameraMetadata* metadata, bool isResult,
+ int arrayWidth, int arrayHeight) {
float zoomRatio = 1.0f;
camera_metadata_entry_t entry;
entry = metadata->find(ANDROID_CONTROL_ZOOM_RATIO);
@@ -307,7 +408,6 @@
}
// Unscale regions with zoomRatio
- status_t res;
for (auto region : kMeteringRegionsToCorrect) {
entry = metadata->find(region);
for (size_t j = 0; j < entry.count; j += 5) {
@@ -316,29 +416,32 @@
continue;
}
// Top-left (inclusive)
- scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, true /*clamp*/);
+ scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, true /*clamp*/, arrayWidth,
+ arrayHeight);
// Bottom-right (exclusive): Use adjacent inclusive pixel to
// calculate.
entry.data.i32[j+2] -= 1;
entry.data.i32[j+3] -= 1;
- scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, true /*clamp*/);
+ scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, true /*clamp*/, arrayWidth,
+ arrayHeight);
entry.data.i32[j+2] += 1;
entry.data.i32[j+3] += 1;
}
}
for (auto rect : kRectsToCorrect) {
entry = metadata->find(rect);
- scaleRects(entry.data.i32, entry.count / 4, 1.0 / zoomRatio);
+ scaleRects(entry.data.i32, entry.count / 4, 1.0 / zoomRatio, arrayWidth, arrayHeight);
}
if (isResult) {
for (auto pts : kResultPointsToCorrectNoClamp) {
entry = metadata->find(pts);
- scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, false /*clamp*/);
+ scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, false /*clamp*/,
+ arrayWidth, arrayHeight);
}
}
zoomRatio = 1.0;
- res = metadata->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
+ status_t res = metadata->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
if (res != OK) {
return res;
}
@@ -347,7 +450,7 @@
}
void ZoomRatioMapper::scaleCoordinates(int32_t* coordPairs, int coordCount,
- float scaleRatio, bool clamp) {
+ float scaleRatio, bool clamp, int32_t arrayWidth, int32_t arrayHeight) {
// A pixel's coordinate is represented by the position of its top-left corner.
// To avoid the rounding error, we use the coordinate for the center of the
// pixel instead:
@@ -360,18 +463,18 @@
for (int i = 0; i < coordCount * 2; i += 2) {
float x = coordPairs[i];
float y = coordPairs[i + 1];
- float xCentered = x - (mArrayWidth - 2) / 2;
- float yCentered = y - (mArrayHeight - 2) / 2;
+ float xCentered = x - (arrayWidth - 2) / 2;
+ float yCentered = y - (arrayHeight - 2) / 2;
float scaledX = xCentered * scaleRatio;
float scaledY = yCentered * scaleRatio;
- scaledX += (mArrayWidth - 2) / 2;
- scaledY += (mArrayHeight - 2) / 2;
+ scaledX += (arrayWidth - 2) / 2;
+ scaledY += (arrayHeight - 2) / 2;
coordPairs[i] = static_cast<int32_t>(std::round(scaledX));
coordPairs[i+1] = static_cast<int32_t>(std::round(scaledY));
// Clamp to within activeArray/preCorrectionActiveArray
if (clamp) {
- int32_t right = mArrayWidth - 1;
- int32_t bottom = mArrayHeight - 1;
+ int32_t right = arrayWidth - 1;
+ int32_t bottom = arrayHeight - 1;
coordPairs[i] =
std::min(right, std::max(0, coordPairs[i]));
coordPairs[i+1] =
@@ -382,7 +485,7 @@
}
void ZoomRatioMapper::scaleRects(int32_t* rects, int rectCount,
- float scaleRatio) {
+ float scaleRatio, int32_t arrayWidth, int32_t arrayHeight) {
for (int i = 0; i < rectCount * 4; i += 4) {
// Map from (l, t, width, height) to (l, t, l+width-1, t+height-1),
// where both top-left and bottom-right are inclusive.
@@ -394,9 +497,9 @@
};
// top-left
- scaleCoordinates(coords, 1, scaleRatio, true /*clamp*/);
+ scaleCoordinates(coords, 1, scaleRatio, true /*clamp*/, arrayWidth, arrayHeight);
// bottom-right
- scaleCoordinates(coords+2, 1, scaleRatio, true /*clamp*/);
+ scaleCoordinates(coords+2, 1, scaleRatio, true /*clamp*/, arrayWidth, arrayHeight);
// Map back to (l, t, width, height)
rects[i] = coords[0];
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.h b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
index 3769299..b7a9e41 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.h
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
@@ -68,22 +68,31 @@
public: // Visible for testing. Do not use concurently.
void scaleCoordinates(int32_t* coordPairs, int coordCount,
- float scaleRatio, bool clamp);
+ float scaleRatio, bool clamp, int32_t arrayWidth, int32_t arrayHeight);
bool isValid() { return mIsValid; }
private:
// const after construction
bool mHalSupportsZoomRatio;
- // active array / pre-correction array dimension
+
+ // active array / pre-correction array dimension for default and maximum
+ // resolution modes.
int32_t mArrayWidth, mArrayHeight;
+ int32_t mArrayWidthMaximumResolution, mArrayHeightMaximumResolution;
bool mIsValid = false;
- float deriveZoomRatio(const CameraMetadata* metadata);
- void scaleRects(int32_t* rects, int rectCount, float scaleRatio);
+ status_t deriveZoomRatio(const CameraMetadata* metadata, float *zoomRatio, int arrayWidth,
+ int arrayHeight);
+ void scaleRects(int32_t* rects, int rectCount, float scaleRatio, int32_t arrayWidth,
+ int32_t arrayHeight);
- status_t separateZoomFromCropLocked(CameraMetadata* metadata, bool isResult);
- status_t combineZoomAndCropLocked(CameraMetadata* metadata, bool isResult);
+ status_t separateZoomFromCropLocked(CameraMetadata* metadata, bool isResult, int arrayWidth,
+ int arrayHeight);
+ status_t combineZoomAndCropLocked(CameraMetadata* metadata, bool isResult, int arrayWidth,
+ int arrayHeight);
+ status_t getArrayDimensionsToBeUsed(const CameraMetadata *settings, int32_t *arrayWidth,
+ int32_t *arrayHeight);
};
} // namespace camera3
diff --git a/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp b/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp
index 96bab4e..88ec85c 100644
--- a/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp
+++ b/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp
@@ -23,6 +23,7 @@
using namespace android;
using namespace android::camera3;
+using DistortionMapperInfo = android::camera3::DistortionMapper::DistortionMapperInfo;
int32_t testActiveArray[] = {100, 100, 1000, 750};
float testICal[] = { 1000.f, 1000.f, 500.f, 500.f, 0.f };
@@ -62,10 +63,10 @@
for (int index = 0; fdp.remaining_bytes() > 0; index++) {
input.push_back(fdp.ConsumeIntegral<int32_t>());
}
-
+ DistortionMapperInfo *mapperInfo = m.getMapperInfo();
// The size argument counts how many coordinate pairs there are, so
// it is expected to be 1/2 the size of the input.
- m.mapCorrectedToRaw(input.data(), input.size()/2, clamp, simple);
+ m.mapCorrectedToRaw(input.data(), input.size()/2, mapperInfo, clamp, simple);
return 0;
}
diff --git a/services/camera/libcameraservice/tests/DistortionMapperTest.cpp b/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
index 54935c9..8331136 100644
--- a/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
+++ b/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
@@ -27,7 +27,7 @@
using namespace android;
using namespace android::camera3;
-
+using DistortionMapperInfo = android::camera3::DistortionMapper::DistortionMapperInfo;
int32_t testActiveArray[] = {100, 100, 1000, 750};
int32_t testPreCorrActiveArray[] = {90, 90, 1020, 770};
@@ -132,14 +132,15 @@
/*preCorrectionActiveArray*/ testActiveArray);
auto coords = basicCoords;
- res = m.mapCorrectedToRaw(coords.data(), 5, /*clamp*/true);
+ DistortionMapperInfo *mapperInfo = m.getMapperInfo();
+ res = m.mapCorrectedToRaw(coords.data(), 5, mapperInfo, /*clamp*/true);
ASSERT_EQ(res, OK);
for (size_t i = 0; i < coords.size(); i++) {
EXPECT_EQ(coords[i], basicCoords[i]);
}
- res = m.mapRawToCorrected(coords.data(), 5, /*clamp*/true);
+ res = m.mapRawToCorrected(coords.data(), 5, mapperInfo, /*clamp*/true);
ASSERT_EQ(res, OK);
for (size_t i = 0; i < coords.size(); i++) {
@@ -152,14 +153,14 @@
};
auto rectsOrig = rects;
- res = m.mapCorrectedRectToRaw(rects.data(), 2, /*clamp*/true);
+ res = m.mapCorrectedRectToRaw(rects.data(), 2, mapperInfo, /*clamp*/true);
ASSERT_EQ(res, OK);
for (size_t i = 0; i < rects.size(); i++) {
EXPECT_EQ(rects[i], rectsOrig[i]);
}
- res = m.mapRawRectToCorrected(rects.data(), 2, /*clamp*/true);
+ res = m.mapRawRectToCorrected(rects.data(), 2, mapperInfo, /*clamp*/true);
ASSERT_EQ(res, OK);
for (size_t i = 0; i < rects.size(); i++) {
@@ -176,14 +177,17 @@
/*preCorrectionActiveArray*/ activeArray.data());
auto rectsOrig = activeArray;
- res = m.mapCorrectedRectToRaw(activeArray.data(), 1, /*clamp*/true, /*simple*/ true);
+ DistortionMapperInfo *mapperInfo = m.getMapperInfo();
+ res = m.mapCorrectedRectToRaw(activeArray.data(), 1, mapperInfo, /*clamp*/true,
+ /*simple*/ true);
ASSERT_EQ(res, OK);
for (size_t i = 0; i < activeArray.size(); i++) {
EXPECT_EQ(activeArray[i], rectsOrig[i]);
}
- res = m.mapRawRectToCorrected(activeArray.data(), 1, /*clamp*/true, /*simple*/ true);
+ res = m.mapRawRectToCorrected(activeArray.data(), 1, mapperInfo, /*clamp*/true,
+ /*simple*/ true);
ASSERT_EQ(res, OK);
for (size_t i = 0; i < activeArray.size(); i++) {
@@ -200,7 +204,8 @@
/*preCorrectionActiveArray*/ testPreCorrActiveArray);
auto coords = basicCoords;
- res = m.mapCorrectedToRaw(coords.data(), 5, /*clamp*/true, /*simple*/true);
+ DistortionMapperInfo *mapperInfo = m.getMapperInfo();
+ res = m.mapCorrectedToRaw(coords.data(), 5, mapperInfo, /*clamp*/true, /*simple*/true);
ASSERT_EQ(res, OK);
ASSERT_EQ(coords[0], 0); ASSERT_EQ(coords[1], 0);
@@ -237,12 +242,13 @@
auto origCoords = randCoords;
base::Timer correctedToRawTimer;
- res = m.mapCorrectedToRaw(randCoords.data(), randCoords.size() / 2, clamp, simple);
+ DistortionMapperInfo *mapperInfo = m.getMapperInfo();
+ res = m.mapCorrectedToRaw(randCoords.data(), randCoords.size() / 2, mapperInfo, clamp, simple);
auto correctedToRawDurationMs = correctedToRawTimer.duration();
EXPECT_EQ(res, OK);
base::Timer rawToCorrectedTimer;
- res = m.mapRawToCorrected(randCoords.data(), randCoords.size() / 2, clamp, simple);
+ res = m.mapRawToCorrected(randCoords.data(), randCoords.size() / 2, mapperInfo, clamp, simple);
auto rawToCorrectedDurationMs = rawToCorrectedTimer.duration();
EXPECT_EQ(res, OK);
@@ -363,7 +369,8 @@
using namespace openCvData;
- res = m.mapRawToCorrected(rawCoords.data(), rawCoords.size() / 2, /*clamp*/false,
+ DistortionMapperInfo *mapperInfo = m.getMapperInfo();
+ res = m.mapRawToCorrected(rawCoords.data(), rawCoords.size() / 2, mapperInfo, /*clamp*/false,
/*simple*/false);
for (size_t i = 0; i < rawCoords.size(); i+=2) {
diff --git a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
index 4e94991..ff7aafd 100644
--- a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
+++ b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
@@ -182,7 +182,7 @@
// Verify 1.0x zoom doesn't change the coordinates
auto coords = originalCoords;
- mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f, false /*clamp*/);
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f, false /*clamp*/, width, height);
for (size_t i = 0; i < coords.size(); i++) {
EXPECT_EQ(coords[i], originalCoords[i]);
}
@@ -199,7 +199,7 @@
(width - 1) * 5.0f / 4.0f, (height - 1) / 2.0f, // middle-right after 1.33x zoom
};
coords = originalCoords;
- mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, false /*clamp*/);
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, false /*clamp*/, width, height);
for (size_t i = 0; i < coords.size(); i++) {
EXPECT_LE(std::abs(coords[i] - expected2xCoords[i]), kMaxAllowedPixelError);
}
@@ -216,7 +216,7 @@
width - 1.0f, (height - 1) / 2.0f, // middle-right after 1.33x zoom
};
coords = originalCoords;
- mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/);
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/, width, height);
for (size_t i = 0; i < coords.size(); i++) {
EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedInc[i]), kMaxAllowedPixelError);
}
@@ -233,7 +233,7 @@
width - 1.0f, height / 2.0f, // middle-right after 1.33x zoom
};
coords = originalCoords;
- mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/);
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/, width, height);
for (size_t i = 0; i < coords.size(); i++) {
EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedExc[i]), kMaxAllowedPixelError);
}
@@ -250,7 +250,7 @@
(width - 1) * 5 / 8.0f, (height - 1) / 2.0f, // middle-right after 1.33x zoom-in
};
coords = originalCoords;
- mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f/3, false /*clamp*/);
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f/3, false /*clamp*/, width, height);
for (size_t i = 0; i < coords.size(); i++) {
EXPECT_LE(std::abs(coords[i] - expectedZoomOutCoords[i]), kMaxAllowedPixelError);
}
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index 0557fcc..76927c0 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -120,6 +120,21 @@
proxyBinder->pingForUserUpdate();
}
+bool CameraServiceProxyWrapper::isRotateAndCropOverrideNeeded(
+ String16 packageName, int sensorOrientation, int lensFacing) {
+ sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+ if (proxyBinder == nullptr) return true;
+ bool ret = true;
+ auto status = proxyBinder->isRotateAndCropOverrideNeeded(packageName, sensorOrientation,
+ lensFacing, &ret);
+ if (!status.isOk()) {
+ ALOGE("%s: Failed during top activity orientation query: %s", __FUNCTION__,
+ status.exceptionMessage().c_str());
+ }
+
+ return ret;
+}
+
void CameraServiceProxyWrapper::updateProxyDeviceState(const CameraSessionStats& sessionStats) {
sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
if (proxyBinder == nullptr) return;
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index 9525935..ad9db68 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -90,6 +90,10 @@
// Ping camera service proxy for user update
static void pingCameraServiceProxy();
+
+ // Check whether the current top activity needs a rotate and crop override.
+ static bool isRotateAndCropOverrideNeeded(String16 packageName, int sensorOrientation,
+ int lensFacing);
};
} // android
diff --git a/services/camera/libcameraservice/utils/ExifUtils.cpp b/services/camera/libcameraservice/utils/ExifUtils.cpp
index 8a0303a..485705c 100644
--- a/services/camera/libcameraservice/utils/ExifUtils.cpp
+++ b/services/camera/libcameraservice/utils/ExifUtils.cpp
@@ -916,11 +916,25 @@
ALOGV("%s: Cannot find focal length in metadata.", __FUNCTION__);
}
+ int32_t sensorPixelMode = ANDROID_SENSOR_PIXEL_MODE_DEFAULT;
+ camera_metadata_ro_entry sensorPixelModeEntry = metadata.find(ANDROID_SENSOR_PIXEL_MODE);
+ if (sensorPixelModeEntry.count != 0) {
+ sensorPixelMode = sensorPixelModeEntry.data.u8[0];
+ if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_DEFAULT ||
+ sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
+ ALOGE("%s: Request sensor pixel mode is not one of the valid values %d",
+ __FUNCTION__, sensorPixelMode);
+ return false;
+ }
+ }
+ int32_t activeArrayTag = sensorPixelMode == ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION ?
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION :
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE;
if (metadata.exists(ANDROID_SCALER_CROP_REGION) &&
- staticInfo.exists(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE)) {
+ staticInfo.exists(activeArrayTag)) {
entry = metadata.find(ANDROID_SCALER_CROP_REGION);
camera_metadata_ro_entry activeArrayEntry =
- staticInfo.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ staticInfo.find(activeArrayTag);
if (!setDigitalZoomRatio(entry.data.i32[2], entry.data.i32[3],
activeArrayEntry.data.i32[2], activeArrayEntry.data.i32[3])) {
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 8f42a85..6dcf440 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -21,22 +21,115 @@
#include "device3/Camera3Device.h"
#include "device3/Camera3OutputStream.h"
-// Convenience methods for constructing binder::Status objects for error returns
-
-#define STATUS_ERROR(errorCode, errorString) \
- binder::Status::fromServiceSpecificError(errorCode, \
- String8::format("%s:%d: %s", __FUNCTION__, __LINE__, errorString))
-
-#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
- binder::Status::fromServiceSpecificError(errorCode, \
- String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, \
- __VA_ARGS__))
-
using android::camera3::OutputStreamInfo;
using android::camera3::OutputStreamInfo;
using android::hardware::camera2::ICameraDeviceUser;
+using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
namespace android {
+namespace camera3 {
+
+void StreamConfiguration::getStreamConfigurations(
+ const CameraMetadata &staticInfo, int configuration,
+ std::unordered_map<int, std::vector<StreamConfiguration>> *scm) {
+ if (scm == nullptr) {
+ ALOGE("%s: StreamConfigurationMap nullptr", __FUNCTION__);
+ return;
+ }
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+
+ camera_metadata_ro_entry availableStreamConfigs = staticInfo.find(configuration);
+ for (size_t i = 0; i < availableStreamConfigs.count; i += 4) {
+ int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ StreamConfiguration sc = {format, width, height, isInput};
+ (*scm)[format].push_back(sc);
+ }
+}
+
+void StreamConfiguration::getStreamConfigurations(
+ const CameraMetadata &staticInfo, bool maxRes,
+ std::unordered_map<int, std::vector<StreamConfiguration>> *scm) {
+ int32_t scalerKey =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxRes);
+
+ int32_t depthKey =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, maxRes);
+
+ int32_t dynamicDepthKey =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+
+ int32_t heicKey =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
+
+ getStreamConfigurations(staticInfo, scalerKey, scm);
+ getStreamConfigurations(staticInfo, depthKey, scm);
+ getStreamConfigurations(staticInfo, dynamicDepthKey, scm);
+ getStreamConfigurations(staticInfo, heicKey, scm);
+}
+
+int32_t SessionConfigurationUtils::getAppropriateModeTag(int32_t defaultTag, bool maxResolution) {
+ if (!maxResolution) {
+ return defaultTag;
+ }
+ switch (defaultTag) {
+ case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS:
+ return ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS:
+ return ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS:
+ return ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS;
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS;
+ case ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS:
+ return ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:
+ return ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS:
+ return ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS;
+ case ANDROID_SENSOR_OPAQUE_RAW_SIZE:
+ return ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION;
+ case ANDROID_LENS_INTRINSIC_CALIBRATION:
+ return ANDROID_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION;
+ case ANDROID_LENS_DISTORTION:
+ return ANDROID_LENS_DISTORTION_MAXIMUM_RESOLUTION;
+ default:
+ ALOGE("%s: Tag %d doesn't have a maximum resolution counterpart", __FUNCTION__,
+ defaultTag);
+ return -1;
+ }
+ return -1;
+}
+
+
+StreamConfigurationPair
+SessionConfigurationUtils::getStreamConfigurationPair(const CameraMetadata &staticInfo) {
+ camera3::StreamConfigurationPair streamConfigurationPair;
+ camera3::StreamConfiguration::getStreamConfigurations(staticInfo, false,
+ &streamConfigurationPair.mDefaultStreamConfigurationMap);
+ camera3::StreamConfiguration::getStreamConfigurations(staticInfo, true,
+ &streamConfigurationPair.mMaximumResolutionStreamConfigurationMap);
+ return streamConfigurationPair;
+}
int64_t SessionConfigurationUtils::euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1) {
int64_t d0 = x0 - x1;
@@ -45,15 +138,22 @@
}
bool SessionConfigurationUtils::roundBufferDimensionNearest(int32_t width, int32_t height,
- int32_t format, android_dataspace dataSpace, const CameraMetadata& info,
- /*out*/int32_t* outWidth, /*out*/int32_t* outHeight) {
+ int32_t format, android_dataspace dataSpace,
+ const CameraMetadata& info, bool maxResolution, /*out*/int32_t* outWidth,
+ /*out*/int32_t* outHeight) {
+ const int32_t depthSizesTag =
+ getAppropriateModeTag(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+ maxResolution);
+ const int32_t scalerSizesTag =
+ getAppropriateModeTag(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxResolution);
+ const int32_t heicSizesTag =
+ getAppropriateModeTag(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, maxResolution);
camera_metadata_ro_entry streamConfigs =
- (dataSpace == HAL_DATASPACE_DEPTH) ?
- info.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS) :
+ (dataSpace == HAL_DATASPACE_DEPTH) ? info.find(depthSizesTag) :
(dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_HEIF)) ?
- info.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS) :
- info.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ info.find(heicSizesTag) :
+ info.find(scalerSizesTag);
int32_t bestWidth = -1;
int32_t bestHeight = -1;
@@ -128,11 +228,11 @@
binder::Status SessionConfigurationUtils::createSurfaceFromGbp(
OutputStreamInfo& streamInfo, bool isStreamInfoValid,
sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
- const String8 &cameraId, const CameraMetadata &physicalCameraMetadata) {
-
+ const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
+ const std::vector<int32_t> &sensorPixelModesUsed){
// bufferProducer must be non-null
if (gbp == nullptr) {
- String8 msg = String8::format("Camera %s: Surface is NULL", cameraId.string());
+ String8 msg = String8::format("Camera %s: Surface is NULL", logicalCameraId.string());
ALOGW("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -144,13 +244,13 @@
status_t err;
if ((err = gbp->getConsumerUsage(&consumerUsage)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface consumer usage: %s (%d)",
- cameraId.string(), strerror(-err), err);
+ logicalCameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
ALOGW("%s: Camera %s with consumer usage flag: %" PRIu64 ": Forcing asynchronous mode for"
- "stream", __FUNCTION__, cameraId.string(), consumerUsage);
+ "stream", __FUNCTION__, logicalCameraId.string(), consumerUsage);
useAsync = true;
}
@@ -169,26 +269,26 @@
android_dataspace dataSpace;
if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface width: %s (%d)",
- cameraId.string(), strerror(-err), err);
+ logicalCameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if ((err = anw->query(anw, NATIVE_WINDOW_HEIGHT, &height)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface height: %s (%d)",
- cameraId.string(), strerror(-err), err);
+ logicalCameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface format: %s (%d)",
- cameraId.string(), strerror(-err), err);
+ logicalCameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,
reinterpret_cast<int*>(&dataSpace))) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface dataspace: %s (%d)",
- cameraId.string(), strerror(-err), err);
+ logicalCameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
@@ -199,16 +299,31 @@
((consumerUsage & GRALLOC_USAGE_HW_MASK) &&
((consumerUsage & GRALLOC_USAGE_SW_READ_MASK) == 0))) {
ALOGW("%s: Camera %s: Overriding format %#x to IMPLEMENTATION_DEFINED",
- __FUNCTION__, cameraId.string(), format);
+ __FUNCTION__, logicalCameraId.string(), format);
format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
}
+ std::unordered_set<int32_t> overriddenSensorPixelModes;
+ if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed, format, width, height,
+ physicalCameraMetadata, flexibleConsumer, &overriddenSensorPixelModes) != OK) {
+ String8 msg = String8::format("Camera %s: sensor pixel modes for stream with "
+ "format %#x are not valid",logicalCameraId.string(), format);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ bool foundInMaxRes = false;
+ if (overriddenSensorPixelModes.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
+ overriddenSensorPixelModes.end()) {
+ // we can use the default stream configuration map
+ foundInMaxRes = true;
+ }
// Round dimensions to the nearest dimensions available for this format
if (flexibleConsumer && isPublicFormat(format) &&
!SessionConfigurationUtils::roundBufferDimensionNearest(width, height,
- format, dataSpace, physicalCameraMetadata, /*out*/&width, /*out*/&height)) {
+ format, dataSpace, physicalCameraMetadata, foundInMaxRes, /*out*/&width,
+ /*out*/&height)) {
String8 msg = String8::format("Camera %s: No supported stream configurations with "
"format %#x defined, failed to create output stream",
- cameraId.string(), format);
+ logicalCameraId.string(), format);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -219,30 +334,31 @@
streamInfo.format = format;
streamInfo.dataSpace = dataSpace;
streamInfo.consumerUsage = consumerUsage;
+ streamInfo.sensorPixelModesUsed = overriddenSensorPixelModes;
return binder::Status::ok();
}
if (width != streamInfo.width) {
String8 msg = String8::format("Camera %s:Surface width doesn't match: %d vs %d",
- cameraId.string(), width, streamInfo.width);
+ logicalCameraId.string(), width, streamInfo.width);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
if (height != streamInfo.height) {
String8 msg = String8::format("Camera %s:Surface height doesn't match: %d vs %d",
- cameraId.string(), height, streamInfo.height);
+ logicalCameraId.string(), height, streamInfo.height);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
if (format != streamInfo.format) {
String8 msg = String8::format("Camera %s:Surface format doesn't match: %d vs %d",
- cameraId.string(), format, streamInfo.format);
+ logicalCameraId.string(), format, streamInfo.format);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
if (dataSpace != streamInfo.dataSpace) {
String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
- cameraId.string(), dataSpace, streamInfo.dataSpace);
+ logicalCameraId.string(), dataSpace, streamInfo.dataSpace);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -251,7 +367,7 @@
if (consumerUsage != streamInfo.consumerUsage) {
String8 msg = String8::format(
"Camera %s:Surface usage flag doesn't match %" PRIu64 " vs %" PRIu64 "",
- cameraId.string(), consumerUsage, streamInfo.consumerUsage);
+ logicalCameraId.string(), consumerUsage, streamInfo.consumerUsage);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -259,7 +375,6 @@
return binder::Status::ok();
}
-
void SessionConfigurationUtils::mapStreamInfo(const OutputStreamInfo &streamInfo,
camera3::camera_stream_rotation_t rotation, String8 physicalId,
int32_t groupId, hardware::camera::device::V3_7::Stream *stream /*out*/) {
@@ -280,6 +395,12 @@
stream->v3_4.physicalCameraId = std::string(physicalId.string());
stream->v3_4.bufferSize = 0;
stream->groupId = groupId;
+ stream->sensorPixelModesUsed.resize(streamInfo.sensorPixelModesUsed.size());
+ size_t idx = 0;
+ for (auto mode : streamInfo.sensorPixelModesUsed) {
+ stream->sensorPixelModesUsed[idx++] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ }
}
binder::Status SessionConfigurationUtils::checkPhysicalCameraId(
@@ -394,6 +515,11 @@
streamConfiguration.streams.resize(streamCount);
size_t streamIdx = 0;
if (isInputValid) {
+ hardware::hidl_vec<CameraMetadataEnumAndroidSensorPixelMode> defaultSensorPixelModes;
+ defaultSensorPixelModes.resize(1);
+ defaultSensorPixelModes[0] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(
+ ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
streamConfiguration.streams[streamIdx++] = {{{/*streamId*/0,
hardware::camera::device::V3_2::StreamType::INPUT,
static_cast<uint32_t> (sessionConfiguration.getInputWidth()),
@@ -401,7 +527,7 @@
Camera3Device::mapToPixelFormat(sessionConfiguration.getInputFormat()),
/*usage*/ 0, HAL_DATASPACE_UNKNOWN,
hardware::camera::device::V3_2::StreamRotation::ROTATION_0},
- /*physicalId*/ nullptr, /*bufferSize*/0}, /*groupId*/-1};
+ /*physicalId*/ nullptr, /*bufferSize*/0}, /*groupId*/-1, defaultSensorPixelModes};
streamConfiguration.multiResolutionInputImage =
sessionConfiguration.inputIsMultiResolution();
}
@@ -411,6 +537,12 @@
it.getGraphicBufferProducers();
bool deferredConsumer = it.isDeferred();
String8 physicalCameraId = String8(it.getPhysicalCameraId());
+
+ std::vector<int32_t> sensorPixelModesUsed = it.getSensorPixelModesUsed();
+ const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId);
+ const CameraMetadata &metadataChosen =
+ physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo;
+
size_t numBufferProducers = bufferProducers.size();
bool isStreamInfoValid = false;
int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
@@ -436,6 +568,15 @@
if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
}
+ if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed,
+ streamInfo.format, streamInfo.width,
+ streamInfo.height, metadataChosen, false /*flexibleConsumer*/,
+ &streamInfo.sensorPixelModesUsed) != OK) {
+ ALOGE("%s: Deferred surface sensor pixel modes not valid",
+ __FUNCTION__);
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Deferred surface sensor pixel modes not valid");
+ }
mapStreamInfo(streamInfo, camera3::CAMERA_STREAM_ROTATION_0, physicalCameraId, groupId,
&streamConfiguration.streams[streamIdx++]);
isStreamInfoValid = true;
@@ -447,10 +588,8 @@
for (auto& bufferProducer : bufferProducers) {
sp<Surface> surface;
- const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId);
res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
- logicalCameraId,
- physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo );
+ logicalCameraId, metadataChosen, sensorPixelModesUsed);
if (!res.isOk())
return res;
@@ -465,6 +604,7 @@
// additional internal camera streams.
std::vector<OutputStreamInfo> compositeStreams;
if (isDepthCompositeStream) {
+ // TODO: Take care of composite streams.
ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
deviceInfo, &compositeStreams);
} else {
@@ -505,7 +645,97 @@
}
}
return binder::Status::ok();
+}
+static bool inStreamConfigurationMap(int format, int width, int height,
+ const std::unordered_map<int, std::vector<camera3::StreamConfiguration>> &sm) {
+ auto scs = sm.find(format);
+ if (scs == sm.end()) {
+ return false;
+ }
+ for (auto &sc : scs->second) {
+ if (sc.width == width && sc.height == height && sc.isInput == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static std::unordered_set<int32_t> convertToSet(const std::vector<int32_t> &sensorPixelModesUsed) {
+ return std::unordered_set<int32_t>(sensorPixelModesUsed.begin(), sensorPixelModesUsed.end());
+}
+
+status_t SessionConfigurationUtils::checkAndOverrideSensorPixelModesUsed(
+ const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
+ const CameraMetadata &staticInfo, bool flexibleConsumer,
+ std::unordered_set<int32_t> *overriddenSensorPixelModesUsed) {
+ if (!isUltraHighResolutionSensor(staticInfo)) {
+ overriddenSensorPixelModesUsed->clear();
+ overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
+ return OK;
+ }
+
+ StreamConfigurationPair streamConfigurationPair = getStreamConfigurationPair(staticInfo);
+ const std::unordered_set<int32_t> &sensorPixelModesUsedSet =
+ convertToSet(sensorPixelModesUsed);
+ bool isInDefaultStreamConfigurationMap =
+ inStreamConfigurationMap(format, width, height,
+ streamConfigurationPair.mDefaultStreamConfigurationMap);
+
+ bool isInMaximumResolutionStreamConfigurationMap =
+ inStreamConfigurationMap(format, width, height,
+ streamConfigurationPair.mMaximumResolutionStreamConfigurationMap);
+
+ // Case 1: The client has not changed the sensor mode defaults. In this case, we check if the
+ // size + format of the OutputConfiguration is found exclusively in 1.
+ // If yes, add that sensorPixelMode to overriddenSensorPixelModes.
+ // If no, add 'DEFAULT' to sensorPixelMode. This maintains backwards
+ // compatibility.
+ if (sensorPixelModesUsedSet.size() == 0) {
+ // Ambiguous case, default to only 'DEFAULT' mode.
+ if (isInDefaultStreamConfigurationMap && isInMaximumResolutionStreamConfigurationMap) {
+ overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
+ return OK;
+ }
+ // We don't allow flexible consumer for max resolution mode.
+ if (isInMaximumResolutionStreamConfigurationMap) {
+ overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
+ return OK;
+ }
+ if (isInDefaultStreamConfigurationMap || (flexibleConsumer && width < ROUNDING_WIDTH_CAP)) {
+ overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
+ return OK;
+ }
+ return BAD_VALUE;
+ }
+
+ // Case2: The app has set sensorPixelModesUsed, we need to verify that they
+ // are valid / err out.
+ if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_DEFAULT) !=
+ sensorPixelModesUsedSet.end() && !isInDefaultStreamConfigurationMap) {
+ return BAD_VALUE;
+ }
+
+ if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
+ sensorPixelModesUsedSet.end() && !isInMaximumResolutionStreamConfigurationMap) {
+ return BAD_VALUE;
+ }
+ *overriddenSensorPixelModesUsed = sensorPixelModesUsedSet;
+ return OK;
+}
+
+bool SessionConfigurationUtils::isUltraHighResolutionSensor(const CameraMetadata &deviceInfo) {
+ camera_metadata_ro_entry_t entryCap;
+ entryCap = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ // Go through the capabilities and check if it has
+ // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
+ for (size_t i = 0; i < entryCap.count; ++i) {
+ uint8_t capability = entryCap.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) {
+ return true;
+ }
+ }
+ return false;
}
bool SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
@@ -531,4 +761,5 @@
return true;
}
-}// namespace android
+} // namespace camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 36e1dd7..863a0cd 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -22,24 +22,60 @@
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
#include <android/hardware/camera/device/3.7/types.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
#include <device3/Camera3StreamInterface.h>
#include <stdint.h>
+// Convenience methods for constructing binder::Status objects for error returns
+
+#define STATUS_ERROR(errorCode, errorString) \
+ binder::Status::fromServiceSpecificError(errorCode, \
+ String8::format("%s:%d: %s", __FUNCTION__, __LINE__, errorString))
+
+#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
+ binder::Status::fromServiceSpecificError(errorCode, \
+ String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, \
+ __VA_ARGS__))
+
namespace android {
+namespace camera3 {
typedef std::function<CameraMetadata (const String8 &)> metadataGetter;
+class StreamConfiguration {
+public:
+ int32_t format;
+ int32_t width;
+ int32_t height;
+ int32_t isInput;
+ static void getStreamConfigurations(
+ const CameraMetadata &static_info, bool maxRes,
+ std::unordered_map<int, std::vector<StreamConfiguration>> *scm);
+ static void getStreamConfigurations(
+ const CameraMetadata &static_info, int configuration,
+ std::unordered_map<int, std::vector<StreamConfiguration>> *scm);
+};
+
+// Holds the default StreamConfigurationMap and Maximum resolution
+// StreamConfigurationMap for a camera device.
+struct StreamConfigurationPair {
+ std::unordered_map<int, std::vector<camera3::StreamConfiguration>>
+ mDefaultStreamConfigurationMap;
+ std::unordered_map<int, std::vector<camera3::StreamConfiguration>>
+ mMaximumResolutionStreamConfigurationMap;
+};
+
class SessionConfigurationUtils {
public:
-
static int64_t euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
// Find the closest dimensions for a given format in available stream configurations with
// a width <= ROUNDING_WIDTH_CAP
static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format,
- android_dataspace dataSpace, const CameraMetadata& info,
+ android_dataspace dataSpace, const CameraMetadata& info, bool maxResolution,
/*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
//check if format is not custom format
@@ -50,7 +86,8 @@
static binder::Status createSurfaceFromGbp(
camera3::OutputStreamInfo& streamInfo, bool isStreamInfoValid,
sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
- const String8 &cameraId, const CameraMetadata &physicalCameraMetadata);
+ const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
+ const std::vector<int32_t> &sensorPixelModesUsed);
static void mapStreamInfo(const camera3::OutputStreamInfo &streamInfo,
camera3::camera_stream_rotation_t rotation, String8 physicalId, int32_t groupId,
@@ -86,10 +123,23 @@
hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37);
+ static StreamConfigurationPair getStreamConfigurationPair(const CameraMetadata &metadata);
+
+ static status_t checkAndOverrideSensorPixelModesUsed(
+ const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
+ const CameraMetadata &staticInfo, bool flexibleConsumer,
+ std::unordered_set<int32_t> *overriddenSensorPixelModesUsed);
+
+ static bool isUltraHighResolutionSensor(const CameraMetadata &deviceInfo);
+
+ static int32_t getAppropriateModeTag(int32_t defaultTag, bool maxResolution = false);
+
static const int32_t MAX_SURFACES_PER_STREAM = 4;
static const int32_t ROUNDING_WIDTH_CAP = 1920;
+
};
+} // camera3
} // android
#endif