[libcamera-devel,RFC,1/2] android: Plumb Sharpness control into EDGE_MODE
diff mbox series

Message ID 20210823094806.1434280-1-paul.elder@ideasonboard.com
State Superseded
Delegated to: Paul Elder
Headers show
Series
  • [libcamera-devel,RFC,1/2] android: Plumb Sharpness control into EDGE_MODE
Related show

Commit Message

Paul Elder Aug. 23, 2021, 9:48 a.m. UTC
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@ideasonboard.com>
---
 src/android/camera_capabilities.cpp | 33 ++++++++++++++++++++++
 src/android/camera_device.cpp       | 44 +++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

Comments

Laurent Pinchart Aug. 31, 2021, 3:07 a.m. UTC | #1
Hi Paul,

Thank you for the patch.

On Mon, Aug 23, 2021 at 06:48:05PM +0900, Paul Elder wrote:
> 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@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;
> +	}

Where did you see that the manual sensor capability requires edge mode ?
I'm looking at
https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
and I don't see edge mode control there. It's however required for FULL
level, but I'm not entirely sure if FULL level request supporting other
modes than OFF.

> +
>  	/*
>  	 * \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);
>  
> +

Extra blank line.

> +	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

Isn't this something that needs to be fixed in controls serialization ?
We can keep the workaround to avoiding depending on that work, but a
todo comment is needed then.

> +			 * 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[] = {

Patch
diff mbox series

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[] = {