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

Commit 9255ce08 authored by Jayant Chowdhary's avatar Jayant Chowdhary
Browse files

camera: Add crop and metering region correction for max resolution requests.



Capture request templates, assume default sensor pixel mode requests. As
a result, the coordinate system of the scaler crop region matches the
ones used for default sensor pixel mode. We need to correct these for
max resolution sensor pixel mode requests, if they haven't been set by
the client.

Bug: 194143991

Test: Camera CTS; manually see that emulator hal gets crop regions ==
      max res active array size.

Change-Id: I06769fd29a5fee9c21c75f151e516f150317148f
Signed-off-by: default avatarJayant Chowdhary <jchowdhary@google.com>
parent 0d0a5832
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -83,6 +83,7 @@ cc_library_shared {
        "device3/Camera3OutputStreamInterface.cpp",
        "device3/Camera3OutputStreamInterface.cpp",
        "device3/Camera3OutputUtils.cpp",
        "device3/Camera3OutputUtils.cpp",
        "device3/Camera3DeviceInjectionMethods.cpp",
        "device3/Camera3DeviceInjectionMethods.cpp",
        "device3/UHRCropAndMeteringRegionMapper.cpp",
        "gui/RingBufferConsumer.cpp",
        "gui/RingBufferConsumer.cpp",
        "hidl/AidlCameraDeviceCallbacks.cpp",
        "hidl/AidlCameraDeviceCallbacks.cpp",
        "hidl/AidlCameraServiceListener.cpp",
        "hidl/AidlCameraServiceListener.cpp",
+34 −1
Original line number Original line Diff line number Diff line
@@ -171,6 +171,13 @@ status_t Camera3Device::initialize(sp<CameraProviderManager> manager, const Stri
            mZoomRatioMappers[physicalId] = ZoomRatioMapper(
            mZoomRatioMappers[physicalId] = ZoomRatioMapper(
                    &mPhysicalDeviceInfoMap[physicalId],
                    &mPhysicalDeviceInfoMap[physicalId],
                    mSupportNativeZoomRatio, usePrecorrectArray);
                    mSupportNativeZoomRatio, usePrecorrectArray);

            if (SessionConfigurationUtils::isUltraHighResolutionSensor(
                    mPhysicalDeviceInfoMap[physicalId])) {
                mUHRCropAndMeteringRegionMappers[physicalId] =
                        UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
                                usePrecorrectArray);
            }
        }
        }
    }
    }


@@ -348,6 +355,11 @@ status_t Camera3Device::initializeCommonLocked() {
    mZoomRatioMappers[mId.c_str()] = ZoomRatioMapper(&mDeviceInfo,
    mZoomRatioMappers[mId.c_str()] = ZoomRatioMapper(&mDeviceInfo,
            mSupportNativeZoomRatio, usePrecorrectArray);
            mSupportNativeZoomRatio, usePrecorrectArray);


    if (SessionConfigurationUtils::isUltraHighResolutionSensor(mDeviceInfo)) {
        mUHRCropAndMeteringRegionMappers[mId.c_str()] =
                UHRCropAndMeteringRegionMapper(mDeviceInfo, usePrecorrectArray);
    }

    if (RotateAndCropMapper::isNeeded(&mDeviceInfo)) {
    if (RotateAndCropMapper::isNeeded(&mDeviceInfo)) {
        mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
        mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
    }
    }
@@ -4826,10 +4838,31 @@ status_t Camera3Device::RequestThread::prepareHalRequests() {
            }
            }


            {
            {
                // Correct metadata regions for distortion correction if enabled
                sp<Camera3Device> parent = mParent.promote();
                sp<Camera3Device> parent = mParent.promote();
                if (parent != nullptr) {
                if (parent != nullptr) {
                    List<PhysicalCameraSettings>::iterator it;
                    List<PhysicalCameraSettings>::iterator it;
                    for (it = captureRequest->mSettingsList.begin();
                            it != captureRequest->mSettingsList.end(); it++) {
                        if (parent->mUHRCropAndMeteringRegionMappers.find(it->cameraId) ==
                                parent->mUHRCropAndMeteringRegionMappers.end()) {
                            continue;
                        }

                        if (!captureRequest->mUHRCropAndMeteringRegionsUpdated) {
                            res = parent->mUHRCropAndMeteringRegionMappers[it->cameraId].
                                    updateCaptureRequest(&(it->metadata));
                            if (res != OK) {
                                SET_ERR("RequestThread: Unable to correct capture requests "
                                        "for scaler crop region and metering regions for request "
                                        "%d: %s (%d)", halRequest->frame_number, strerror(-res),
                                        res);
                                return INVALID_OPERATION;
                            }
                            captureRequest->mUHRCropAndMeteringRegionsUpdated = true;
                        }
                    }

                    // Correct metadata regions for distortion correction if enabled
                    for (it = captureRequest->mSettingsList.begin();
                    for (it = captureRequest->mSettingsList.begin();
                            it != captureRequest->mSettingsList.end(); it++) {
                            it != captureRequest->mSettingsList.end(); it++) {
                        if (parent->mDistortionMappers.find(it->cameraId) ==
                        if (parent->mDistortionMappers.find(it->cameraId) ==
+10 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@
#include "device3/DistortionMapper.h"
#include "device3/DistortionMapper.h"
#include "device3/ZoomRatioMapper.h"
#include "device3/ZoomRatioMapper.h"
#include "device3/RotateAndCropMapper.h"
#include "device3/RotateAndCropMapper.h"
#include "device3/UHRCropAndMeteringRegionMapper.h"
#include "device3/InFlightRequest.h"
#include "device3/InFlightRequest.h"
#include "device3/Camera3OutputInterface.h"
#include "device3/Camera3OutputInterface.h"
#include "device3/Camera3OfflineSession.h"
#include "device3/Camera3OfflineSession.h"
@@ -589,6 +590,9 @@ class Camera3Device :
        bool                                mRotationAndCropUpdated = false;
        bool                                mRotationAndCropUpdated = false;
        // Whether this capture request's zoom ratio update has been done.
        // Whether this capture request's zoom ratio update has been done.
        bool                                mZoomRatioUpdated = false;
        bool                                mZoomRatioUpdated = false;
        // Whether this max resolution capture request's  crop / metering region update has been
        // done.
        bool                                mUHRCropAndMeteringRegionsUpdated = false;
    };
    };
    typedef List<sp<CaptureRequest> > RequestList;
    typedef List<sp<CaptureRequest> > RequestList;


@@ -1229,6 +1233,12 @@ class Camera3Device :
     */
     */
    std::unordered_map<std::string, camera3::ZoomRatioMapper> mZoomRatioMappers;
    std::unordered_map<std::string, camera3::ZoomRatioMapper> mZoomRatioMappers;


    /**
     * UHR request crop / metering region mapper support
     */
    std::unordered_map<std::string, camera3::UHRCropAndMeteringRegionMapper>
            mUHRCropAndMeteringRegionMappers;

    /**
    /**
     * RotateAndCrop mapper support
     * RotateAndCrop mapper support
     */
     */
+168 −0
Original line number Original line Diff line number Diff line
/*
 * 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_TAG "Camera3-UHRCropAndMeteringRegionMapper"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0

#include <algorithm>
#include <cmath>

#include "device3/UHRCropAndMeteringRegionMapper.h"
#include "utils/SessionConfigurationUtils.h"

namespace android {

namespace camera3 {
// For Capture request
// metering region -> {fwk private key for metering region set, true}
static std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> kMeteringRegionsToCorrect = {
    {ANDROID_CONTROL_AF_REGIONS,
        {ANDROID_CONTROL_AF_REGIONS_SET, ANDROID_CONTROL_AF_REGIONS_SET_TRUE}},
    {ANDROID_CONTROL_AE_REGIONS,
        {ANDROID_CONTROL_AE_REGIONS_SET, ANDROID_CONTROL_AE_REGIONS_SET_TRUE}},
    {ANDROID_CONTROL_AWB_REGIONS,
        {ANDROID_CONTROL_AWB_REGIONS_SET,  ANDROID_CONTROL_AWB_REGIONS_SET_TRUE}}
};

UHRCropAndMeteringRegionMapper::UHRCropAndMeteringRegionMapper(const CameraMetadata &deviceInfo,
        bool usePreCorrectedArray) {

    if (usePreCorrectedArray) {
        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
                ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, &mArrayWidth,
                &mArrayHeight)) {
            ALOGE("%s: Couldn't get pre correction active array size", __FUNCTION__);
            return;
        }
        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
                ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
                &mArrayWidthMaximumResolution, &mArrayHeightMaximumResolution)) {
            ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
                    __FUNCTION__);
            return;
        }
    } else {
        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
                ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &mArrayWidth,
                &mArrayHeight)) {
            ALOGE("%s: Couldn't get active array size", __FUNCTION__);
            return;
        }
        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
                ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
                &mArrayWidthMaximumResolution, &mArrayHeightMaximumResolution)) {
            ALOGE("%s: Couldn't get maximum resolution active array size", __FUNCTION__);
            return;
        }

    }

    mIsValid = true;

    ALOGV("%s: array size: %d x %d, full res array size: %d x %d,",
            __FUNCTION__, mArrayWidth, mArrayHeight, mArrayWidthMaximumResolution,
            mArrayHeightMaximumResolution);
}

void UHRCropAndMeteringRegionMapper::fixMeteringRegionsIfNeeded(CameraMetadata *request) {
    if (request == nullptr) {
      ALOGE("%s request is nullptr, can't fix crop region", __FUNCTION__);
      return;
    }
    for (const auto &entry : kMeteringRegionsToCorrect) {
        // Check if the metering region Set key is set to TRUE, we don't
        // need to correct the metering regions.
        camera_metadata_entry meteringRegionsSetEntry =
                request->find(entry.second.first);
        if (meteringRegionsSetEntry.count == 1 &&
                meteringRegionsSetEntry.data.u8[0] == entry.second.second) {
            // metering region set by client, doesn't need to be fixed.
            continue;
        }
        camera_metadata_entry meteringRegionEntry = request->find(entry.first);
        if (meteringRegionEntry.count % 5 != 0) {
            ALOGE("%s: Metering region entry for tag %d does not have a valid number of entries, "
                    "skipping", __FUNCTION__, (int)entry.first);
            continue;
        }
        for (size_t j = 0; j < meteringRegionEntry.count; j += 5) {
            int32_t *meteringRegionStart = meteringRegionEntry.data.i32 + j;
            meteringRegionStart[0] = 0;
            meteringRegionStart[1] = 0;
            meteringRegionStart[2] = mArrayWidthMaximumResolution;
            meteringRegionStart[3] = mArrayHeightMaximumResolution;
        }
    }
}

void UHRCropAndMeteringRegionMapper::fixCropRegionsIfNeeded(CameraMetadata *request) {
    if (request == nullptr) {
      ALOGE("%s request is nullptr, can't fix crop region", __FUNCTION__);
      return;
    }
    // Check if the scalerCropRegionSet key is set to TRUE, we don't
    // need to correct the crop region.
    camera_metadata_entry cropRegionSetEntry =
            request->find(ANDROID_SCALER_CROP_REGION_SET);
    if (cropRegionSetEntry.count == 1 &&
        cropRegionSetEntry.data.u8[0] == ANDROID_SCALER_CROP_REGION_SET_TRUE) {
        // crop regions set by client, doesn't need to be fixed.
        return;
    }
    camera_metadata_entry_t cropRegionEntry = request->find(ANDROID_SCALER_CROP_REGION);
    if (cropRegionEntry.count == 4) {
        cropRegionEntry.data.i32[0] = 0;
        cropRegionEntry.data.i32[1] = 0;
        cropRegionEntry.data.i32[2] = mArrayWidthMaximumResolution;
        cropRegionEntry.data.i32[3] = mArrayHeightMaximumResolution;
    }
}

status_t UHRCropAndMeteringRegionMapper::updateCaptureRequest(CameraMetadata* request) {
    if (request == nullptr) {
        ALOGE("%s Invalid request, request is nullptr", __FUNCTION__);
        return BAD_VALUE;
    }
    if (!mIsValid) {
        ALOGE("%s UHRCropAndMeteringRegionMapper didn't initialize correctly", __FUNCTION__);
        return INVALID_OPERATION;
    }

    camera_metadata_entry sensorPixelModeEntry = request->find(ANDROID_SENSOR_PIXEL_MODE);

    // Check if this is max resolution capture, if not, we don't need to do
    // anything.
    if (sensorPixelModeEntry.count != 0) {
        int32_t sensorPixelMode = sensorPixelModeEntry.data.u8[0];
        if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
            // Correction not needed for default mode requests.
           return OK;
        }
    } else {
        // sensor pixel mode not set -> default sensor pixel mode request, which
        // doesn't need correction.
        return OK;
    }

    fixCropRegionsIfNeeded(request);
    fixMeteringRegionsIfNeeded(request);
    return OK;
}

} // namespace camera3

} // namespace android
+59 −0
Original line number Original line Diff line number Diff line
/*
 * 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 ANDROID_SERVERS_UHRCROP_REGIONS_MAPPER_H
#define ANDROID_SERVERS_UHRCROP_REGIONS_MAPPER_H

#include <utils/Errors.h>
#include <array>

#include "camera/CameraMetadata.h"

namespace android {

namespace camera3 {

/**
 * Utilities to transform SCALER_CROP_REGION and metering regions for ultra high
 * resolution sensors.
 */
class UHRCropAndMeteringRegionMapper {
 public:
    UHRCropAndMeteringRegionMapper() = default;
    UHRCropAndMeteringRegionMapper(const CameraMetadata &deviceInfo, bool usePreCorrectionArray);

    /**
     * Adjust capture request assuming rotate and crop AUTO is enabled
     */
    status_t updateCaptureRequest(CameraMetadata *request);

 private:

    void fixCropRegionsIfNeeded(CameraMetadata *request);
    void fixMeteringRegionsIfNeeded(CameraMetadata *request);

    int32_t mArrayWidth = 0;
    int32_t mArrayHeight = 0;
    int32_t mArrayWidthMaximumResolution = 0;
    int32_t mArrayHeightMaximumResolution = 0;
    bool mIsValid = false;
}; // class UHRCropAndMeteringRegionMapper

} // namespace camera3

} // namespace android

#endif
Loading