[libcamera-devel] [RFC PATCH 1/2] android: Plumb Sharpness control into EDGE_MODE

Paul Elder paul.elder at ideasonboard.com
Mon Aug 23 11:48:05 CEST 2021


Plumb the Sharpness control into the HAL for EDGE_MODE and other related
android controls.

Bug: https://bugs.libcamera.org/show_bug.cgi?id=46
Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
---
 src/android/camera_capabilities.cpp | 33 ++++++++++++++++++++++
 src/android/camera_device.cpp       | 44 +++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
index bd661675..d12dc048 100644
--- a/src/android/camera_capabilities.cpp
+++ b/src/android/camera_capabilities.cpp
@@ -231,6 +231,11 @@ bool CameraCapabilities::validateManualSensorCapability()
 		return false;
 	}
 
+	if (!staticMetadata_->hasEntry(ANDROID_EDGE_AVAILABLE_EDGE_MODES)) {
+		LOG(HAL, Info) << noMode << "missing edge modes";
+		return false;
+	}
+
 	/*
 	 * \todo Return true here after we satisfy all the requirements:
 	 * https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
@@ -938,6 +943,22 @@ int CameraCapabilities::initializeStaticMetadata()
 	staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,
 				  availableControlModes);
 
+
+	const auto &edgeInfo = controlsInfo.find(&controls::Sharpness);
+	if (edgeInfo != controlsInfo.end()) {
+		std::vector<uint8_t> availableEdgeModes = {
+			ANDROID_EDGE_MODE_OFF,
+			ANDROID_EDGE_MODE_FAST,
+			ANDROID_EDGE_MODE_HIGH_QUALITY,
+		};
+
+		staticMetadata_->addEntry(ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+					  availableEdgeModes);
+		availableCharacteristicsKeys_.insert(ANDROID_EDGE_AVAILABLE_EDGE_MODES);
+		availableRequestKeys_.insert(ANDROID_EDGE_MODE);
+		availableResultKeys_.insert(ANDROID_EDGE_MODE);
+	}
+
 	/* JPEG static metadata. */
 
 	/*
@@ -1330,6 +1351,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateManual() cons
 	if (!manualTemplate)
 		return nullptr;
 
+	if (availableRequestKeys_.count(ANDROID_EDGE_MODE))
+		manualTemplate->addEntry(ANDROID_EDGE_MODE, ANDROID_EDGE_MODE_OFF);
+
 	return manualTemplate;
 }
 
@@ -1390,6 +1414,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
 	uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
 	requestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);
 
+	if (availableRequestKeys_.count(ANDROID_EDGE_MODE))
+		requestTemplate->addEntry(ANDROID_EDGE_MODE, ANDROID_EDGE_MODE_FAST);
+
 	uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
 	requestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);
 
@@ -1428,6 +1455,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateStill() const
 	if (!stillTemplate)
 		return nullptr;
 
+	if (availableRequestKeys_.count(ANDROID_EDGE_MODE))
+		stillTemplate->addEntry(ANDROID_EDGE_MODE, ANDROID_EDGE_MODE_HIGH_QUALITY);
+
 	return stillTemplate;
 }
 
@@ -1445,6 +1475,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateVideo() const
 	staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
 				  &entry);
 
+	if (availableRequestKeys_.count(ANDROID_EDGE_MODE))
+		previewTemplate->addEntry(ANDROID_EDGE_MODE, ANDROID_EDGE_MODE_FAST);
+
 	/*
 	 * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata
 	 * has been assembled as {{min, max} {max, max}}.
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index a69b687a..96afec81 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -829,6 +829,24 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
 		controls.set(controls::draft::TestPatternMode, testPatternMode);
 	}
 
+	if (settings.getEntry(ANDROID_EDGE_MODE, &entry)) {
+		const auto &info = camera_->controls().find(&controls::Sharpness);
+		if (info != camera_->controls().end()) {
+			float min = info->second.min().get<float>();
+			float def = info->second.def().get<float>();
+			float max = info->second.max().get<float>();
+			/*
+			 * The default value might be unusable since control
+			 * serialization ignores it. Alternatively the default
+			 * could be simply set to zero or the minimum value.
+			 * Use the maximum sharpness value in these cases.
+			 */
+			float val = (def == 0.0f || def == min) ? max : def;
+			controls.set(controls::Sharpness,
+				     *entry.data.u8 == ANDROID_EDGE_MODE_OFF ? min : val);
+		}
+	}
+
 	return 0;
 }
 
@@ -1371,6 +1389,32 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
 					 duration);
 	}
 
+	if (metadata.contains(controls::Sharpness) &&
+	    settings.getEntry(ANDROID_EDGE_MODE, &entry)) {
+		const auto &info = camera_->controls().find(&controls::Sharpness);
+		if (info != camera_->controls().end()) {
+			float min = info->second.min().get<float>();
+			float max = info->second.max().get<float>();
+			float sharpness = metadata.get(controls::Sharpness);
+			/*
+			 * 1% of the sharpening value range is considered "no
+			 * sharpening".
+			 */
+			bool closeToMin = (sharpness - min) < (min + (0.01 * (max - min))) ||
+					  min == max;
+
+			/*
+			 * libcamera doesn't distinguish between fast vs HQ
+			 * sharpening modes. Report the mode that was
+			 * requested.
+			 */
+			resultMetadata->addEntry(ANDROID_EDGE_MODE,
+						 closeToMin ?
+						 (uint8_t)ANDROID_EDGE_MODE_OFF :
+						 *entry.data.u8);
+		}
+	}
+
 	if (metadata.contains(controls::ScalerCrop)) {
 		Rectangle crop = metadata.get(controls::ScalerCrop);
 		int32_t cropRect[] = {
-- 
2.27.0



More information about the libcamera-devel mailing list