Camera: Add stream use case API
- Add availableStreamUseCase static metadata tag
- Add STREAM_USE_CASE camera capability
- Add useCase flag in camera stream interface
Test: atest VtsHalCameraProviderV2_4TargetTest
Bug: 200307880
Change-Id: I4e473edcb52a97fa0e1b27cf94603cf9f9984f82
diff --git a/camera/device/3.8/ICameraDevice.hal b/camera/device/3.8/ICameraDevice.hal
index 8832c68..09edb8b 100644
--- a/camera/device/3.8/ICameraDevice.hal
+++ b/camera/device/3.8/ICameraDevice.hal
@@ -113,7 +113,8 @@
*
* Identical to @3.7::ICameraDevice.isStreamCombinationSupported, except
* that it takes a @3.8::StreamConfiguration parameter, which could contain
- * additional information about a specific 10-bit dynamic range profile.
+ * additional information about a specific 10-bit dynamic range profile or
+ * stream use case.
*
*/
isStreamCombinationSupported_3_8(StreamConfiguration streams)
diff --git a/camera/device/3.8/ICameraDeviceSession.hal b/camera/device/3.8/ICameraDeviceSession.hal
index 88e4338..c3aa836 100644
--- a/camera/device/3.8/ICameraDeviceSession.hal
+++ b/camera/device/3.8/ICameraDeviceSession.hal
@@ -35,6 +35,8 @@
*
* - The requestedConfiguration allows the camera framework to configure
* 10-bit dynamic range profile.
+ * - The requestedConfiguration allows the camera framework to configure
+ * stream use cases.
*
* @return status Status code for the operation, one of:
* OK:
@@ -61,6 +63,7 @@
* input stream.
* - Invalid combination between a 10-bit dynamic range profile
* and none impl. defined 8-bit format for a particular stream.
+ * - Unsupported stream use case
* The camera service cannot filter out all possible illegal stream
* configurations, since some devices may support more simultaneous
* streams or larger stream resolutions than the minimum required
diff --git a/camera/device/3.8/types.hal b/camera/device/3.8/types.hal
index 9d1ac22..04a2450 100644
--- a/camera/device/3.8/types.hal
+++ b/camera/device/3.8/types.hal
@@ -17,6 +17,7 @@
package android.hardware.camera.device@3.8;
import @3.2::ErrorMsg;
+import @3.2::CameraMetadata;
import @3.2::MsgType;
import @3.2::ShutterMsg;
import @3.2::CameraMetadata;
@@ -24,6 +25,7 @@
import @3.7::Stream;
import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
+import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
/**
* ShutterMsg:
@@ -80,7 +82,8 @@
* by the framework by its buffer resolution and format, and additionally by the
* HAL with the gralloc usage flags and the maximum in-flight buffer count.
*
- * This version extends the @3.7 Stream with the dynamic range profile field.
+ * This version extends the @3.7 Stream with the dynamic range profile and the
+ * stream use case field.
*/
struct Stream {
/**
@@ -98,6 +101,25 @@
*
*/
CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap dynamicRangeProfile;
+
+ /**
+ * The stream use case describing the stream's purpose
+ *
+ * This flag provides the camera device a hint on what user scenario this
+ * stream is intended for. With this flag, the camera device can optimize
+ * camera pipeline parameters, such as tuning, sensor mode, and ISP settings,
+ * for the intended use case.
+ *
+ * When this field is set to DEFAULT, the camera device should behave in
+ * the same way as in previous HAL versions, and optimize the camera pipeline
+ * based on stream format, data space, usage flag, and other stream properties.
+ *
+ * The HAL reports supported stream use cases in
+ * ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES. If the HAL doesn't support
+ * setting stream use cases, the camera framework leaves this field as
+ * DEFAULT.
+ */
+ CameraMetadataEnumAndroidScalerAvailableStreamUseCases useCase;
};
/**
@@ -115,7 +137,6 @@
/**
* The definition of operation mode from prior version.
- *
*/
@3.2::StreamConfigurationMode operationMode;
@@ -130,17 +151,7 @@
uint32_t streamConfigCounter;
/**
- * If an input stream is configured, whether the input stream is expected to
- * receive variable resolution images.
- *
- * This flag can only be set to true if the camera device supports
- * multi-resolution input streams by advertising input stream configurations in
- * physicalCameraMultiResolutionStreamConfigurations in its physical cameras'
- * characteristics.
- *
- * When this flag is set to true, the input stream's width and height can be
- * any one of the supported multi-resolution input stream sizes.
+ * The definition of multi-resolution input image flag from prior version.
*/
bool multiResolutionInputImage;
};
-
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
index 4c70eb9..488bf9d 100644
--- a/camera/metadata/3.8/types.hal
+++ b/camera/metadata/3.8/types.hal
@@ -68,6 +68,14 @@
ANDROID_REQUEST_END_3_8,
+ /** android.scaler.availableStreamUseCases [static, enum[], public]
+ *
+ * <p>The stream use cases supported by this camera device.</p>
+ */
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = android.hardware.camera.metadata@3.6::CameraMetadataTag:ANDROID_SCALER_END_3_6,
+
+ ANDROID_SCALER_END_3_8,
+
};
/*
@@ -88,6 +96,7 @@
enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
@3.6::CameraMetadataEnumAndroidRequestAvailableCapabilities {
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE,
};
/** android.request.availableDynamicRangeProfilesMap enumeration values
@@ -129,3 +138,17 @@
ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8
= 0x9,
};
+
+/** android.scaler.availableStreamUseCases enumeration values
+ * @see ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+enum CameraMetadataEnumAndroidScalerAvailableStreamUseCases : uint32_t {
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL
+ = 0x4,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000,
+};
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 8c44010..3254cf2 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -44,6 +44,7 @@
#include <android/hardware/camera/device/3.7/ICameraDevice.h>
#include <android/hardware/camera/device/3.8/ICameraDevice.h>
#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
@@ -135,6 +136,8 @@
using ::android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
using ::android::hardware::camera::metadata::V3_8::
CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
+using ::android::hardware::camera::metadata::V3_8::
+ CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
using ::android::hardware::camera::provider::V2_4::ICameraProvider;
using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
@@ -198,6 +201,15 @@
HIDDEN_SECURE_CAMERA
};
+const static std::vector<int32_t> kMandatoryUseCases = {
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL
+};
+
namespace {
// "device@<version>/legacy/<id>"
const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
@@ -879,6 +891,7 @@
void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
void verifyZoomCharacteristics(const camera_metadata_t* metadata);
+ void verifyStreamUseCaseCharacteristics(const camera_metadata_t* metadata);
void verifyRecommendedConfigs(const CameraMetadata& metadata);
void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
void verifyMonochromeCameraResult(
@@ -6879,6 +6892,134 @@
}
}
+// Verify that valid stream use cases can be configured successfully, and invalid use cases
+// fail stream configuration.
+TEST_P(CameraHidlTest, configureStreamsUseCases) {
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+ for (const auto& name : cameraDeviceNames) {
+ int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
+ continue;
+ }
+
+ camera_metadata_t* staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ sp<device::V3_3::ICameraDeviceSession> session3_3;
+ sp<device::V3_4::ICameraDeviceSession> session3_4;
+ sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
+ sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
+ sp<device::V3_2::ICameraDevice> cameraDevice;
+ sp<device::V3_5::ICameraDevice> cameraDevice3_5;
+ sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
+ openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
+ &cameraDevice /*out*/);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
+ &session3_6, &session3_7, &session3_8);
+ ASSERT_NE(nullptr, session3_8);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+ &cameraDevice3_8);
+ ASSERT_NE(nullptr, cameraDevice3_8);
+
+ // Check if camera support depth only
+ if (isDepthOnly(staticMeta)) {
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ std::vector<AvailableStream> outputPreviewStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams,
+ &previewThreshold));
+ ASSERT_NE(0u, outputPreviewStreams.size());
+
+ // Combine valid and invalid stream use cases
+ std::vector<int32_t> useCases(kMandatoryUseCases);
+ useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
+
+ std::vector<int32_t> supportedUseCases;
+ camera_metadata_ro_entry entry;
+ auto retcode = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ supportedUseCases.insert(supportedUseCases.end(), entry.data.i32,
+ entry.data.i32 + entry.count);
+ } else {
+ supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+ }
+ free_camera_metadata(staticMeta);
+
+ ::android::hardware::hidl_vec<V3_8::Stream> streams3_8(1);
+ streams3_8[0].v3_7.groupId = -1;
+ streams3_8[0].v3_7.sensorPixelModesUsed = {
+ CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
+ streams3_8[0].v3_7.v3_4.bufferSize = 0;
+ streams3_8[0].v3_7.v3_4.v3_2.id = 0;
+ streams3_8[0].v3_7.v3_4.v3_2.streamType = StreamType::OUTPUT;
+ streams3_8[0].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(outputPreviewStreams[0].width);
+ streams3_8[0].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(outputPreviewStreams[0].height);
+ streams3_8[0].v3_7.v3_4.v3_2.format =
+ static_cast<PixelFormat>(outputPreviewStreams[0].format);
+ streams3_8[0].v3_7.v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
+ streams3_8[0].v3_7.v3_4.v3_2.dataSpace = 0;
+ streams3_8[0].v3_7.v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
+ streams3_8[0].dynamicRangeProfile =
+ static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+
+ uint32_t streamConfigCounter = 0;
+ ::android::hardware::camera::device::V3_8::StreamConfiguration config3_8;
+ RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+ ret = session3_8->constructDefaultRequestSettings(reqTemplate,
+ [&config3_8](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ config3_8.sessionParams = req;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ for (int32_t useCase : useCases) {
+ bool useCaseSupported = std::find(supportedUseCases.begin(),
+ supportedUseCases.end(), useCase) != supportedUseCases.end();
+
+ streams3_8[0].useCase =
+ static_cast<CameraMetadataEnumAndroidScalerAvailableStreamUseCases>(useCase);
+ config3_8.streams = streams3_8;
+ config3_8.operationMode = StreamConfigurationMode::NORMAL_MODE;
+ config3_8.streamConfigCounter = streamConfigCounter;
+ config3_8.multiResolutionInputImage = false;
+ ret = cameraDevice3_8->isStreamCombinationSupported_3_8(
+ config3_8, [&useCaseSupported](Status s, bool combStatus) {
+ ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
+ if (Status::OK == s) {
+ ASSERT_EQ(combStatus, useCaseSupported);
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = session3_8->configureStreams_3_8(
+ config3_8,
+ [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
+ if (useCaseSupported) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(1u, halConfig.streams.size());
+ } else {
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ ret = session3_8->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+}
+
// Retrieve all valid output stream resolutions from the camera
// static characteristics.
Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
@@ -9042,6 +9183,7 @@
verifyExtendedSceneModeCharacteristics(metadata);
verifyZoomCharacteristics(metadata);
+ verifyStreamUseCaseCharacteristics(metadata);
}
void CameraHidlTest::verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata) {
@@ -9272,6 +9414,46 @@
}
}
+void CameraHidlTest::verifyStreamUseCaseCharacteristics(const camera_metadata_t* metadata) {
+ camera_metadata_ro_entry entry;
+ // Check capabilities
+ int retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ bool hasStreamUseCaseCap = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ if (std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE) !=
+ entry.data.u8 + entry.count) {
+ hasStreamUseCaseCap = true;
+ }
+ }
+
+ bool supportMandatoryUseCases = false;
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ supportMandatoryUseCases = true;
+ for (size_t i = 0; i < kMandatoryUseCases.size(); i++) {
+ if (std::find(entry.data.i32, entry.data.i32 + entry.count, kMandatoryUseCases[i])
+ == entry.data.i32 + entry.count) {
+ supportMandatoryUseCases = false;
+ break;
+ }
+ }
+ bool supportDefaultUseCase = false;
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.i32[i] == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+ supportDefaultUseCase = true;
+ }
+ ASSERT_TRUE(entry.data.i32[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL ||
+ entry.data.i32[i] >= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START);
+ }
+ ASSERT_TRUE(supportDefaultUseCase);
+ }
+
+ ASSERT_EQ(hasStreamUseCaseCap, supportMandatoryUseCases);
+}
+
void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
int deviceVersion) {
const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();