[PATCH] libcamera: pipeline: uvcvideo: Map focus controls
Cláudio Paulo
claudio.paulo at makewise.pt
Fri Sep 13 19:22:03 CEST 2024
Added mapping of controls::LensPosition and controls::AfMode to
v4l2 controls V4L2_CID_FOCUS_ABSOLUTE and V4L2_CID_FOCUS_AUTO
respectively when the device supports them.
If not supported, they are not registered.
Signed-off-by: Cláudio Paulo <claudio.paulo at makewise.pt>
---
include/linux/v4l2-controls.h | 4 +
src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 88 +++++++++++++++++---
2 files changed, 82 insertions(+), 10 deletions(-)
diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h
index 882a8180..1ac85507 100644
--- a/include/linux/v4l2-controls.h
+++ b/include/linux/v4l2-controls.h
@@ -994,6 +994,10 @@ enum v4l2_exposure_auto_type {
#define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10)
#define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11)
#define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12)
+enum v4l2_focus_auto_type {
+ V4L2_FOCUS_MANUAL = 0,
+ V4L2_FOCUS_AUTO = 1
+};
#define V4L2_CID_ZOOM_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+13)
#define V4L2_CID_ZOOM_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+14)
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 6b32fa18..fe3c71d0 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -304,13 +304,14 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
cid = V4L2_CID_EXPOSURE_ABSOLUTE;
else if (id == controls::AnalogueGain)
cid = V4L2_CID_GAIN;
+ else if (id == controls::LensPosition && controls->idMap()->count(V4L2_CID_FOCUS_ABSOLUTE)) // Check if device supports this control
+ cid = V4L2_CID_FOCUS_ABSOLUTE;
+ else if (id == controls::AfMode && controls->idMap()->count(V4L2_CID_FOCUS_AUTO)) // Check if device supports this control
+ cid = V4L2_CID_FOCUS_AUTO;
else
return -EINVAL;
const ControlInfo &v4l2Info = controls->infoMap()->at(cid);
- int32_t min = v4l2Info.min().get<int32_t>();
- int32_t def = v4l2Info.def().get<int32_t>();
- int32_t max = v4l2Info.max().get<int32_t>();
/*
* See UVCCameraData::addControl() for explanations of the different
@@ -318,6 +319,10 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
*/
switch (cid) {
case V4L2_CID_BRIGHTNESS: {
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+
float scale = std::max(max - def, def - min);
float fvalue = value.get<float>() * scale + def;
controls->set(cid, static_cast<int32_t>(lroundf(fvalue)));
@@ -325,6 +330,9 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
}
case V4L2_CID_SATURATION: {
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
+
float scale = def - min;
float fvalue = value.get<float>() * scale + min;
controls->set(cid, static_cast<int32_t>(lroundf(fvalue)));
@@ -345,6 +353,10 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
case V4L2_CID_CONTRAST:
case V4L2_CID_GAIN: {
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+
float m = (4.0f - 1.0f) / (max - def);
float p = 1.0f - m * def;
@@ -358,6 +370,22 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
break;
}
+ case V4L2_CID_FOCUS_ABSOLUTE: {
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+
+ float focusedAt50Cm = 0.15f * (max - min);
+ float scale = focusedAt50Cm / 2.0f;
+
+ controls->set(cid, static_cast<int>(min + value.get<float>() * scale));
+ break;
+ }
+
+ case V4L2_CID_FOCUS_AUTO: {
+ controls->set(cid, static_cast<int>(value.get<int>() == 0 ? V4L2_FOCUS_MANUAL : V4L2_FOCUS_AUTO));
+ break;
+ }
+
default: {
int32_t ivalue = value.get<int32_t>();
controls->set(cid, ivalue);
@@ -655,14 +683,17 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,
case V4L2_CID_GAIN:
id = &controls::AnalogueGain;
break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ id = &controls::LensPosition;
+ break;
+ case V4L2_CID_FOCUS_AUTO:
+ id = &controls::AfMode;
+ break;
default:
return;
}
/* Map the control info. */
- int32_t min = v4l2Info.min().get<int32_t>();
- int32_t max = v4l2Info.max().get<int32_t>();
- int32_t def = v4l2Info.def().get<int32_t>();
switch (cid) {
case V4L2_CID_BRIGHTNESS: {
@@ -673,6 +704,9 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,
* Accommodate this by restricting the range of the libcamera
* control, but always within the maximum limits.
*/
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
float scale = std::max(max - def, def - min);
info = ControlInfo{
@@ -683,36 +717,42 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,
break;
}
- case V4L2_CID_SATURATION:
+ case V4L2_CID_SATURATION: {
/*
* The Saturation control is a float, with 0.0 mapped to the
* minimum value (corresponding to a fully desaturated image)
* and 1.0 mapped to the default value. Calculate the maximum
* value accordingly.
*/
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
info = ControlInfo{
{ 0.0f },
{ static_cast<float>(max - min) / (def - min) },
{ 1.0f }
};
break;
-
+ }
case V4L2_CID_EXPOSURE_AUTO:
info = ControlInfo{ false, true, true };
break;
- case V4L2_CID_EXPOSURE_ABSOLUTE:
+ case V4L2_CID_EXPOSURE_ABSOLUTE: {
/*
* ExposureTime is in units of 1 µs, and UVC expects
* V4L2_CID_EXPOSURE_ABSOLUTE in units of 100 µs.
*/
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
info = ControlInfo{
{ min * 100 },
{ max * 100 },
{ def * 100 }
};
break;
-
+ }
case V4L2_CID_CONTRAST:
case V4L2_CID_GAIN: {
/*
@@ -723,6 +763,9 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,
* maximum values are respectively no lower than 0.5 and no
* higher than 4.0.
*/
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
float m = (4.0f - 1.0f) / (max - def);
float p = 1.0f - m * def;
@@ -738,6 +781,31 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,
};
break;
}
+ case V4L2_CID_FOCUS_ABSOLUTE: {
+ int32_t min = v4l2Info.min().get<int32_t>();
+ int32_t max = v4l2Info.max().get<int32_t>();
+ int32_t def = v4l2Info.def().get<int32_t>();
+
+ float focusedAt50Cm = 0.15f * (max - min);
+ float scale = 2.0f / focusedAt50Cm;
+
+ info = ControlInfo{
+ { 0.0f },
+ { scale * (max - min) },
+ { scale * (def - min) }
+ };
+ break;
+ }
+ case V4L2_CID_FOCUS_AUTO: {
+ bool def = v4l2Info.def().get<bool>();
+
+ info = ControlInfo{
+ { static_cast<int>(V4L2_FOCUS_MANUAL) },
+ { static_cast<int>(V4L2_FOCUS_AUTO) },
+ { static_cast<int>(def ? V4L2_FOCUS_AUTO : V4L2_FOCUS_MANUAL) },
+ };
+ break;
+ }
default:
info = v4l2Info;
--
2.34.1
More information about the libcamera-devel
mailing list