[libcamera-devel] [PATCH v2] android: Plumb Sharpness control into EDGE_MODE

Paul Elder paul.elder at ideasonboard.com
Tue Dec 21 05:41:33 CET 2021


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

libcamera doesn't distinguish between fast and HQ, but rather with a
floating value for how much sharpening to apply. This is thus
unsufficient information for retaining whether the request was for fast
or HQ, so save it in the request, and report what was requested.

Bug: https://bugs.libcamera.org/show_bug.cgi?id=46
Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>

---
This patch depends on "android: camera_metadata: Add appendEntry helper"

Changes in v2:
- fix the assertions in template creation
- report the edge mode that was requested, instead of doing conversion
  to and from the floating value and its ControlInfo
- move edge mode capability check out of manual control (as docs say
  it's not required) and into the top-level FULL hardware level
  validator
---
 src/android/camera_capabilities.cpp | 44 +++++++++++++++++++++++++++++
 src/android/camera_device.cpp       | 28 ++++++++++++++++++
 src/android/camera_request.h        |  4 +++
 3 files changed, 76 insertions(+)

diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
index b9a1f6e5..727204b9 100644
--- a/src/android/camera_capabilities.cpp
+++ b/src/android/camera_capabilities.cpp
@@ -401,6 +401,11 @@ void CameraCapabilities::computeHwLevel(
 	if (!caps.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE))
 		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
 
+	if (!staticMetadata_->hasEntry(ANDROID_EDGE_AVAILABLE_EDGE_MODES)) {
+		LOG(HAL, Info) << noFull << "missing edge modes";
+		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
+	}
+
 	found = staticMetadata_->getEntry(ANDROID_SYNC_MAX_LATENCY, &entry);
 	if (!found || *entry.data.i32 != 0) {
 		LOG(HAL, Info) << noFull << "missing or invalid max sync latency";
@@ -1078,6 +1083,21 @@ 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. */
 
 	/*
@@ -1593,6 +1613,12 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateManual() cons
 		manualTemplate->appendEntry(ANDROID_CONTROL_AE_MODE, aeMode);
 	}
 
+	if (staticMetadata_->entryContains<uint8_t>(ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+						    ANDROID_EDGE_MODE_OFF)) {
+		uint8_t edgeMode = ANDROID_EDGE_MODE_OFF;
+		manualTemplate->appendEntry(ANDROID_EDGE_MODE, edgeMode);
+	}
+
 	return manualTemplate;
 }
 
@@ -1675,6 +1701,12 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
 	if (availableRequestKeys_.count(ANDROID_SENSOR_SENSITIVITY))
 		requestTemplate->addEntry(ANDROID_SENSOR_SENSITIVITY, minISO_);
 
+	if (staticMetadata_->entryContains<uint8_t>(ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+						    ANDROID_EDGE_MODE_FAST)) {
+		uint8_t edgeMode = ANDROID_EDGE_MODE_FAST;
+		requestTemplate->addEntry(ANDROID_EDGE_MODE, edgeMode);
+	}
+
 	uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
 	requestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);
 
@@ -1713,6 +1745,12 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateStill() const
 	if (!stillTemplate)
 		return nullptr;
 
+	if (staticMetadata_->entryContains<uint8_t>(ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+						    ANDROID_EDGE_MODE_HIGH_QUALITY)) {
+		uint8_t edgeMode = ANDROID_EDGE_MODE_HIGH_QUALITY;
+		stillTemplate->appendEntry(ANDROID_EDGE_MODE, edgeMode);
+	}
+
 	return stillTemplate;
 }
 
@@ -1730,6 +1768,12 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateVideo() const
 	staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
 				  &entry);
 
+	if (staticMetadata_->entryContains<uint8_t>(ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+						    ANDROID_EDGE_MODE_FAST)) {
+		uint8_t edgeMode = ANDROID_EDGE_MODE_FAST;
+		previewTemplate->appendEntry(ANDROID_EDGE_MODE, edgeMode);
+	}
+
 	/*
 	 * 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 1a508923..0d668ea6 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -920,6 +920,26 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
 			controls.set(controls::DigitalGain, lastDigitalGain_);
 	}
 
+	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);
+
+			descriptor->edgeMode_ = *entry.data.u8;
+		}
+	}
+
 	return 0;
 }
 
@@ -1602,6 +1622,14 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
 					 duration);
 	}
 
+	if (metadata.contains(controls::Sharpness)) {
+		/*
+		 * libcamera doesn't distinguish between fast vs HQ sharpening
+		 * modes. Report the mode that was requested.
+		 */
+		resultMetadata->addEntry(ANDROID_EDGE_MODE, descriptor.edgeMode_);
+	}
+
 	if (metadata.contains(controls::ScalerCrop)) {
 		Rectangle crop = metadata.get(controls::ScalerCrop);
 		int32_t cropRect[] = {
diff --git a/src/android/camera_request.h b/src/android/camera_request.h
index b2809179..69b6c8fc 100644
--- a/src/android/camera_request.h
+++ b/src/android/camera_request.h
@@ -87,6 +87,10 @@ public:
 	/* The libcamera internal AE state for this request */
 	AutoMode aeMode_ = AutoMode::Auto;
 
+	/* The android edge mode associated with this request */
+	/* \todo Wrap all such controls? */
+	int32_t edgeMode_;
+
 private:
 	LIBCAMERA_DISABLE_COPY(Camera3RequestDescriptor)
 };
-- 
2.27.0



More information about the libcamera-devel mailing list