camera: Update multi-camera capture VTS case
Individual physical camera requests should only be allowed
in case the respective physical Ids are among the last
configured Hal streams.
Bug: 72524603
Test: run vts --skip-all-system-status-check --skip-preconditions
--primary-abi-only --module VtsHalCameraProviderV2_4Target -l INFO
Change-Id: Ia5715398f74f03528d7fe2e52e5b9e32ad654a2c
diff --git a/camera/device/3.4/types.hal b/camera/device/3.4/types.hal
index d80ab67..c8ebb17 100644
--- a/camera/device/3.4/types.hal
+++ b/camera/device/3.4/types.hal
@@ -185,7 +185,9 @@
* PhysicalCameraSetting:
*
* Individual camera settings for logical camera backed by multiple physical devices.
- * Clients are allowed to pass separate settings for each physical device.
+ * Clients are allowed to pass separate settings for each physical device that has
+ * corresponding configured HalStream and the respective stream id is present in the
+ * output buffers of the capture request.
*/
struct PhysicalCameraSetting {
/**
@@ -197,8 +199,9 @@
/**
* Contains the physical device camera id. Any settings passed by client here
- * should be applied for this physical device. In case the physical id is invalid
- * Hal should fail the process request and return Status::ILLEGAL_ARGUMENT.
+ * should be applied for this physical device. In case the physical id is invalid or
+ * it is not present among the last configured streams, Hal should fail the process
+ * request and return Status::ILLEGAL_ARGUMENT.
*/
string physicalCameraId;
@@ -238,7 +241,12 @@
/**
* A vector containing individual camera settings for logical camera backed by multiple physical
- * devices. In case the vector is empty, Hal should use the settings field in 'v3_2'.
+ * devices. In case the vector is empty, Hal should use the settings field in 'v3_2'. The
+ * individual settings should only be honored for physical devices that have respective Hal
+ * stream. Physical devices that have a corresponding Hal stream but don't have attached
+ * settings here should use the settings field in 'v3_2'.
+ * If any of the physical settings in the array are applied on one or more devices, then the
+ * visual effect on any Hal streams attached to the logical camera is undefined.
*/
vec<PhysicalCameraSetting> physicalCameraSettings;
};
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 4652efd..1405ea9 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -20,6 +20,7 @@
#include <mutex>
#include <regex>
#include <unordered_map>
+#include <unordered_set>
#include <condition_variable>
#include <inttypes.h>
@@ -28,6 +29,7 @@
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
@@ -531,8 +533,10 @@
}
};
- struct DeviceCb : public ICameraDeviceCallback {
+ struct DeviceCb : public V3_4::ICameraDeviceCallback {
DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+ Return<void> processCaptureResult_3_4(
+ const hidl_vec<V3_4::CaptureResult>& results) override;
Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
@@ -627,6 +631,15 @@
::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2,
::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4);
+ void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
+ sp<ICameraProvider> provider,
+ const AvailableStream *previewThreshold,
+ const std::unordered_set<std::string>& physicalIds,
+ sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+ V3_2::Stream* previewStream /*out*/,
+ device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
+ bool *supportsPartialResults /*out*/,
+ uint32_t *partialResultCount /*out*/);
void configurePreviewStream(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,
const AvailableStream *previewThreshold,
@@ -641,7 +654,7 @@
static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
static Status isLogicalMultiCamera(camera_metadata_t *staticMeta);
static Status getPhysicalCameraIds(camera_metadata_t *staticMeta,
- std::vector<std::string> *physicalIds/*out*/);
+ std::unordered_set<std::string> *physicalIds/*out*/);
static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
AvailableStream &hfrStream);
static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
@@ -844,6 +857,27 @@
return Void();
}
+Return<void> CameraHidlTest::DeviceCb::processCaptureResult_3_4(
+ const hidl_vec<V3_4::CaptureResult>& results) {
+
+ if (nullptr == mParent) {
+ return Void();
+ }
+
+ bool notify = false;
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ for (size_t i = 0 ; i < results.size(); i++) {
+ notify = processCaptureResultLocked(results[i].v3_2);
+ }
+
+ l.unlock();
+ if (notify) {
+ mParent->mResultCondition.notify_one();
+ }
+
+ return Void();
+}
+
Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
const hidl_vec<CaptureResult>& results) {
if (nullptr == mParent) {
@@ -3304,7 +3338,7 @@
TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
- static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
@@ -3327,7 +3361,7 @@
ASSERT_TRUE(ret.isOk());
continue;
}
- std::vector<std::string> physicalIds;
+ std::unordered_set<std::string> physicalIds;
rc = getPhysicalCameraIds(staticMeta, &physicalIds);
ASSERT_TRUE(Status::OK == rc);
ASSERT_TRUE(physicalIds.size() > 1);
@@ -3336,22 +3370,23 @@
ret = session->close();
ASSERT_TRUE(ret.isOk());
- V3_2::Stream previewStream;
- HalStreamConfiguration halStreamConfig;
+ // Leave only 2 physical devices in the id set.
+ auto it = physicalIds.begin(); it++; it++;
+ physicalIds.erase(it, physicalIds.end());
+
+ V3_4::HalStreamConfiguration halStreamConfig;
bool supportsPartialResults = false;
uint32_t partialResultCount = 0;
- configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
- &previewStream /*out*/, &halStreamConfig /*out*/,
- &supportsPartialResults /*out*/,
- &partialResultCount /*out*/);
- sp<device::V3_3::ICameraDeviceSession> session3_3;
+ V3_2::Stream previewStream;
sp<device::V3_4::ICameraDeviceSession> session3_4;
- castSession(session, deviceVersion, &session3_3, &session3_4);
+ configurePreviewStreams3_4(name, deviceVersion, mProvider, &previewThreshold, physicalIds,
+ &session3_4, &previewStream, &halStreamConfig /*out*/,
+ &supportsPartialResults /*out*/, &partialResultCount /*out*/);
ASSERT_NE(session3_4, nullptr);
std::shared_ptr<ResultMetadataQueue> resultQueue;
auto resultQueueRet =
- session->getCaptureResultMetadataQueue(
+ session3_4->getCaptureResultMetadataQueue(
[&resultQueue](const auto& descriptor) {
resultQueue = std::make_shared<ResultMetadataQueue>(
descriptor);
@@ -3365,38 +3400,40 @@
});
ASSERT_TRUE(resultQueueRet.isOk());
- InFlightRequest inflightReq = {1, false, supportsPartialResults,
- partialResultCount, resultQueue};
+ InFlightRequest inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
+ supportsPartialResults, partialResultCount, resultQueue};
RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
- ret = session->constructDefaultRequestSettings(reqTemplate,
+ ret = session3_4->constructDefaultRequestSettings(reqTemplate,
[&](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
settings = req;
});
ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(settings.size() > 0);
- sp<GraphicBuffer> gb = new GraphicBuffer(
- previewStream.width, previewStream.height,
- static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
- android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
- halStreamConfig.streams[0].consumerUsage));
- ASSERT_NE(nullptr, gb.get());
+ std::vector<sp<GraphicBuffer>> graphicBuffers;
+ graphicBuffers.reserve(physicalIds.size());
::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
- outputBuffers.resize(1);
- outputBuffers[0] = {halStreamConfig.streams[0].id,
- bufferId,
- hidl_handle(gb->getNativeBuffer()->handle),
- BufferStatus::OK,
- nullptr,
- nullptr};
-
- StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
- nullptr};
+ outputBuffers.resize(physicalIds.size());
hidl_vec<V3_4::PhysicalCameraSetting> camSettings;
- camSettings.resize(2);
- camSettings[0] = {0, hidl_string(physicalIds[0]), settings};
- camSettings[1] = {0, hidl_string(physicalIds[1]), settings};
+ camSettings.resize(physicalIds.size());
+ size_t k = 0;
+ for (const auto physicalIdIt : physicalIds) {
+ sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, previewStream.height,
+ static_cast<int32_t>(halStreamConfig.streams[k].v3_3.v3_2.overrideFormat), 1,
+ android_convertGralloc1To0Usage(
+ halStreamConfig.streams[k].v3_3.v3_2.producerUsage,
+ halStreamConfig.streams[k].v3_3.v3_2.consumerUsage));
+ ASSERT_NE(nullptr, gb.get());
+ outputBuffers[k] = {halStreamConfig.streams[k].v3_3.v3_2.id, bufferId,
+ hidl_handle(gb->getNativeBuffer()->handle), BufferStatus::OK, nullptr, nullptr};
+ graphicBuffers.push_back(gb);
+ camSettings[k] = {0, hidl_string(physicalIdIt), settings};
+ k++;
+ }
+
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
V3_4::CaptureRequest request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
emptyInputBuffer, outputBuffers}, camSettings};
@@ -3421,22 +3458,20 @@
{
std::unique_lock<std::mutex> l(mLock);
while (!inflightReq.errorCodeValid &&
- ((0 < inflightReq.numBuffersLeft) ||
- (!inflightReq.haveResultMetadata))) {
+ ((0 < inflightReq.numBuffersLeft) ||
+ (!inflightReq.haveResultMetadata))) {
auto timeout = std::chrono::system_clock::now() +
- std::chrono::seconds(kStreamBufferTimeoutSec);
+ std::chrono::seconds(kStreamBufferTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mResultCondition.wait_until(l, timeout));
}
ASSERT_FALSE(inflightReq.errorCodeValid);
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
- ASSERT_EQ(halStreamConfig.streams[0].id,
- inflightReq.resultOutputBuffers[0].streamId);
}
// Empty physical camera settings should fail process requests
- camSettings[1] = {0, hidl_string(physicalIds[1]), emptySettings};
+ camSettings[1].settings = emptySettings;
frameNumber++;
request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
emptyInputBuffer, outputBuffers}, camSettings};
@@ -3449,7 +3484,8 @@
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
// Invalid physical camera id should fail process requests
- camSettings[1] = {0, invalidPhysicalId, settings};
+ camSettings[1].physicalCameraId = invalidPhysicalId;
+ camSettings[1].settings = settings;
request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
emptyInputBuffer, outputBuffers}, camSettings};
returnStatus = session3_4->processCaptureRequest_3_4(
@@ -3460,7 +3496,7 @@
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
- ret = session->close();
+ ret = session3_4->close();
ASSERT_TRUE(ret.isOk());
}
}
@@ -3838,7 +3874,7 @@
// Generate a list of physical camera ids backing a logical multi-camera.
Status CameraHidlTest::getPhysicalCameraIds(camera_metadata_t *staticMeta,
- std::vector<std::string> *physicalIds) {
+ std::unordered_set<std::string> *physicalIds) {
if ((nullptr == staticMeta) || (nullptr == physicalIds)) {
return Status::ILLEGAL_ARGUMENT;
}
@@ -3856,7 +3892,7 @@
if (ids[i] == '\0') {
if (start != i) {
std::string currentId(reinterpret_cast<const char *> (ids + start));
- physicalIds->push_back(currentId);
+ physicalIds->emplace(currentId);
}
start = i + 1;
}
@@ -4028,6 +4064,111 @@
*config3_2 = {streams3_2, configMode};
}
+// Configure multiple preview streams using different physical ids.
+void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
+ sp<ICameraProvider> provider,
+ const AvailableStream *previewThreshold,
+ const std::unordered_set<std::string>& physicalIds,
+ sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+ V3_2::Stream *previewStream /*out*/,
+ device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
+ bool *supportsPartialResults /*out*/,
+ uint32_t *partialResultCount /*out*/) {
+ ASSERT_NE(nullptr, session3_4);
+ ASSERT_NE(nullptr, halStreamConfig);
+ ASSERT_NE(nullptr, previewStream);
+ ASSERT_NE(nullptr, supportsPartialResults);
+ ASSERT_NE(nullptr, partialResultCount);
+ ASSERT_FALSE(physicalIds.empty());
+
+ std::vector<AvailableStream> outputPreviewStreams;
+ ::android::sp<ICameraDevice> device3_x;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = provider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_x = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<DeviceCb> cb = new DeviceCb(this);
+ sp<ICameraDeviceSession> session;
+ ret = device3_x->open(
+ cb,
+ [&session](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<device::V3_3::ICameraDeviceSession> session3_3;
+ castSession(session, deviceVersion, &session3_3, session3_4);
+ ASSERT_NE(nullptr, session3_4);
+
+ camera_metadata_t *staticMeta;
+ ret = device3_x->getCameraCharacteristics([&] (Status s,
+ CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ staticMeta = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+ ASSERT_NE(nullptr, staticMeta);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ camera_metadata_ro_entry entry;
+ auto status = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+ if ((0 == status) && (entry.count > 0)) {
+ *partialResultCount = entry.data.i32[0];
+ *supportsPartialResults = (*partialResultCount > 1);
+ }
+
+ outputPreviewStreams.clear();
+ auto rc = getAvailableOutputStreams(staticMeta,
+ outputPreviewStreams, previewThreshold);
+ free_camera_metadata(staticMeta);
+ ASSERT_EQ(Status::OK, rc);
+ ASSERT_FALSE(outputPreviewStreams.empty());
+
+ ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(physicalIds.size());
+ int32_t streamId = 0;
+ for (auto const& physicalId : physicalIds) {
+ V3_4::Stream stream3_4 = {{streamId, StreamType::OUTPUT,
+ static_cast<uint32_t> (outputPreviewStreams[0].width),
+ static_cast<uint32_t> (outputPreviewStreams[0].height),
+ static_cast<PixelFormat> (outputPreviewStreams[0].format),
+ GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0},
+ physicalId.c_str(), /*bufferSize*/ 0};
+ streams3_4[streamId++] = stream3_4;
+ }
+
+ ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+ config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
+ RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+ ret = (*session3_4)->constructDefaultRequestSettings(reqTemplate,
+ [&config3_4](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ config3_4.sessionParams = req;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = (*session3_4)->configureStreams_3_4(config3_4,
+ [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
+ *halStreamConfig = halConfig;
+ });
+ *previewStream = streams3_4[0].v3_2;
+ ASSERT_TRUE(ret.isOk());
+}
+
// Open a device session and configure a preview stream.
void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,