Camera: Add new camera metadata for settings override frame number
Add a frame number field in HAL capture result metadata to indicate
the frame number of newer request overriding this capture.
This is needed so that ZoomRatioMapper can look up the newer request's
zoom ratio.
Also add VTS test for transition between OFF and ZOOM.
Test: Camera VTS on cuttlefish
Bug: 239822823
Change-Id: I7439950cdb9f346bf36c4cc872fd7865eb9cf669
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 617979d..ecbfc93 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -94,9 +94,10 @@
ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION = 65584,
ANDROID_CONTROL_SETTINGS_OVERRIDE = 65588,
ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES = 65589,
- ANDROID_CONTROL_AUTOFRAMING = 65590,
- ANDROID_CONTROL_AUTOFRAMING_AVAILABLE = 65591,
- ANDROID_CONTROL_AUTOFRAMING_STATE = 65592,
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER = 65590,
+ ANDROID_CONTROL_AUTOFRAMING = 65591,
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE = 65592,
+ ANDROID_CONTROL_AUTOFRAMING_STATE = 65593,
ANDROID_DEMOSAIC_MODE = 131072,
ANDROID_EDGE_MODE = 196608,
ANDROID_EDGE_STRENGTH = 196609,
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 85e56bc..2e9bde9 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -464,6 +464,12 @@
*/
ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
/**
+ * android.control.settingsOverridingFrameNumber [dynamic, int32, system]
+ *
+ * <p>The frame number of the newer request overriding this capture.</p>
+ */
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER,
+ /**
* android.control.autoframing [dynamic, enum, public]
*
* <p>Automatic crop, pan and zoom to keep objects in the center of the frame.</p>
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 017f6ef..747ea33 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -2065,6 +2065,28 @@
}
}
+TEST_P(CameraAidlTest, processZoomSettingsOverrideRequests) {
+ const int32_t kFrameCount = 5;
+ const int32_t kTestCases = 2;
+ const bool kOverrideSequence[kTestCases][kFrameCount] = {
+ // ZOOM, ZOOM, ZOOM, ZOOM, ZOOM;
+ { true, true, true, true, true },
+ // OFF, OFF, ZOOM, ZOOM, OFF;
+ { false, false, true, true, false } };
+ const bool kExpectedOverrideResults[kTestCases][kFrameCount] = {
+ // All resuls should be overridden except the last one. The last result's
+ // zoom doesn't have speed-up.
+ { true, true, true, true, false },
+ // Because we require at least 2 frames speed-up, request #1, #2 and #3
+ // will be overridden.
+ { true, true, true, false, false } };
+
+ for (int i = 0; i < kTestCases; i++) {
+ processZoomSettingsOverrideRequests(kFrameCount, kOverrideSequence[i],
+ kExpectedOverrideResults[i]);
+ }
+}
+
// Generate and verify a burst containing alternating sensor sensitivity values
TEST_P(CameraAidlTest, processCaptureRequestBurstISO) {
std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index ca316e5..b9e30ab 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -363,10 +363,15 @@
retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
bool hasSettingsOverrideResultKey = false;
+ bool hasOverridingFrameNumberKey = false;
if ((0 == retcode) && (entry.count > 0)) {
hasSettingsOverrideResultKey =
std::find(entry.data.i32, entry.data.i32 + entry.count,
ANDROID_CONTROL_SETTINGS_OVERRIDE) != entry.data.i32 + entry.count;
+ hasOverridingFrameNumberKey =
+ std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER)
+ != entry.data.i32 + entry.count;
} else {
ADD_FAILURE() << "Get camera availableResultKeys failed!";
}
@@ -385,6 +390,7 @@
ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideRequestKey);
ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideResultKey);
+ ASSERT_EQ(supportSettingsOverride, hasOverridingFrameNumberKey);
ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideCharacteristicsKey);
}
@@ -1579,7 +1585,7 @@
// Check settings override
camera_metadata_ro_entry settingsOverrideEntry;
int foundSettingsOverride = find_camera_metadata_ro_entry(metadata,
- ANDROID_CONTROL_SETTINGS_OVERRIDE,&settingsOverrideEntry);
+ ANDROID_CONTROL_SETTINGS_OVERRIDE, &settingsOverrideEntry);
if (foundSettingsOverride == 0) {
ASSERT_EQ(settingsOverrideEntry.count, 1);
ASSERT_EQ(settingsOverrideEntry.data.u8[0], ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF);
@@ -3019,6 +3025,30 @@
}
}
+bool CameraAidlTest::supportZoomSettingsOverride(const camera_metadata_t* staticMeta) {
+ camera_metadata_ro_entry availableOverridesEntry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
+ &availableOverridesEntry);
+ if (rc == 0) {
+ for (size_t i = 0; i < availableOverridesEntry.count; i++) {
+ if (availableOverridesEntry.data.i32[i] == ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool CameraAidlTest::isPerFrameControl(const camera_metadata_t* staticMeta) {
+ camera_metadata_ro_entry syncLatencyEntry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SYNC_MAX_LATENCY,
+ &syncLatencyEntry);
+ if (rc == 0 && syncLatencyEntry.data.i32[0] == ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL) {
+ return true;
+ }
+ return false;
+}
+
void CameraAidlTest::configurePreviewStream(
const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
const AvailableStream* previewThreshold, std::shared_ptr<ICameraDeviceSession>* session,
@@ -3385,3 +3415,158 @@
ASSERT_TRUE(ret.isOk());
}
}
+
+void CameraAidlTest::processZoomSettingsOverrideRequests(
+ int32_t frameCount, const bool *overrideSequence, const bool *expectedResults) {
+ std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ int64_t bufferId = 1;
+ int32_t frameNumber = 1;
+ CameraMetadata settings;
+ ndk::ScopedAStatus ret;
+ for (const auto& name : cameraDeviceNames) {
+ CameraMetadata meta;
+ std::shared_ptr<ICameraDevice> device;
+ openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+ &device /*out*/);
+ camera_metadata_t* staticMeta =
+ clone_camera_metadata(reinterpret_cast<camera_metadata_t*>(meta.metadata.data()));
+
+ ret = mSession->close();
+ mSession = nullptr;
+ ASSERT_TRUE(ret.isOk());
+
+ // Device does not support zoom settnigs override
+ if (!supportZoomSettingsOverride(staticMeta)) {
+ continue;
+ }
+
+ if (!isPerFrameControl(staticMeta)) {
+ continue;
+ }
+
+ bool supportsPartialResults = false;
+ bool useHalBufManager = false;
+ int32_t partialResultCount = 0;
+ Stream previewStream;
+ std::vector<HalStream> halStreams;
+ std::shared_ptr<DeviceCb> cb;
+ configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+ &previewStream /*out*/, &halStreams /*out*/,
+ &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+ &useHalBufManager /*out*/, &cb /*out*/);
+ ASSERT_NE(mSession, nullptr);
+
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ descriptor;
+ auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+ ASSERT_TRUE(resultQueueRet.isOk());
+
+ std::shared_ptr<ResultMetadataQueue> resultQueue =
+ std::make_shared<ResultMetadataQueue>(descriptor);
+ if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+ ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+ resultQueue = nullptr;
+ // Don't use the queue onwards.
+ }
+
+ ret = mSession->constructDefaultRequestSettings(RequestTemplate::PREVIEW, &settings);
+ ASSERT_TRUE(ret.isOk());
+
+ mInflightMap.clear();
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+ std::vector<CaptureRequest> requests(frameCount);
+ std::vector<buffer_handle_t> buffers(frameCount);
+ std::vector<std::shared_ptr<InFlightRequest>> inflightReqs(frameCount);
+ std::vector<CameraMetadata> requestSettings(frameCount);
+
+ for (int32_t i = 0; i < frameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+ CaptureRequest& request = requests[i];
+ std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+ outputBuffers.resize(1);
+ StreamBuffer& outputBuffer = outputBuffers[0];
+
+ if (useHalBufManager) {
+ outputBuffer = {halStreams[0].id, 0,
+ NativeHandle(), BufferStatus::OK,
+ NativeHandle(), NativeHandle()};
+ } else {
+ allocateGraphicBuffer(previewStream.width, previewStream.height,
+ android_convertGralloc1To0Usage(
+ static_cast<uint64_t>(halStreams[0].producerUsage),
+ static_cast<uint64_t>(halStreams[0].consumerUsage)),
+ halStreams[0].overrideFormat, &buffers[i]);
+ outputBuffer = {halStreams[0].id, bufferId + i, ::android::makeToAidl(buffers[i]),
+ BufferStatus::OK, NativeHandle(), NativeHandle()};
+ }
+
+ // Set appropriate settings override tag
+ requestMeta.append(reinterpret_cast<camera_metadata_t*>(settings.metadata.data()));
+ int32_t settingsOverride = overrideSequence[i] ?
+ ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM : ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF;
+ ASSERT_EQ(::android::OK, requestMeta.update(ANDROID_CONTROL_SETTINGS_OVERRIDE,
+ &settingsOverride, 1));
+ camera_metadata_t* metaBuffer = requestMeta.release();
+ uint8_t* rawMetaBuffer = reinterpret_cast<uint8_t*>(metaBuffer);
+ requestSettings[i].metadata = std::vector(
+ rawMetaBuffer, rawMetaBuffer + get_camera_metadata_size(metaBuffer));
+ overrideRotateAndCrop(&(requestSettings[i]));
+ request.frameNumber = frameNumber + i;
+ request.fmqSettingsSize = 0;
+ request.settings = requestSettings[i];
+ request.inputBuffer = {
+ -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+
+ inflightReqs[i] = std::make_shared<InFlightRequest>(1, false, supportsPartialResults,
+ partialResultCount, resultQueue);
+ mInflightMap[frameNumber + i] = inflightReqs[i];
+ }
+
+ int32_t numRequestProcessed = 0;
+ std::vector<BufferCache> cachesToRemove;
+
+ ndk::ScopedAStatus returnStatus =
+ mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(numRequestProcessed, frameCount);
+
+ for (size_t i = 0; i < frameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+ while (!inflightReqs[i]->errorCodeValid && ((0 < inflightReqs[i]->numBuffersLeft) ||
+ (!inflightReqs[i]->haveResultMetadata))) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+ }
+
+ ASSERT_FALSE(inflightReqs[i]->errorCodeValid);
+ ASSERT_NE(inflightReqs[i]->resultOutputBuffers.size(), 0u);
+ ASSERT_EQ(previewStream.id, inflightReqs[i]->resultOutputBuffers[0].buffer.streamId);
+ ASSERT_FALSE(inflightReqs[i]->collectedResult.isEmpty());
+ ASSERT_TRUE(inflightReqs[i]->collectedResult.exists(ANDROID_CONTROL_SETTINGS_OVERRIDE));
+ camera_metadata_entry_t overrideResult =
+ inflightReqs[i]->collectedResult.find(ANDROID_CONTROL_SETTINGS_OVERRIDE);
+ ASSERT_EQ(overrideResult.data.i32[0] == ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM,
+ expectedResults[i]);
+ ASSERT_TRUE(inflightReqs[i]->collectedResult.exists(
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER));
+ camera_metadata_entry_t frameNumberEntry = inflightReqs[i]->collectedResult.find(
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER);
+ ALOGV("%s: i %zu, expcetedResults[i] %d, overrideResult is %d, frameNumber %d",
+ __FUNCTION__, i, expectedResults[i], overrideResult.data.i32[0],
+ frameNumberEntry.data.i32[0]);
+ if (expectedResults[i]) {
+ ASSERT_GT(frameNumberEntry.data.i32[0], inflightReqs[i]->frameNumber);
+ } else {
+ ASSERT_EQ(frameNumberEntry.data.i32[0], frameNumber + i);
+ }
+ }
+
+ ret = mSession->close();
+ mSession = nullptr;
+ ASSERT_TRUE(ret.isOk());
+ }
+}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index ff3617f..b6e398b 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -406,6 +406,12 @@
aidl::android::hardware::camera::metadata::
RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile);
+ void processZoomSettingsOverrideRequests(
+ int32_t frameCount, const bool *overrideSequence, const bool *expectedResults);
+
+ bool supportZoomSettingsOverride(const camera_metadata_t* staticMeta);
+ bool isPerFrameControl(const camera_metadata_t* staticMeta);
+
protected:
// In-flight queue for tracking completion of capture requests.
struct InFlightRequest {