[libcamera-devel,2/2] android: Plumb lens shading
diff mbox series

Message ID 20211221052507.2678322-3-paul.elder@ideasonboard.com
State New
Delegated to: Paul Elder
Headers show
Series
  • android: Lens shading
Related show

Commit Message

Paul Elder Dec. 21, 2021, 5:25 a.m. UTC
Plumb the controls related to lens shading:
- request the lens shading map to be reported (and report the current
  mode)
- report the lens shading map (size + map)
- request and report enabling/disabling of lens shading
- corresponding static metadata to report available modes

Also add a check for the RAW capability, as being able to report the
lens shading map is a requirement for it.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
---
 src/android/camera_capabilities.cpp | 102 +++++++++++++++++++++++++++-
 src/android/camera_device.cpp       | 100 +++++++++++++++++++++++++--
 2 files changed, 196 insertions(+), 6 deletions(-)

Patch
diff mbox series

diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
index 742c6a6a..cb5ea5e9 100644
--- a/src/android/camera_capabilities.cpp
+++ b/src/android/camera_capabilities.cpp
@@ -295,6 +295,18 @@  bool CameraCapabilities::validateManualPostProcessingCapability()
 		return false;
 	}
 
+	/* From docs */
+	if (!staticMetadata_->entryContains<uint8_t>(ANDROID_SHADING_AVAILABLE_MODES,
+						     ANDROID_SHADING_MODE_OFF) ||
+	    !staticMetadata_->entryContains<uint8_t>(ANDROID_SHADING_AVAILABLE_MODES,
+						     ANDROID_SHADING_MODE_FAST) ||
+	    /* From CTS */
+	    !staticMetadata_->entryContains<uint8_t>(ANDROID_SHADING_AVAILABLE_MODES,
+						     ANDROID_SHADING_MODE_HIGH_QUALITY)) {
+		LOG(HAL, Info) << noMode << "missing shading modes off or fast or HQ";
+		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_POST_PROCESSING
@@ -375,8 +387,12 @@  CameraCapabilities::computeCapabilities()
 	if (validateBurstCaptureCapability())
 		capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
 
-	if (rawStreamAvailable_)
+	if (rawStreamAvailable_ &&
+	    staticMetadata_->entryContains<uint8_t>(
+		    ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+		    ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON)) {
 		capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
+	}
 
 	return capabilities;
 }
@@ -437,6 +453,21 @@  void CameraCapabilities::computeHwLevel(
 		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
 	}
 
+	/*
+	 * Shading mode and lens shading map mode are always available and
+	 * don't need to be checked. We only need to check we support reporting
+	 * the lens shading map.
+	 *
+	 * The lens shading map may have a null map with a zero size. It is
+	 * valid, but will give android a null correction map.
+	 * \todo Confirm that this is fine
+	 */
+	found = availableResultKeys_.count(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+	if (!found) {
+		LOG(HAL, Info) << noFull << "missing reportable lens shading map";
+		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
+	}
+
 	hwLevel_ = hwLevel;
 }
 
@@ -871,7 +902,9 @@  int CameraCapabilities::initializeStaticMetadata()
 		ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
 		ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
 		ANDROID_SENSOR_ORIENTATION,
+		ANDROID_SHADING_AVAILABLE_MODES,
 		ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
+		ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
 		ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
 		ANDROID_SYNC_MAX_LATENCY,
 	};
@@ -903,7 +936,9 @@  int CameraCapabilities::initializeStaticMetadata()
 		ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
 		ANDROID_NOISE_REDUCTION_MODE,
 		ANDROID_SCALER_CROP_REGION,
-		ANDROID_STATISTICS_FACE_DETECT_MODE
+		ANDROID_SHADING_MODE,
+		ANDROID_STATISTICS_FACE_DETECT_MODE,
+		ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
 	};
 
 	availableResultKeys_ = {
@@ -949,6 +984,7 @@  int CameraCapabilities::initializeStaticMetadata()
 		ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
 		ANDROID_SENSOR_TEST_PATTERN_MODE,
 		ANDROID_SENSOR_TIMESTAMP,
+		ANDROID_SHADING_MODE,
 		ANDROID_STATISTICS_FACE_DETECT_MODE,
 		ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
 		ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
@@ -1361,7 +1397,25 @@  int CameraCapabilities::initializeStaticMetadata()
 	staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
 				  maxFaceCount);
 
+	/* Lens shading */
 	{
+		/*
+		 * Controls for requesting and reporting the lens shading map:
+		 * static:
+		 * - ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES
+		 *   - availability of requesting the lens shading map, always
+		 *     available
+		 * request:
+		 * - ANDROID_STATISTICS_LENS_SHADING_MAP_MODE
+		 *   - request reporting of the lens shading map, always available
+		 * result:
+		 * - ANDROID_STATISTICS_LENS_SHADING_MAP_MODE
+		 *   - result version of the above control
+		 * - ANDROID_LENS_INFO_SHADING_MAP_SIZE
+		 *   - size of the lens shading map
+		 * - ANDROID_STATISTICS_LENS_SHADING_MAP
+		 *   - the actual lens shading map
+		 */
 		std::vector<uint8_t> data;
 		data.reserve(2);
 		const auto &infoMap = controlsInfo.find(&controls::StatsLensShadingMapMode);
@@ -1373,6 +1427,34 @@  int CameraCapabilities::initializeStaticMetadata()
 		}
 		staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
 					  data);
+
+		const auto &mapSizeInfoMap = controlsInfo.find(&controls::StatsLensShadingMapSize);
+		if (mapSizeInfoMap != controlsInfo.end())
+			availableResultKeys_.insert(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+
+		const auto &mapInfoMap = controlsInfo.find(&controls::StatsLensShadingMap);
+		if (mapInfoMap != controlsInfo.end())
+			availableResultKeys_.insert(ANDROID_STATISTICS_LENS_SHADING_MAP);
+
+		/*
+		 * Controls for enabling/disabling lens shading:
+		 * static:
+		 * - ANDROID_SHADING_AVAILABLE_MODES
+		 *   - list of available lens shading modes, always available
+		 * request and result:
+		 * - ANDROID_SHADING_MODE
+		 *   - set/report the shading mode (off, fast, hq)
+		 */
+		data.clear();
+		data.reserve(3);
+		const auto &shadingInfoMap = controlsInfo.find(&controls::LensShadingMode);
+		if (shadingInfoMap != controlsInfo.end()) {
+			for (const auto &value : shadingInfoMap->second.values())
+				data.push_back(value.get<int32_t>());
+		} else {
+			data.push_back(ANDROID_SHADING_MODE_OFF);
+		}
+		staticMetadata_->addEntry(ANDROID_SHADING_AVAILABLE_MODES, data);
 	}
 
 	/* Sync static metadata. */
@@ -1802,6 +1884,16 @@  std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
 	requestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,
 				  captureIntent);
 
+	uint8_t shadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+	requestTemplate->addEntry(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+				  shadingMapMode);
+
+	if (staticMetadata_->entryContains<uint8_t>(ANDROID_SHADING_AVAILABLE_MODES,
+						    ANDROID_SHADING_MODE_FAST)) {
+		uint8_t shadingMode = ANDROID_SHADING_MODE_FAST;
+		requestTemplate->addEntry(ANDROID_SHADING_MODE, shadingMode);
+	}
+
 	return requestTemplate;
 }
 
@@ -1817,6 +1909,12 @@  std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateStill() const
 		stillTemplate->appendEntry(ANDROID_EDGE_MODE, edgeMode);
 	}
 
+	if (staticMetadata_->entryContains<uint8_t>(ANDROID_SHADING_AVAILABLE_MODES,
+						    ANDROID_SHADING_MODE_HIGH_QUALITY)) {
+		uint8_t shadingMode = ANDROID_SHADING_MODE_HIGH_QUALITY;
+		stillTemplate->appendEntry(ANDROID_SHADING_MODE, shadingMode);
+	}
+
 	if (staticMetadata_->entryContains<uint8_t>(
 			ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
 			ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY)) {
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index 883a5dc1..7be0ce45 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -973,6 +973,47 @@  int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
 		}
 	}
 
+	if (settings.getEntry(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &entry)) {
+		const int32_t data = static_cast<int32_t>(*entry.data.u8);
+		int32_t statsLensShadingMode;
+		switch (data) {
+		case ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON:
+			statsLensShadingMode = controls::StatsLensShadingMapModeOn;
+			break;
+		case ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF:
+			statsLensShadingMode = controls::StatsLensShadingMapModeOff;
+			break;
+		default:
+			LOG(HAL, Error)
+				<< "Unknown lens shading map mode: " << data;
+			return -EINVAL;
+		}
+
+		controls.set(controls::StatsLensShadingMapMode, statsLensShadingMode);
+	}
+
+	if (settings.getEntry(ANDROID_SHADING_MODE, &entry)) {
+		const int32_t data = static_cast<int32_t>(*entry.data.u8);
+		int32_t shadingMode;
+		switch (data) {
+		case ANDROID_SHADING_MODE_OFF:
+			shadingMode = controls::LensShadingModeOff;
+			break;
+		case ANDROID_SHADING_MODE_FAST:
+			shadingMode = controls::LensShadingModeFast;
+			break;
+		case ANDROID_SHADING_MODE_HIGH_QUALITY:
+			shadingMode = controls::LensShadingModeHighQuality;
+			break;
+		default:
+			LOG(HAL, Error)
+				<< "Unknown shading mode: " << data;
+			return -EINVAL;
+		}
+
+		controls.set(controls::LensShadingMode, shadingMode);
+	}
+
 	return 0;
 }
 
@@ -1613,10 +1654,6 @@  CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
 	value = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
 	resultMetadata->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE, value);
 
-	value = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
-	resultMetadata->addEntry(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
-				 value);
-
 	value = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
 	resultMetadata->addEntry(ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, value);
 
@@ -1720,6 +1757,61 @@  CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
 	std::vector<float> focusRange = { 0.0f, 0.0f };
 	resultMetadata->addEntry(ANDROID_LENS_FOCUS_RANGE, focusRange);
 
+	value = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+	if (metadata.contains(controls::StatsLensShadingMapMode)) {
+		switch (metadata.get(controls::StatsLensShadingMapMode)) {
+		case controls::StatsLensShadingMapModeOn:
+			value = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON;
+			break;
+		case controls::StatsLensShadingMapModeOff:
+			value = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+			break;
+		default:
+			LOG(HAL, Error) << "Invalid StatsLensShadingMapMode";
+		}
+	}
+	resultMetadata->addEntry(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, value);
+
+	if (metadata.contains(controls::LensShadingMode)) {
+		bool valid;
+		switch (metadata.get(controls::LensShadingMode)) {
+		case controls::LensShadingModeOff:
+			value = ANDROID_SHADING_MODE_OFF;
+			valid = true;
+			break;
+		case controls::LensShadingModeFast:
+			value = ANDROID_SHADING_MODE_FAST;
+			valid = true;
+			break;
+		case controls::LensShadingModeHighQuality:
+			value = ANDROID_SHADING_MODE_HIGH_QUALITY;
+			valid = true;
+			break;
+		default:
+			LOG(HAL, Error) << "Invalid LensShadingMode";
+			valid = false;
+		}
+
+		/* Can be null on non-FULL */
+		if (valid)
+			resultMetadata->addEntry(ANDROID_SHADING_MODE, value);
+	}
+
+	if (metadata.contains(controls::StatsLensShadingMapSize)) {
+		Size size = metadata.get(controls::StatsLensShadingMapSize);
+		std::array<uint32_t, 2> mapSize = { size.width, size.height };
+		resultMetadata->addEntry(ANDROID_LENS_INFO_SHADING_MAP_SIZE, mapSize);
+
+		/* valid size and null map is fine, but not vice versa */
+		if (metadata.contains(controls::StatsLensShadingMap)) {
+			const Span<const float> map =
+				metadata.get(controls::StatsLensShadingMap);
+			std::vector<float> shadingMap(map.begin(), map.end());
+			resultMetadata->addEntry(ANDROID_STATISTICS_LENS_SHADING_MAP,
+						 shadingMap);
+		}
+	}
+
 	/*
 	 * Return the result metadata pack even is not valid: get() will return
 	 * nullptr.