From patchwork Sat Apr 25 00:45:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3535 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9229262E67 for ; Sat, 25 Apr 2020 02:45:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="c1VnRet0"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 14AC8A2A; Sat, 25 Apr 2020 02:45:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1587775552; bh=448iEOPlaUemeZNL2zT+W4rOBRbWl1QT4fdKb9St0Js=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=c1VnRet0acqX7sdQKSLhRdx8MzPhxDJwsq3PKnCwkl+r3JJMLRBKgZfI7n2qGvYDd XPQHtlj8tyQdZQ4fOU2RDN9sGZxIPzIaAXON1v4HYLyqf3/SnIz+WkED7YeHnpJBOq 8n8imFZ9bgCLGvivr0wOXIf4Hl0Xu0JDXI3U//yA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Apr 2020 03:45:27 +0300 Message-Id: <20200425004533.26907-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> References: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 1/7] libcamera: pipeline: uvcvideo: Refactor control handling X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Apr 2020 00:45:52 -0000 Move addition and processing of individual controls to separate functions, to prepare for more complex mappings of control values. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 103 ++++++++++++------- 1 file changed, 67 insertions(+), 36 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index ffbddf27ae2f..92777b9f5fe4 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -42,6 +42,8 @@ public: } int init(MediaEntity *entity); + void addControl(uint32_t cid, const ControlInfo &v4l2info, + ControlInfoMap::Map *ctrls); void bufferReady(FrameBuffer *buffer); V4L2VideoDevice *video_; @@ -76,6 +78,8 @@ public: bool match(DeviceEnumerator *enumerator) override; private: + int processControl(ControlList *controls, unsigned int id, + const ControlValue &value); int processControls(UVCCameraData *data, Request *request); UVCCameraData *cameraData(const Camera *camera) @@ -237,6 +241,37 @@ void PipelineHandlerUVC::stop(Camera *camera) data->video_->releaseBuffers(); } +int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, + const ControlValue &value) +{ + if (value.type() != ControlTypeInteger32) + return -EINVAL; + + uint32_t cid; + + if (id == controls::Brightness) + cid = V4L2_CID_BRIGHTNESS; + else if (id == controls::Contrast) + cid = V4L2_CID_CONTRAST; + else if (id == controls::Saturation) + cid = V4L2_CID_SATURATION; + else if (id == controls::ManualExposure) + cid = V4L2_CID_EXPOSURE_ABSOLUTE; + else if (id == controls::ManualGain) + cid = V4L2_CID_GAIN; + else + return -EINVAL; + + int32_t ivalue = value.get(); + + if (cid == V4L2_CID_EXPOSURE_ABSOLUTE) + controls->set(V4L2_CID_EXPOSURE_AUTO, static_cast(1)); + + controls->set(cid, ivalue); + + return 0; +} + int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) { ControlList controls(data->video_->controls()); @@ -245,18 +280,7 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) 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); - } else if (id == controls::ManualExposure) { - controls.set(V4L2_CID_EXPOSURE_AUTO, static_cast(1)); - controls.set(V4L2_CID_EXPOSURE_ABSOLUTE, value); - } else if (id == controls::ManualGain) { - controls.set(V4L2_CID_GAIN, value); - } + processControl(&controls, id, value); } for (const auto &ctrl : controls) @@ -346,34 +370,13 @@ int UVCCameraData::init(MediaEntity *entity) video_->bufferReady.connect(this, &UVCCameraData::bufferReady); /* Initialise the supported controls. */ - const ControlInfoMap &controls = video_->controls(); ControlInfoMap::Map ctrls; - for (const auto &ctrl : controls) { + for (const auto &ctrl : video_->controls()) { + uint32_t cid = ctrl.first->id(); const ControlInfo &info = ctrl.second; - const ControlId *id; - switch (ctrl.first->id()) { - case V4L2_CID_BRIGHTNESS: - id = &controls::Brightness; - break; - case V4L2_CID_CONTRAST: - id = &controls::Contrast; - break; - case V4L2_CID_SATURATION: - id = &controls::Saturation; - break; - case V4L2_CID_EXPOSURE_ABSOLUTE: - id = &controls::ManualExposure; - break; - case V4L2_CID_GAIN: - id = &controls::ManualGain; - break; - default: - continue; - } - - ctrls.emplace(id, info); + addControl(cid, info, &ctrls); } controlInfo_ = std::move(ctrls); @@ -381,6 +384,34 @@ int UVCCameraData::init(MediaEntity *entity) return 0; } +void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, + ControlInfoMap::Map *ctrls) +{ + const ControlId *id; + + switch (cid) { + case V4L2_CID_BRIGHTNESS: + id = &controls::Brightness; + break; + case V4L2_CID_CONTRAST: + id = &controls::Contrast; + break; + case V4L2_CID_SATURATION: + id = &controls::Saturation; + break; + case V4L2_CID_EXPOSURE_ABSOLUTE: + id = &controls::ManualExposure; + break; + case V4L2_CID_GAIN: + id = &controls::ManualGain; + break; + default: + return; + } + + ctrls->emplace(id, v4l2Info); +} + void UVCCameraData::bufferReady(FrameBuffer *buffer) { Request *request = buffer->request(); From patchwork Sat Apr 25 00:45:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3536 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EB24162E67 for ; Sat, 25 Apr 2020 02:45:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tvC8980u"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 79446A4F; Sat, 25 Apr 2020 02:45:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1587775552; bh=avs0w/guuptuEhMqpbQSNR1GngWJj0G0drhYY+7n9YE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tvC8980uGqdYvkcdnxbGNS5KNsRlpU6jRC+OrXPltlOsU7ColaY5PNC7Hp6/6/4NE 5Iuf4NvBFhLMIPsjLfZS6P9JdBNAjelkVtOMB4kEEF2qjRPBKNkn5SZMTiKNnIiyV2 qoSLFeyxQBQXDSI5Nu8zEImguFohTCh7Rhm7esE8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Apr 2020 03:45:28 +0300 Message-Id: <20200425004533.26907-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> References: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 2/7] libcamera: pipeline: uvcvideo: Add support for AeEnable X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Apr 2020 00:45:53 -0000 UVC devices support auto-exposure, expose the feature through the AeEnable control. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 42 +++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 92777b9f5fe4..b040f2460b1c 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -244,9 +244,6 @@ void PipelineHandlerUVC::stop(Camera *camera) int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, const ControlValue &value) { - if (value.type() != ControlTypeInteger32) - return -EINVAL; - uint32_t cid; if (id == controls::Brightness) @@ -255,6 +252,8 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, cid = V4L2_CID_CONTRAST; else if (id == controls::Saturation) cid = V4L2_CID_SATURATION; + else if (id == controls::AeEnable) + cid = V4L2_CID_EXPOSURE_AUTO; else if (id == controls::ManualExposure) cid = V4L2_CID_EXPOSURE_ABSOLUTE; else if (id == controls::ManualGain) @@ -262,12 +261,21 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, else return -EINVAL; - int32_t ivalue = value.get(); + switch (cid) { + case V4L2_CID_EXPOSURE_AUTO: { + int32_t ivalue = value.get() + ? V4L2_EXPOSURE_APERTURE_PRIORITY + : V4L2_EXPOSURE_MANUAL; + controls->set(V4L2_CID_EXPOSURE_AUTO, ivalue); + break; + } - if (cid == V4L2_CID_EXPOSURE_ABSOLUTE) - controls->set(V4L2_CID_EXPOSURE_AUTO, static_cast(1)); - - controls->set(cid, ivalue); + default: { + int32_t ivalue = value.get(); + controls->set(cid, ivalue); + break; + } + } return 0; } @@ -388,7 +396,9 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, ControlInfoMap::Map *ctrls) { const ControlId *id; + ControlInfo info; + /* Map the control ID. */ switch (cid) { case V4L2_CID_BRIGHTNESS: id = &controls::Brightness; @@ -399,6 +409,9 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, case V4L2_CID_SATURATION: id = &controls::Saturation; break; + case V4L2_CID_EXPOSURE_AUTO: + id = &controls::AeEnable; + break; case V4L2_CID_EXPOSURE_ABSOLUTE: id = &controls::ManualExposure; break; @@ -409,7 +422,18 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, return; } - ctrls->emplace(id, v4l2Info); + /* Map the control info. */ + switch (cid) { + case V4L2_CID_EXPOSURE_AUTO: + info = ControlInfo{ false, true, true }; + break; + + default: + info = v4l2Info; + break; + } + + ctrls->emplace(id, info); } void UVCCameraData::bufferReady(FrameBuffer *buffer) From patchwork Sat Apr 25 00:45:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3537 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5D12462E45 for ; Sat, 25 Apr 2020 02:45:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MgpH4N9b"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DCE27DAD; Sat, 25 Apr 2020 02:45:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1587775553; bh=BX8EnDSYZidO11p66DGz/BVxNd8Tm7yk+F1W2wGxoZc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MgpH4N9bc0klcgYDdCCm/xRN/0GONeE5uZ0kN3IUKot18w5bVvetLofQf661SCVHG XbX9RUebpzCLZfM97m/Q8a1OBI6zaTVGFIQ3obqTjKF5hZnanM1f1bRuAA+//tbm4i pR3BVuObXn1DFZb4au/11pbzOVzuixOhDhu5Tl9E= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Apr 2020 03:45:29 +0300 Message-Id: <20200425004533.26907-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> References: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 3/7] libcamera: control_ids: Add comment to specify control direction X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Apr 2020 00:45:53 -0000 From: Naushir Patuck Document that controls are bi-directional by default. If a control is only returned in metadata, this must be specified in the control's description. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- src/libcamera/control_ids.cpp.in | 3 +++ src/libcamera/control_ids.yaml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in index 99c511d0e712..cba6258d68dd 100644 --- a/src/libcamera/control_ids.cpp.in +++ b/src/libcamera/control_ids.cpp.in @@ -33,6 +33,9 @@ ${controls_def} /** * \brief List of all supported libcamera controls + * + * Unless otherwise stated, all controls are bi-directional, i.e. they can be + * set through Request::controls() and returned out through Request::metadata(). */ extern const ControlIdMap controls { ${controls_map} diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index 4befec746a59..bcbab195a374 100644 --- a/src/libcamera/control_ids.yaml +++ b/src/libcamera/control_ids.yaml @@ -4,6 +4,8 @@ # %YAML 1.2 --- +# Unless otherwise stated, all controls are bi-directional, i.e. they can be +# set through Request::controls() and returned out through Request::metadata(). controls: - AeEnable: type: bool From patchwork Sat Apr 25 00:45:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3538 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C782E62E45 for ; Sat, 25 Apr 2020 02:45:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VgjGHQZZ"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4D49E4F7; Sat, 25 Apr 2020 02:45:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1587775553; bh=2hq6nSqBeXPY+gKPtrw3F1EgXjYPCWQB3Wf8fmoaKrQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VgjGHQZZ2ufQaiEOtDG/KHAtiQ3o7uj4TyVgH4CkVvA0z9ixqF0tHy6J0Ti5AJ89i IoTikoSq9iHNYnJ/prlCpTyCgkqP/I53P9thnYSSUXT5phuFAbbAsSWCsZNoQhTEyl Behl5nkcNWh2+qgDsz9/h/lKaYvONpHcWGRXO4+A= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Apr 2020 03:45:30 +0300 Message-Id: <20200425004533.26907-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> References: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 4/7] libcamera: controls: Updates to gain and exposure controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Apr 2020 00:45:55 -0000 From: Naushir Patuck Rename: ManualExposure -> ExposureTime ManualGain -> AnalogueGain Use micro-seconds units for ExposureTime. This is changed from milli- seconds. The latter would not allow very low exposure times. AnalogueGain switch to use a float to allow fractional gain adjustments. Update the uvcvideo pipeline handler to use the new exposure and gain units. For ExposureTime, UVC uses units of 100 micro-seconds, so map the values before setting V4L2_CID_EXPOSURE_ABSOLUTE. For AnalogueGain, UVC has no explicit gain units, so map the default gain value to 1.0 and linearly scale to the requested value. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- src/libcamera/control_ids.yaml | 22 ++++-- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 77 +++++++++++++++++++- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index bcbab195a374..d8bdb3829be4 100644 --- a/src/libcamera/control_ids.yaml +++ b/src/libcamera/control_ids.yaml @@ -12,7 +12,7 @@ controls: description: | Enable or disable the AE. - \sa ManualExposure + \sa ExposureTime AnalogueGain - AeLocked: type: bool @@ -30,8 +30,6 @@ controls: description: | Enable or disable the AWB. - \sa ManualGain - - Brightness: type: int32_t description: Specify a fixed brightness parameter @@ -44,12 +42,20 @@ controls: type: int32_t description: Specify a fixed saturation parameter - - ManualExposure: + - ExposureTime: type: int32_t - description: Specify a fixed exposure time in milli-seconds + description: | + Exposure time (shutter speed) for the frame applied in the sensor + device. This value is specified in micro-seconds. - - ManualGain: - type: int32_t - description: Specify a fixed gain parameter + \sa AnalogueGain AeEnable + + - AnalogueGain: + type: float + description: | + Analogue gain value applied in the sensor device. + The value of the control specifies the gain multiplier applied to all + colour channels. This value cannot be lower than 1.0. + \sa ExposureTime AeEnable ... diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index b040f2460b1c..452f38dcad2f 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -254,13 +254,19 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, cid = V4L2_CID_SATURATION; else if (id == controls::AeEnable) cid = V4L2_CID_EXPOSURE_AUTO; - else if (id == controls::ManualExposure) + else if (id == controls::ExposureTime) cid = V4L2_CID_EXPOSURE_ABSOLUTE; - else if (id == controls::ManualGain) + else if (id == controls::AnalogueGain) cid = V4L2_CID_GAIN; else return -EINVAL; + const ControlInfo &v4l2Info = controls->infoMap()->at(cid); + + /* + * See UVCCameraData::addControl() for explanations of the different + * value mappings. + */ switch (cid) { case V4L2_CID_EXPOSURE_AUTO: { int32_t ivalue = value.get() @@ -270,6 +276,28 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, break; } + case V4L2_CID_EXPOSURE_ABSOLUTE: + controls->set(cid, value.get() / 100); + break; + + case V4L2_CID_GAIN: { + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + int32_t def = v4l2Info.def().get(); + + 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 = (value.get() - p) / m; + controls->set(cid, static_cast(lroundf(fvalue))); + break; + } + default: { int32_t ivalue = value.get(); controls->set(cid, ivalue); @@ -413,21 +441,62 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, id = &controls::AeEnable; break; case V4L2_CID_EXPOSURE_ABSOLUTE: - id = &controls::ManualExposure; + id = &controls::ExposureTime; break; case V4L2_CID_GAIN: - id = &controls::ManualGain; + id = &controls::AnalogueGain; break; default: return; } /* Map the control info. */ + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + int32_t def = v4l2Info.def().get(); + switch (cid) { case V4L2_CID_EXPOSURE_AUTO: info = ControlInfo{ false, true, true }; break; + case V4L2_CID_EXPOSURE_ABSOLUTE: + /* + * ExposureTime is in units of 1 µs, and UVC expects + * V4L2_CID_EXPOSURE_ABSOLUTE in units of 100 µs. + */ + info = ControlInfo{ + { min * 100 }, + { max * 100 }, + { def * 100 } + }; + break; + + 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. + */ + 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; + } + + info = ControlInfo{ + { m * min + p }, + { m * max + p }, + { 1.0f } + }; + break; + } + default: info = v4l2Info; break; From patchwork Sat Apr 25 00:45:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3539 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2C42062F46 for ; Sat, 25 Apr 2020 02:45:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WWjP3ISN"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B261CA2A; Sat, 25 Apr 2020 02:45:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1587775553; bh=Wr1ZUSdGxzfgfnN8TbrmAFULWcf48CQEb2xYk2mYw1Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WWjP3ISNzvJW93iFjfRRSU9mRkxMjS52RLYvyKwBZFPuKeGzMuSL7vgBxoq4NpaZE hksxnOdLDrTNbSf9sdRpolLseiCYNuj/yCfbslrCXJJKVt6z0q3KeQ4Ps8X6XbSOht 9X7JzPEesxK/WQc6A58PgB+MESCa06yZhHKVpNWk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Apr 2020 03:45:31 +0300 Message-Id: <20200425004533.26907-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> References: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 5/7] libcamera: controls: Reorder and update description of existing controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Apr 2020 00:45:55 -0000 From: Naushir Patuck Group AE, AWB, etc. controls together for accessibility. Update descriptions for Contrast, Brightness, and Saturation controls. Update the uvcvideo and vimc pipeline handlers to use the new brightness, contrast and saturation units. UVC has no explicit units for those controls, so map them with a best effort heuristic. For VIMC, hardcode the control range based on knowledge of the driver implementation for simplicity. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- src/libcamera/control_ids.yaml | 42 +++++++----- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 67 +++++++++++++++++--- src/libcamera/pipeline/vimc/vimc.cpp | 29 ++++++--- 3 files changed, 103 insertions(+), 35 deletions(-) diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index d8bdb3829be4..f2ac052b3d3e 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 452f38dcad2f..136d6d0af5d5 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -262,12 +262,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 def = v4l2Info.def().get(); + int32_t max = v4l2Info.max().get(); /* * 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() * scale + def; + controls->set(cid, static_cast(lroundf(fvalue))); + break; + } + + case V4L2_CID_SATURATION: { + float scale = def - min; + float fvalue = value.get() * scale + min; + controls->set(cid, static_cast(lroundf(fvalue))); + break; + } + case V4L2_CID_EXPOSURE_AUTO: { int32_t ivalue = value.get() ? V4L2_EXPOSURE_APERTURE_PRIORITY @@ -280,11 +297,8 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, controls->set(cid, value.get() / 100); break; + case V4L2_CID_CONTRAST: case V4L2_CID_GAIN: { - int32_t min = v4l2Info.min().get(); - int32_t max = v4l2Info.max().get(); - int32_t def = v4l2Info.def().get(); - float m = (4.0f - 1.0f) / (max - def); float p = 1.0f - m * def; @@ -456,6 +470,38 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, int32_t def = v4l2Info.def().get(); 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(min - def) / scale }, + { static_cast(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(max - min) / (def - min) }, + { 1.0f } + }; + break; + case V4L2_CID_EXPOSURE_AUTO: info = ControlInfo{ false, true, true }; break; @@ -472,14 +518,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 c5eea3a01b0e..62279ef17102 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -304,14 +304,24 @@ int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request) for (auto it : request->controls()) { unsigned int id = it.first; - ControlValue &value = it.second; + unsigned int offset; + uint32_t cid; - 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); + 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() * 128 + offset); + controls.set(cid, utils::clamp(value, 0, 255)); } for (const auto &ctrl : controls) @@ -434,18 +444,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; From patchwork Sat Apr 25 00:45:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3540 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9678262F15 for ; Sat, 25 Apr 2020 02:45:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FTty0pT7"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 264324F7; Sat, 25 Apr 2020 02:45:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1587775554; bh=YRZFnsiPti/+Mwqbo5vguecZLZ3p2Jphcr1Rcxy7xF8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FTty0pT7OY0tDc7x+8Mz85yxrTP0sA49cEyVYz07Jd0Wif/WkCLBOfbgJdLQUe/aX bfAXtcUbm+lAHj8mweFcU337TlQZG399CMXN1lySoYjAgJGEqxek4ajQLB7H2xEgeT T1Zn3e9B+OxI3PBIkMFARwqzIlfEpObhgPK6QjPk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Apr 2020 03:45:32 +0300 Message-Id: <20200425004533.26907-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> References: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 6/7] libcamera: controls: Add AE related controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Apr 2020 00:45:56 -0000 From: Naushir Patuck AeMeteringMode, AeConstraintMode, and AeExposureMode are new enum type controls used to specify operating modes in the AE algorithm. All modes may not be supported by all platforms. ExposureValue is a new control used to set the log2 exposure adjustment for the AE algorithm. Lux is a new control that returns the current lux estimate. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- src/libcamera/control_ids.yaml | 109 +++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index f2ac052b3d3e..0907167fccea 100644 --- a/src/libcamera/control_ids.yaml +++ b/src/libcamera/control_ids.yaml @@ -25,6 +25,109 @@ controls: \sa AeEnable + # AeMeteringMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeMeteringMode: + type: int32_t + description: | + Specify a metering mode for the AE algorithm to use. The metering + modes determine which parts of the image are used to determine the + scene brightness. Metering modes may be platform specific and not + all metering modes may be supported. + enum: + - name: MeteringCentreWeighted + value: 0 + description: Centre-weighted metering mode. + - name: MeteringSpot + value: 1 + description: Spot metering mode. + - name: MeteringMatrix + value: 2 + description: Matrix metering mode. + - name: MeteringCustom + value: 3 + description: Custom metering mode. + - name: MeteringModeMax + value: 3 + description: Maximum allowed value (place any new values above here). + + # AeConstraintMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeConstraintMode: + type: int32_t + description: | + Specify a constraint mode for the AE algorithm to use. These determine + how the measured scene brightness is adjusted to reach the desired + target exposure. Constraint modes may be platform specific, and not + all constraint modes may be supported. + enum: + - name: ConstraintNormal + value: 0 + description: Default constraint mode. + This mode aims to balance the exposure of different parts of the + image so as to reach a reasonable average level. However, highlights + in the image may appear over-exposed and lowlights may appear + under-exposed. + - name: ConstraintHighlight + value: 1 + description: Highlight constraint mode. + This mode adjusts the exposure levels in order to try and avoid + over-exposing the brightest parts (highlights) of an image. + Other non-highlight parts of the image may appear under-exposed. + - name: ConstraintShadows + value: 2 + description: Shadows constraint mode. + This mode adjusts the exposure levels in order to try and avoid + under-exposing the dark parts (shadows) of an image. Other normally + exposed parts of the image may appear over-exposed. + - name: ConstraintCustom + value: 3 + description: Custom constraint mode. + - name: ConstraintModeMax + value: 3 + description: Maximum allowed value (place any new values above here). + + # AeExposureMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeExposureMode: + type: int32_t + description: | + Specify an exposure mode for the AE algorithm to use. These specify + how the desired total exposure is divided between the shutter time + and the sensor's analogue gain. The exposure modes are platform + specific, and not all exposure modes may be supported. + enum: + - name: ExposureNormal + value: 0 + description: Default exposure mode. + - name: ExposureShort + value: 1 + description: Exposure mode allowing only short exposure times. + - name: ExposureLong + value: 2 + description: Exposure mode allowing long exposure times. + - name: ExposureCustom + value: 3 + description: Custom exposure mode. + - name: ExposureModeMax + value: 3 + description: Maximum allowed value (place any new values above here). + + - ExposureValue: + type: float + description: | + Specify an Exposure Value (EV) parameter. The EV parameter will only be + applied if the AE algorithm is currently enabled. + + By convention EV adjusts the exposure as log2. For example + EV = [-2, -1, 0.5, 0, 0.5, 1, 2] results in an exposure adjustment + of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + + \sa AeEnable + - ExposureTime: type: int32_t description: | @@ -55,6 +158,12 @@ controls: Specify a fixed contrast parameter. Normal contrast is given by the value 1.0; larger values produce images with more contrast. + - Lux: + type: float + description: | + Report an estimate of the current illuminance level in lux. The Lux + control can only be returned in metadata. + - AwbEnable: type: bool description: | From patchwork Sat Apr 25 00:45:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3541 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 107C462E67 for ; Sat, 25 Apr 2020 02:45:55 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rXC6WOQi"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 90B27A2A; Sat, 25 Apr 2020 02:45:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1587775554; bh=Oi1jVtSGbQr9uMAM40281tGAzsmNj2397nd0PAcwxg0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rXC6WOQiiAG8cEB5IRgzhVjs2qHsjObHI5NEjXkHNnbYeCbsHnNrUgtj+DedUAJUD JyNArGgls9Ygmtrgc3b/iiJRnrXmre0gSpRV5BcKryyCzFnCfrLWIvv8uh9sAfuAzS SFVLZq7dSZqyULqXGDIkQp+JwgyVbLDt4fXfFhD0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Apr 2020 03:45:33 +0300 Message-Id: <20200425004533.26907-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> References: <20200425004533.26907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 7/7] libcamera: controls: Add AWB related controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Apr 2020 00:45:56 -0000 From: Naushir Patuck AwbMode is a new enum type to specify operating mode of the AWB algorithm. All modes may not be supported by all platforms. ColourGains is a new float array type used to specify manual red and blue (in that order) colour channel gains when AWB is disabled. ColourTemperature is a new control to return the current estimate of the colour temperature. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- src/libcamera/control_ids.yaml | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index 0907167fccea..b419f8a78c19 100644 --- a/src/libcamera/control_ids.yaml +++ b/src/libcamera/control_ids.yaml @@ -169,6 +169,61 @@ controls: description: | Enable or disable the AWB. + \sa ColourGains + + # AwbMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AwbMode: + type: int32_t + description: | + Specify the range of illuminants to use for the AWB algorithm. The modes + supported are platform specific, and not all modes may be supported. + enum: + - name: AwbAuto + value: 0 + description: Search over the whole colour temperature range. + - name: AwbIncandescent + value: 1 + description: Incandescent AWB lamp mode. + - name: AwbTungsten + value: 2 + description: Tungsten AWB lamp mode. + - name: AwbFluorescent + value: 3 + description: Fluorescent AWB lamp mode. + - name: AwbIndoor + value: 4 + description: Indoor AWB lighting mode. + - name: AwbDaylight + value: 5 + description: Daylight AWB lighting mode. + - name: AwbCloudy + value: 6 + description: Cloudy AWB lighting mode. + - name: AwbCustom + value: 7 + description: Custom AWB mode. + - name: AwbModeMax + value: 7 + description: Maximum allowed value (place any new values above here). + + - ColourGains: + type: float + description: | + Pair of gain values for the Red and Blue colour channels, in that + order. ColourGains can only be applied in a Request when the AWB is + disabled. + + \sa AwbEnable + size: [2] + + - ColourTemperature: + type: int32_t + description: Report the current estimate of the colour temperature, in + kelvin, for this frame. The ColourTemperature control can only be + returned in metadata. + - Saturation: type: float description: |