diff options
-rw-r--r-- | src/libcamera/control_ids.yaml | 42 | ||||
-rw-r--r-- | src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 67 | ||||
-rw-r--r-- | src/libcamera/pipeline/vimc/vimc.cpp | 32 |
3 files changed, 105 insertions, 36 deletions
diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index d8bdb382..f2ac052b 100644 --- a/src/libcamera/control_ids.yaml +++ b/src/libcamera/control_ids.yaml @@ -25,23 +25,6 @@ controls: \sa AeEnable - - AwbEnable: - type: bool - description: | - Enable or disable the AWB. - - - Brightness: - type: int32_t - description: Specify a fixed brightness parameter - - - Contrast: - type: int32_t - description: Specify a fixed contrast parameter - - - Saturation: - type: int32_t - description: Specify a fixed saturation parameter - - ExposureTime: type: int32_t description: | @@ -58,4 +41,29 @@ controls: colour channels. This value cannot be lower than 1.0. \sa ExposureTime AeEnable + + - Brightness: + type: float + description: | + Specify a fixed brightness parameter. Positive values (up to 1.0) + produce brighter images; negative values (up to -1.0) produce darker + images and 0.0 leaves pixels unchanged. + + - Contrast: + type: float + description: | + Specify a fixed contrast parameter. Normal contrast is given by the + value 1.0; larger values produce images with more contrast. + + - AwbEnable: + type: bool + description: | + Enable or disable the AWB. + + - Saturation: + type: float + description: | + Specify a fixed saturation parameter. Normal saturation is given by + the value 1.0; larger values produce more saturated colours; 0.0 + produces a greyscale image. ... diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 08462542..030ac686 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -263,12 +263,29 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, 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 * value mappings. */ switch (cid) { + case V4L2_CID_BRIGHTNESS: { + float scale = std::max(max - def, def - min); + float fvalue = value.get<float>() * scale + def; + controls->set(cid, static_cast<int32_t>(lroundf(fvalue))); + break; + } + + case V4L2_CID_SATURATION: { + float scale = def - min; + float fvalue = value.get<float>() * scale + min; + controls->set(cid, static_cast<int32_t>(lroundf(fvalue))); + break; + } + case V4L2_CID_EXPOSURE_AUTO: { int32_t ivalue = value.get<bool>() ? V4L2_EXPOSURE_APERTURE_PRIORITY @@ -281,11 +298,8 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, controls->set(cid, value.get<int32_t>() / 100); break; + case V4L2_CID_CONTRAST: case V4L2_CID_GAIN: { - 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; @@ -457,6 +471,38 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, int32_t def = v4l2Info.def().get<int32_t>(); switch (cid) { + case V4L2_CID_BRIGHTNESS: { + /* + * The Brightness control is a float, with 0.0 mapped to the + * default value. The control range is [-1.0, 1.0], but the V4L2 + * default may not be in the middle of the V4L2 range. + * Accommodate this by restricting the range of the libcamera + * control, but always within the maximum limits. + */ + float scale = std::max(max - def, def - min); + + info = ControlInfo{ + { static_cast<float>(min - def) / scale }, + { static_cast<float>(max - def) / scale }, + { 0.0f } + }; + break; + } + + 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. + */ + 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; @@ -473,14 +519,15 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, }; break; + case V4L2_CID_CONTRAST: case V4L2_CID_GAIN: { /* - * The AnalogueGain control is a float, with 1.0 mapped to the - * default value. UVC doesn't specify units, and cameras have - * been seen to expose very different ranges for the gain - * control. Arbitrarily assume that the minimum and maximum - * values are respectively no lower than 0.5 and no higher than - * 4.0. + * The Contrast and AnalogueGain controls are floats, with 1.0 + * mapped to the default value. UVC doesn't specify units, and + * cameras have been seen to expose very different ranges for + * the controls. Arbitrarily assume that the minimum and + * maximum values are respectively no lower than 0.5 and no + * higher than 4.0. */ float m = (4.0f - 1.0f) / (max - def); float p = 1.0f - m * def; diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index c5eea3a0..77de4c38 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -8,6 +8,7 @@ #include <algorithm> #include <array> #include <iomanip> +#include <math.h> #include <tuple> #include <linux/media-bus-format.h> @@ -304,14 +305,24 @@ int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request) for (auto it : request->controls()) { unsigned int id = it.first; - ControlValue &value = it.second; - - if (id == controls::Brightness) - controls.set(V4L2_CID_BRIGHTNESS, value); - else if (id == controls::Contrast) - controls.set(V4L2_CID_CONTRAST, value); - else if (id == controls::Saturation) - controls.set(V4L2_CID_SATURATION, value); + unsigned int offset; + uint32_t cid; + + if (id == controls::Brightness) { + cid = V4L2_CID_BRIGHTNESS; + offset = 128; + } else if (id == controls::Contrast) { + cid = V4L2_CID_CONTRAST; + offset = 0; + } else if (id == controls::Saturation) { + cid = V4L2_CID_SATURATION; + offset = 0; + } else { + continue; + } + + int32_t value = lroundf(it.second.get<float>() * 128 + offset); + controls.set(cid, utils::clamp(value, 0, 255)); } for (const auto &ctrl : controls) @@ -434,18 +445,21 @@ int VimcCameraData::init(MediaDevice *media) ControlInfoMap::Map ctrls; for (const auto &ctrl : controls) { - const ControlInfo &info = ctrl.second; const ControlId *id; + ControlInfo info; switch (ctrl.first->id()) { case V4L2_CID_BRIGHTNESS: id = &controls::Brightness; + info = ControlInfo{ { -1.0f }, { 1.0f }, { 0.0f } }; break; case V4L2_CID_CONTRAST: id = &controls::Contrast; + info = ControlInfo{ { 0.0f }, { 2.0f }, { 1.0f } }; break; case V4L2_CID_SATURATION: id = &controls::Saturation; + info = ControlInfo{ { 0.0f }, { 2.0f }, { 1.0f } }; break; default: continue; |