@@ -6,9 +6,9 @@
*/
#include <algorithm>
+#include <cmath>
#include <fstream>
#include <map>
-#include <math.h>
#include <memory>
#include <set>
#include <string>
@@ -304,13 +304,33 @@ 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)
+ cid = V4L2_CID_FOCUS_ABSOLUTE;
+ else if (id == controls::AfMode)
+ cid = V4L2_CID_FOCUS_AUTO;
else
return -EINVAL;
+ /* Check if the device supports this control. */
+ if (controls->idMap()->find(cid) == controls->idMap()->end())
+ 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>();
+
+ int32_t min, def, max;
+ if (v4l2Info.min().type() == ControlTypeInteger32) {
+ min = v4l2Info.min().get<int32_t>();
+ def = v4l2Info.def().get<int32_t>();
+ max = v4l2Info.max().get<int32_t>();
+ } else if (v4l2Info.min().type() == ControlTypeBool) {
+ min = v4l2Info.min().get<bool>();
+ def = v4l2Info.def().get<bool>();
+ max = v4l2Info.max().get<bool>();
+ } else {
+ LOG(UVC, Error) << "v4l2 ControlInfo with value type "
+ << v4l2Info.min().type() << " not mapped";
+ return -EINVAL;
+ }
/*
* See UVCCameraData::addControl() for explanations of the different
@@ -358,6 +378,21 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
break;
}
+ case V4L2_CID_FOCUS_ABSOLUTE: {
+ float focusedAt50Cm = 0.15f * (max - min);
+ float scale = focusedAt50Cm / 2.0f;
+
+ float fvalue = value.get<float>() * scale + min;
+ controls->set(cid, static_cast<int32_t>(std::lround(fvalue)));
+ break;
+ }
+
+ case V4L2_CID_FOCUS_AUTO: {
+ int32_t ivalue = value.get<int32_t>() != controls::AfModeManual;
+ controls->set(cid, ivalue);
+ break;
+ }
+
default: {
int32_t ivalue = value.get<int32_t>();
controls->set(cid, ivalue);
@@ -655,14 +690,31 @@ 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>();
+ int32_t min, def, max;
+ if (v4l2Info.min().type() == ControlTypeInteger32) {
+ min = v4l2Info.min().get<int32_t>();
+ def = v4l2Info.def().get<int32_t>();
+ max = v4l2Info.max().get<int32_t>();
+ } else if (v4l2Info.min().type() == ControlTypeBool) {
+ min = v4l2Info.min().get<bool>();
+ def = v4l2Info.def().get<bool>();
+ max = v4l2Info.max().get<bool>();
+ } else {
+ LOG(UVC, Error) << "v4l2 ControlInfo with value type "
+ << v4l2Info.min().type() << " not mapped";
+ return;
+ }
switch (cid) {
case V4L2_CID_BRIGHTNESS: {
@@ -739,6 +791,47 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,
break;
}
+ case V4L2_CID_FOCUS_ABSOLUTE: {
+ /*
+ * LensPosition expects values to be in the range of
+ * [0.0f, maxDioptres], while a value of 0 means focused to
+ * infinity, 0.5 means focused at 2m, 2 means focused at 50cm
+ * and maxDioptres will be the closest possible focus which
+ * will equate to a focus distance of (1 / maxDioptres) metres.
+ *
+ * \todo These values will definitely vary for each different
+ * hardware, so this should be tunable somehow. In this case
+ * 0.15f (~= 150 / (1023 - 1)) was a value read from
+ * V4L2_CID_FOCUS_ABSOLUTE control when using a random camera
+ * and having it autofocus at a distance of about 50cm.
+ * This means the minimum focus distance of this camera should
+ * be 75mm (0.15 / 2) which equals a maxDioptres value of ~=
+ * 13.3333 (2 / 0.15). Also, the values might not scale
+ * linearly, but this implementation assumes they do.
+ */
+ float focusedAt50Cm = 0.15f * (max - min);
+ float scale = 2.0f / focusedAt50Cm;
+
+ info = ControlInfo{
+ { 0.0f },
+ { (max - min) * scale },
+ { (def - min) * scale }
+ };
+ break;
+ }
+
+ case V4L2_CID_FOCUS_AUTO: {
+ std::vector<ControlValue> values;
+
+ if (!min || !max)
+ values.emplace_back(static_cast<int32_t>(controls::AfModeManual));
+ if (min || max)
+ values.emplace_back(static_cast<int32_t>(controls::AfModeContinuous));
+
+ info = ControlInfo{ values, values.back() };
+ break;
+ }
+
default:
info = v4l2Info;
break;
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@makewise.pt> --- Fixed issues raised in review. src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 107 +++++++++++++++++-- 1 file changed, 100 insertions(+), 7 deletions(-)