Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c14496f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Camera: Add support for empty physical settings optimization"

parents 72eb5eea e0c52bb1
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -370,7 +370,7 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ

        for (size_t i = 0; i < settingsCount; i++) {
            uint64_t settingsSize = request.physicalCameraSettings[i].fmqSettingsSize;
            const camera_metadata_t *settings;
            const camera_metadata_t *settings = nullptr;
            if (settingsSize > 0) {
                physicalFmq.push_back(V3_2::CameraMetadata(settingsSize));
                bool read = mRequestMetadataQueue->read(physicalFmq[i].data(), settingsSize);
@@ -392,6 +392,13 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ
                ALOGE("%s: physical camera settings metadata is corrupt!", __FUNCTION__);
                return Status::ILLEGAL_ARGUMENT;
            }

            if (mFirstRequest && settings == nullptr) {
                ALOGE("%s: Individual request settings must not be null for first request!",
                        __FUNCTION__);
                return Status::ILLEGAL_ARGUMENT;
            }

            physicalCameraIds.push_back(request.physicalCameraSettings[i].physicalCameraId.c_str());
        }
    }
+8 −3
Original line number Diff line number Diff line
@@ -177,9 +177,14 @@ struct PhysicalCameraSetting {

    /**
     * If fmqSettingsSize is zero, the settings buffer contains the capture and
     * processing parameters for the physical device with id 'phyCamId'.
     * In case the individual settings are empty or missing, Hal should fail the
     * request and return Status::ILLEGAL_ARGUMENT.
     * processing parameters for the physical device with id 'physicalCameraId'.
     * As a special case, an empty settings buffer indicates that the
     * settings are identical to the most-recently submitted capture request.
     * An empty buffer cannot be used as the first submitted request after
     * a configureStreams() call.
     *
     * This field must be used if fmqSettingsSize is zero. It must not be used
     * if fmqSettingsSize is non-zero.
     */
    CameraMetadata settings;
};
+157 −61
Original line number Diff line number Diff line
@@ -655,6 +655,13 @@ public:
    static Status isLogicalMultiCamera(camera_metadata_t *staticMeta);
    static Status getPhysicalCameraIds(camera_metadata_t *staticMeta,
            std::unordered_set<std::string> *physicalIds/*out*/);
    static Status getSupportedKeys(camera_metadata_t *staticMeta,
            uint32_t tagId, std::unordered_set<int32_t> *requestIDs/*out*/);
    static void constructFilteredSettings(const sp<ICameraDeviceSession>& session,
            const std::unordered_set<int32_t>& availableKeys, RequestTemplate reqTemplate,
            android::hardware::camera::common::V1_0::helper::CameraMetadata* defaultSettings/*out*/,
            android::hardware::camera::common::V1_0::helper::CameraMetadata* filteredSettings
            /*out*/);
    static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
            AvailableStream &hfrStream);
    static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
@@ -2748,42 +2755,23 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) {
        castSession(session, deviceVersion, &session3_3, &session3_4);
        ASSERT_NE(session3_4, nullptr);

        const android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
                staticMetaBuffer);
        camera_metadata_ro_entry availableSessionKeys = staticMeta.find(
                ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
        if (availableSessionKeys.count == 0) {
        std::unordered_set<int32_t> availableSessionKeys;
        auto rc = getSupportedKeys(staticMetaBuffer, ANDROID_REQUEST_AVAILABLE_SESSION_KEYS,
                &availableSessionKeys);
        ASSERT_TRUE(Status::OK == rc);
        if (availableSessionKeys.empty()) {
            free_camera_metadata(staticMetaBuffer);
            ret = session->close();
            ASSERT_TRUE(ret.isOk());
            continue;
        }

        android::hardware::camera::common::V1_0::helper::CameraMetadata previewRequestSettings;
        ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW,
                [&previewRequestSettings] (auto status, const auto& req) mutable {
                    ASSERT_EQ(Status::OK, status);

                    const camera_metadata_t *metadata = reinterpret_cast<const camera_metadata_t*> (
                            req.data());
                    size_t expectedSize = req.size();
                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
                    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));

                    size_t entryCount = get_camera_metadata_entry_count(metadata);
                    ASSERT_GT(entryCount, 0u);
                    previewRequestSettings = metadata;
                    });
        ASSERT_TRUE(ret.isOk());
        const android::hardware::camera::common::V1_0::helper::CameraMetadata &constSettings =
            previewRequestSettings;
        android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
        for (size_t i = 0; i < availableSessionKeys.count; i++) {
            camera_metadata_ro_entry entry = constSettings.find(availableSessionKeys.data.i32[i]);
            if (entry.count > 0) {
                sessionParams.update(entry);
            }
        }
        constructFilteredSettings(session, availableSessionKeys, RequestTemplate::PREVIEW,
                &previewRequestSettings, &sessionParams);
        if (sessionParams.isEmpty()) {
            free_camera_metadata(staticMetaBuffer);
            ret = session->close();
            ASSERT_TRUE(ret.isOk());
            continue;
@@ -2817,7 +2805,7 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) {
                });
        ASSERT_TRUE(ret.isOk());

        sessionParams.unlock(sessionParamsBuffer);
        free_camera_metadata(staticMetaBuffer);
        ret = session->close();
        ASSERT_TRUE(ret.isOk());
    }
@@ -3350,6 +3338,8 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
            continue;
        }
        std::string version, deviceId;
        ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &deviceId));
        camera_metadata_t* staticMeta;
        Return<void> ret;
        sp<ICameraDeviceSession> session;
@@ -3357,6 +3347,7 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {

        Status rc = isLogicalMultiCamera(staticMeta);
        if (Status::METHOD_NOT_SUPPORTED == rc) {
            free_camera_metadata(staticMeta);
            ret = session->close();
            ASSERT_TRUE(ret.isOk());
            continue;
@@ -3366,13 +3357,45 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
        ASSERT_TRUE(Status::OK == rc);
        ASSERT_TRUE(physicalIds.size() > 1);

        std::unordered_set<int32_t> physicalRequestKeyIDs;
        rc = getSupportedKeys(staticMeta,
                ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS, &physicalRequestKeyIDs);
        ASSERT_TRUE(Status::OK == rc);
        if (physicalRequestKeyIDs.empty()) {
            free_camera_metadata(staticMeta);
            ret = session->close();
            ASSERT_TRUE(ret.isOk());
            // The logical camera doesn't support any individual physical requests.
            continue;
        }

        // Leave only 2 physical devices in the id set.
        auto it = physicalIds.begin(); it++; it++;
        physicalIds.erase(it, physicalIds.end());
        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultPreviewSettings;
        android::hardware::camera::common::V1_0::helper::CameraMetadata filteredSettings;
        constructFilteredSettings(session, physicalRequestKeyIDs, RequestTemplate::PREVIEW,
                &defaultPreviewSettings, &filteredSettings);
        if (filteredSettings.isEmpty()) {
            // No physical device settings in default request.
            free_camera_metadata(staticMeta);
            ret = session->close();
            ASSERT_TRUE(ret.isOk());
            continue;
        }

        const camera_metadata_t *settingsBuffer = defaultPreviewSettings.getAndLock();
        settings.setToExternal(
                reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (settingsBuffer)),
                get_camera_metadata_size(settingsBuffer));

        free_camera_metadata(staticMeta);
        ret = session->close();
        ASSERT_TRUE(ret.isOk());

        auto it = physicalIds.begin();
        string physicalDeviceId = *it;
        // Leave only the first physical device in the id set and insert the logical device.
        physicalIds.erase(++it, physicalIds.end());
        physicalIds.emplace(deviceId);
        ASSERT_EQ(physicalIds.size(), 2u);

        V3_4::HalStreamConfiguration halStreamConfig;
        bool supportsPartialResults = false;
@@ -3400,38 +3423,34 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
                });
        ASSERT_TRUE(resultQueueRet.isOk());

        InFlightRequest inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
        InFlightRequest inflightReq = {static_cast<ssize_t> (halStreamConfig.streams.size()), false,
            supportsPartialResults, partialResultCount, resultQueue};

        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
        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);

        std::vector<sp<GraphicBuffer>> graphicBuffers;
        graphicBuffers.reserve(physicalIds.size());
        graphicBuffers.reserve(halStreamConfig.streams.size());
        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
        outputBuffers.resize(physicalIds.size());
        hidl_vec<V3_4::PhysicalCameraSetting> camSettings;
        camSettings.resize(physicalIds.size());
        outputBuffers.resize(halStreamConfig.streams.size());
        size_t k = 0;
        for (const auto physicalIdIt : physicalIds) {
        for (const auto& halStream : halStreamConfig.streams) {
            sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, previewStream.height,
                    static_cast<int32_t>(halStreamConfig.streams[k].v3_3.v3_2.overrideFormat), 1,
                    static_cast<int32_t>(halStream.v3_3.v3_2.overrideFormat), 1,
                    android_convertGralloc1To0Usage(
                        halStreamConfig.streams[k].v3_3.v3_2.producerUsage,
                        halStreamConfig.streams[k].v3_3.v3_2.consumerUsage));
                        halStream.v3_3.v3_2.producerUsage, halStream.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};
            outputBuffers[k] = {halStream.v3_3.v3_2.id, bufferId,
                hidl_handle(gb->getNativeBuffer()->handle), BufferStatus::OK, nullptr, nullptr};
            bufferId++;
            k++;
        }
        hidl_vec<V3_4::PhysicalCameraSetting> camSettings(1);
        const camera_metadata_t *filteredSettingsBuffer = filteredSettings.getAndLock();
        camSettings[0].settings.setToExternal(
                reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (
                        filteredSettingsBuffer)),
                get_camera_metadata_size(filteredSettingsBuffer));
        camSettings[0].fmqSettingsSize = 0;
        camSettings[0].physicalCameraId = physicalDeviceId;

        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
        V3_4::CaptureRequest request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
@@ -3468,24 +3487,49 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {

            ASSERT_FALSE(inflightReq.errorCodeValid);
            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);

            request.v3_2.frameNumber++;
            // Empty settings should be supported after the first call
            // for repeating requests.
            request.v3_2.settings.setToExternal(nullptr, 0, true);
            request.physicalCameraSettings[0].settings.setToExternal(nullptr, 0, true);
            // The buffer has been registered to HAL by bufferId, so per
            // API contract we should send a null handle for this buffer
            request.v3_2.outputBuffers[0].buffer = nullptr;
            mInflightMap.clear();
            inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
                supportsPartialResults, partialResultCount, resultQueue};
            mInflightMap.add(request.v3_2.frameNumber, &inflightReq);
        }

        // Empty physical camera settings should fail process requests
        camSettings[1].settings = emptySettings;
        frameNumber++;
        request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
            emptyInputBuffer, outputBuffers}, camSettings};
        returnStatus = session3_4->processCaptureRequest_3_4(
            {request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
                stat = s;
                numRequestProcessed = n;
            });
        ASSERT_TRUE(returnStatus.isOk());
        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
        ASSERT_EQ(Status::OK, stat);
        ASSERT_EQ(numRequestProcessed, 1u);

        {
            std::unique_lock<std::mutex> l(mLock);
            while (!inflightReq.errorCodeValid &&
                    ((0 < inflightReq.numBuffersLeft) ||
                     (!inflightReq.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(inflightReq.errorCodeValid);
            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
        }

        // Invalid physical camera id should fail process requests
        camSettings[1].physicalCameraId = invalidPhysicalId;
        camSettings[1].settings = settings;
        frameNumber++;
        camSettings[0].physicalCameraId = invalidPhysicalId;
        camSettings[0].settings = settings;
        request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
            emptyInputBuffer, outputBuffers}, camSettings};
        returnStatus = session3_4->processCaptureRequest_3_4(
@@ -3496,6 +3540,8 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
        ASSERT_TRUE(returnStatus.isOk());
        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);

        defaultPreviewSettings.unlock(settingsBuffer);
        filteredSettings.unlock(filteredSettingsBuffer);
        ret = session3_4->close();
        ASSERT_TRUE(ret.isOk());
    }
@@ -3901,6 +3947,56 @@ Status CameraHidlTest::getPhysicalCameraIds(camera_metadata_t *staticMeta,
    return Status::OK;
}

// Generate a set of suported camera key ids.
Status CameraHidlTest::getSupportedKeys(camera_metadata_t *staticMeta,
        uint32_t tagId, std::unordered_set<int32_t> *requestIDs) {
    if ((nullptr == staticMeta) || (nullptr == requestIDs)) {
        return Status::ILLEGAL_ARGUMENT;
    }

    camera_metadata_ro_entry entry;
    int rc = find_camera_metadata_ro_entry(staticMeta, tagId, &entry);
    if ((0 != rc) || (entry.count == 0)) {
        return Status::OK;
    }

    requestIDs->insert(entry.data.i32, entry.data.i32 + entry.count);

    return Status::OK;
}

void CameraHidlTest::constructFilteredSettings(const sp<ICameraDeviceSession>& session,
        const std::unordered_set<int32_t>& availableKeys, RequestTemplate reqTemplate,
        android::hardware::camera::common::V1_0::helper::CameraMetadata* defaultSettings,
        android::hardware::camera::common::V1_0::helper::CameraMetadata* filteredSettings) {
    ASSERT_NE(defaultSettings, nullptr);
    ASSERT_NE(filteredSettings, nullptr);

    auto ret = session->constructDefaultRequestSettings(reqTemplate,
            [&defaultSettings] (auto status, const auto& req) mutable {
                ASSERT_EQ(Status::OK, status);

                const camera_metadata_t *metadata = reinterpret_cast<const camera_metadata_t*> (
                        req.data());
                size_t expectedSize = req.size();
                int result = validate_camera_metadata_structure(metadata, &expectedSize);
                ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));

                size_t entryCount = get_camera_metadata_entry_count(metadata);
                ASSERT_GT(entryCount, 0u);
                *defaultSettings = metadata;
                });
    ASSERT_TRUE(ret.isOk());
    const android::hardware::camera::common::V1_0::helper::CameraMetadata &constSettings =
        *defaultSettings;
    for (const auto& keyIt : availableKeys) {
        camera_metadata_ro_entry entry = constSettings.find(keyIt);
        if (entry.count > 0) {
            filteredSettings->update(entry);
        }
    }
}

// Check if constrained mode is supported by using the static
// camera characteristics.
Status CameraHidlTest::isConstrainedModeAvailable(camera_metadata_t *staticMeta) {