[v3] libcamera: pipeline: uvcvideo: Retrieve v4l2 device control information
diff mbox series

Message ID 01020191f2bd3860-8a479d82-2724-43c0-895c-779c826ef28a-000000@eu-west-1.amazonses.com
State Superseded
Headers show
Series
  • [v3] libcamera: pipeline: uvcvideo: Retrieve v4l2 device control information
Related show

Commit Message

Cláudio Paulo Sept. 14, 2024, 10:52 p.m. UTC
Populate frame metadata by using V4L2Device::getControls() to get
the values for all supported controls on each frame.

Signed-off-by: Cláudio Paulo <claudio.paulo@makewise.pt>
---
Fixed similar issues reported on a distinct patch.

 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 112 ++++++++++++++++++-
 1 file changed, 108 insertions(+), 4 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 6b32fa18..6313e9e0 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -333,8 +333,8 @@  int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
 
 	case V4L2_CID_EXPOSURE_AUTO: {
 		int32_t ivalue = value.get<bool>()
-			       ? V4L2_EXPOSURE_APERTURE_PRIORITY
-			       : V4L2_EXPOSURE_MANUAL;
+					 ? V4L2_EXPOSURE_APERTURE_PRIORITY
+					 : V4L2_EXPOSURE_MANUAL;
 		controls->set(V4L2_CID_EXPOSURE_AUTO, ivalue);
 		break;
 	}
@@ -750,10 +750,114 @@  void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,
 void UVCCameraData::bufferReady(FrameBuffer *buffer)
 {
 	Request *request = buffer->request();
+	ControlList *metadata = &request->metadata();
 
 	/* \todo Use the UVC metadata to calculate a more precise timestamp */
-	request->metadata().set(controls::SensorTimestamp,
-				buffer->metadata().timestamp);
+	metadata->set(controls::SensorTimestamp, buffer->metadata().timestamp);
+
+	/* Retrieve control as reported by the device. */
+	std::vector<uint32_t> ids;
+	for (const auto &[controlId, _] : video_->controls()) {
+		switch (uint32_t cid = controlId->id()) {
+		case V4L2_CID_BRIGHTNESS:
+		case V4L2_CID_CONTRAST:
+		case V4L2_CID_SATURATION:
+		case V4L2_CID_EXPOSURE_AUTO:
+		case V4L2_CID_EXPOSURE_ABSOLUTE:
+		case V4L2_CID_GAIN:
+		case V4L2_CID_FOCUS_ABSOLUTE:
+		case V4L2_CID_FOCUS_AUTO:
+			ids.push_back(cid);
+			break;
+		default:;
+		}
+	}
+
+	/*
+	 * See UVCCameraData::addControl() for explanations of the different
+	 * value mappings.
+	 */
+	ControlList deviceControls = video_->getControls(ids);
+	for (const auto &[cid, value] : deviceControls) {
+		ControlInfo v4l2Info = video_->controls().at(cid);
+
+		int32_t min = -1, def = -1, max = -1;
+		if (v4l2Info.min().type() == ControlTypeInteger32)
+			min = v4l2Info.min().get<int32_t>();
+		if (v4l2Info.min().type() == ControlTypeInteger32)
+			def = v4l2Info.def().get<int32_t>();
+		if (v4l2Info.min().type() == ControlTypeInteger32)
+			max = v4l2Info.max().get<int32_t>();
+
+		switch (cid) {
+		case V4L2_CID_BRIGHTNESS: {
+			float scale = std::max(max - def, def - min);
+
+			int ivalue = (value.get<int32_t>() - def) / scale;
+			metadata->set(controls::Brightness, ivalue);
+			break;
+		}
+
+		case V4L2_CID_GAIN:
+		case V4L2_CID_CONTRAST: {
+			float m = (4.0f - 1.0f) / (max - def);
+			float p = 1.0f - m * def;
+
+			if (m * min + p < 0.5f) {
+				m = (1.0f - 0.5f) / (def - min);
+				p = 1.0f - m * def;
+			}
+
+			float fvalue = m * value.get<int32_t>() + p;
+			if (cid == V4L2_CID_GAIN)
+				metadata->set(controls::AnalogueGain, fvalue);
+			else if (cid == V4L2_CID_CONTRAST)
+				metadata->set(controls::Contrast, fvalue);
+			break;
+		}
+
+		case V4L2_CID_SATURATION: {
+			float scale = def - min;
+
+			metadata->set(controls::Saturation,
+				      (value.get<int32_t>() - min) / scale);
+			break;
+		}
+
+		case V4L2_CID_EXPOSURE_AUTO: {
+			int32_t ivalue = value.get<int32_t>();
+			if (ivalue == V4L2_EXPOSURE_APERTURE_PRIORITY)
+				metadata->set(controls::AeEnable, true);
+			else if (ivalue == V4L2_EXPOSURE_MANUAL)
+				metadata->set(controls::AeEnable, false);
+			break;
+		}
+
+		case V4L2_CID_EXPOSURE_ABSOLUTE:
+			metadata->set(controls::ExposureTime,
+				      value.get<int32_t>() * 100);
+			break;
+
+		case V4L2_CID_FOCUS_ABSOLUTE: {
+			float focusedAt50Cm = 0.15f * (max - min);
+			float scale = 2.0f / focusedAt50Cm;
+
+			metadata->set(controls::LensPosition,
+				      (value.get<int32_t>() - min) * scale);
+			break;
+		}
+
+		case V4L2_CID_FOCUS_AUTO: {
+			metadata->set(controls::AfMode,
+				      value.get<int32_t>() == 0
+					      ? controls::AfModeManual
+					      : controls::AfModeContinuous);
+			break;
+		}
+
+		default:;
+		}
+	}
 
 	pipe()->completeBuffer(request, buffer);
 	pipe()->completeRequest(request);