Camera: Improve monochrome camera capability support
- Add dummy CFA pattern for monochrome camera.
- Handle monochrome camera in DngCreator.
- Fix up static and dynamic metadata tags related to monochrome camera
for older version of devices.
Test: Camera CTS
Test: Capture a DNG file and inspect with LightRoom
Bug: 70216652
Change-Id: I68d2b3d77b7f81bdc9e4129c2a8af10a4f18db3b
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index a94e886..2542ab2 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -425,6 +425,102 @@
}
}
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
+ status_t res = OK;
+ auto& c = mCameraCharacteristics;
+
+ // Override static metadata for MONOCHROME camera with older device version
+ if (mVersion.get_major() == 3 && mVersion.get_minor() < 5) {
+ camera_metadata_entry cap = c.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ for (size_t i = 0; i < cap.count; i++) {
+ if (cap.data.u8[i] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+ // ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+ uint8_t cfa = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO;
+ res = c.update(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, &cfa, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update COLOR_FILTER_ARRANGEMENT: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS
+ const std::vector<uint32_t> sKeys = {
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1,
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT2,
+ ANDROID_SENSOR_CALIBRATION_TRANSFORM1,
+ ANDROID_SENSOR_CALIBRATION_TRANSFORM2,
+ ANDROID_SENSOR_COLOR_TRANSFORM1,
+ ANDROID_SENSOR_COLOR_TRANSFORM2,
+ ANDROID_SENSOR_FORWARD_MATRIX1,
+ ANDROID_SENSOR_FORWARD_MATRIX2,
+ };
+ res = removeAvailableKeys(c, sKeys,
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ if (res != OK) {
+ ALOGE("%s: Failed to update REQUEST_AVAILABLE_CHARACTERISTICS_KEYS: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS
+ const std::vector<uint32_t> reqKeys = {
+ ANDROID_COLOR_CORRECTION_MODE,
+ ANDROID_COLOR_CORRECTION_TRANSFORM,
+ ANDROID_COLOR_CORRECTION_GAINS,
+ };
+ res = removeAvailableKeys(c, reqKeys, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+ if (res != OK) {
+ ALOGE("%s: Failed to update REQUEST_AVAILABLE_REQUEST_KEYS: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // ANDROID_REQUEST_AVAILABLE_RESULT_KEYS
+ const std::vector<uint32_t> resKeys = {
+ ANDROID_SENSOR_GREEN_SPLIT,
+ ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
+ ANDROID_COLOR_CORRECTION_MODE,
+ ANDROID_COLOR_CORRECTION_TRANSFORM,
+ ANDROID_COLOR_CORRECTION_GAINS,
+ };
+ res = removeAvailableKeys(c, resKeys, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS);
+ if (res != OK) {
+ ALOGE("%s: Failed to update REQUEST_AVAILABLE_RESULT_KEYS: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // ANDROID_SENSOR_BLACK_LEVEL_PATTERN
+ camera_metadata_entry blEntry = c.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+ for (size_t j = 1; j < blEntry.count; j++) {
+ blEntry.data.i32[j] = blEntry.data.i32[0];
+ }
+ }
+ }
+ }
+ return res;
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::removeAvailableKeys(
+ CameraMetadata& c, const std::vector<uint32_t>& keys, uint32_t keyTag) {
+ status_t res = OK;
+
+ camera_metadata_entry keysEntry = c.find(keyTag);
+ if (keysEntry.count == 0) {
+ ALOGE("%s: Failed to find tag %u: %s (%d)", __FUNCTION__, keyTag, strerror(-res), res);
+ return res;
+ }
+ std::vector<int32_t> vKeys;
+ vKeys.reserve(keysEntry.count);
+ for (size_t i = 0; i < keysEntry.count; i++) {
+ if (std::find(keys.begin(), keys.end(), keysEntry.data.i32[i]) == keys.end()) {
+ vKeys.push_back(keysEntry.data.i32[i]);
+ }
+ }
+ res = c.update(keyTag, vKeys.data(), vKeys.size());
+ return res;
+}
+
bool CameraProviderManager::isLogicalCamera(const std::string& id,
std::vector<std::string>* physicalCameraIds) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -1131,6 +1227,12 @@
__FUNCTION__, mId.c_str(), CameraProviderManager::statusToString(status), status);
return;
}
+ status_t res = fixupMonochromeTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
+ }
camera_metadata_entry flashAvailable =
mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
if (flashAvailable.count == 1 &&
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 9016747..c506d35 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -385,6 +385,9 @@
CameraMetadata mCameraCharacteristics;
std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
void queryPhysicalCameraIds();
+ status_t fixupMonochromeTags();
+ status_t removeAvailableKeys(CameraMetadata& c, const std::vector<uint32_t>& keys,
+ uint32_t keyTag);
};
private:
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 90d9888..f982f67 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -79,7 +79,8 @@
mNextReprocessShutterFrameNumber(0),
mListener(NULL),
mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID),
- mLastTemplateId(-1)
+ mLastTemplateId(-1),
+ mNeedFixupMonochromeTags(false)
{
ATRACE_CALL();
ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
@@ -188,6 +189,28 @@
mTagMonitor.parseTagsToMonitor(String8(monitorTags));
}
+ // Metadata tags needs fixup for monochrome camera device version less
+ // than 3.5.
+ hardware::hidl_version maxVersion{0,0};
+ res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
+ if (res != OK) {
+ ALOGE("%s: Error in getting camera device version id: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ int deviceVersion = HARDWARE_DEVICE_API_VERSION(
+ maxVersion.get_major(), maxVersion.get_minor());
+
+ bool isMonochrome = false;
+ camera_metadata_entry_t entry = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ for (size_t i = 0; i < entry.count; i++) {
+ uint8_t capability = entry.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+ isMonochrome = true;
+ }
+ }
+ mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
+
return initializeCommonLocked();
}
@@ -3276,6 +3299,13 @@
captureResult.mResultExtras = resultExtras;
captureResult.mMetadata = partialResult;
+ // Fix up result metadata for monochrome camera.
+ status_t res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
+ if (res != OK) {
+ SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+ return;
+ }
+
insertResultLocked(&captureResult, frameNumber);
}
@@ -3347,6 +3377,21 @@
frameNumber, strerror(res), res);
return;
}
+ // Fix up result metadata for monochrome camera.
+ res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
+ if (res != OK) {
+ SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+ return;
+ }
+ for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+ String8 cameraId8(physicalMetadata.mPhysicalCameraId);
+ res = fixupMonochromeTags(mPhysicalDeviceInfoMap.at(cameraId8.c_str()),
+ physicalMetadata.mPhysicalCameraMetadata);
+ if (res != OK) {
+ SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+ return;
+ }
+ }
mTagMonitor.monitorMetadata(TagMonitor::RESULT,
frameNumber, timestamp.data.i64[0], captureResult.mMetadata);
@@ -3519,7 +3564,7 @@
if (shutterTimestamp == 0) {
request.pendingMetadata = result->result;
request.collectedPartialResult = collectedPartialResult;
- } else if (request.hasCallback) {
+ } else if (request.hasCallback) {
CameraMetadata metadata;
metadata = result->result;
sendCaptureResult(metadata, request.resultExtras,
@@ -6298,4 +6343,75 @@
return false;
}
+status_t Camera3Device::fixupMonochromeTags(const CameraMetadata& deviceInfo,
+ CameraMetadata& resultMetadata) {
+ status_t res = OK;
+ if (!mNeedFixupMonochromeTags) {
+ return res;
+ }
+
+ // Remove tags that are not applicable to monochrome camera.
+ int32_t tagsToRemove[] = {
+ ANDROID_SENSOR_GREEN_SPLIT,
+ ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
+ ANDROID_COLOR_CORRECTION_MODE,
+ ANDROID_COLOR_CORRECTION_TRANSFORM,
+ ANDROID_COLOR_CORRECTION_GAINS,
+ };
+ for (auto tag : tagsToRemove) {
+ res = resultMetadata.erase(tag);
+ if (res != OK) {
+ ALOGE("%s: Failed to remove tag %d for monochrome camera", __FUNCTION__, tag);
+ return res;
+ }
+ }
+
+ // ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL
+ camera_metadata_entry blEntry = resultMetadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+ for (size_t i = 1; i < blEntry.count; i++) {
+ blEntry.data.f[i] = blEntry.data.f[0];
+ }
+
+ // ANDROID_SENSOR_NOISE_PROFILE
+ camera_metadata_entry npEntry = resultMetadata.find(ANDROID_SENSOR_NOISE_PROFILE);
+ if (npEntry.count > 0 && npEntry.count % 2 == 0) {
+ double np[] = {npEntry.data.d[0], npEntry.data.d[1]};
+ res = resultMetadata.update(ANDROID_SENSOR_NOISE_PROFILE, np, 2);
+ if (res != OK) {
+ ALOGE("%s: Failed to update SENSOR_NOISE_PROFILE: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ }
+
+ // ANDROID_STATISTICS_LENS_SHADING_MAP
+ camera_metadata_ro_entry lsSizeEntry = deviceInfo.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+ camera_metadata_entry lsEntry = resultMetadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+ if (lsSizeEntry.count == 2 && lsEntry.count > 0
+ && (int32_t)lsEntry.count == 4 * lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]) {
+ for (int32_t i = 0; i < lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]; i++) {
+ lsEntry.data.f[4*i+1] = lsEntry.data.f[4*i];
+ lsEntry.data.f[4*i+2] = lsEntry.data.f[4*i];
+ lsEntry.data.f[4*i+3] = lsEntry.data.f[4*i];
+ }
+ }
+
+ // ANDROID_TONEMAP_CURVE_BLUE
+ // ANDROID_TONEMAP_CURVE_GREEN
+ // ANDROID_TONEMAP_CURVE_RED
+ camera_metadata_entry tcbEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_BLUE);
+ camera_metadata_entry tcgEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_GREEN);
+ camera_metadata_entry tcrEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_RED);
+ if (tcbEntry.count > 0
+ && tcbEntry.count == tcgEntry.count
+ && tcbEntry.count == tcrEntry.count) {
+ for (size_t i = 0; i < tcbEntry.count; i++) {
+ tcbEntry.data.f[i] = tcrEntry.data.f[i];
+ tcgEntry.data.f[i] = tcrEntry.data.f[i];
+ }
+ }
+
+ return res;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 4f5be6b..3f291ba 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1324,6 +1324,9 @@
int mRequestBufferStatusId;
} mRequestBufferSM;
+ // Fix up result metadata for monochrome camera.
+ bool mNeedFixupMonochromeTags;
+ status_t fixupMonochromeTags(const CameraMetadata& deviceInfo, CameraMetadata& resultMetadata);
}; // class Camera3Device
}; // namespace android