From patchwork Mon Jul 1 20:14:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1567 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D48FB6157C for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 85F61120A for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012130; bh=gnNyFf9fr4k5EzjFRlCoBTokKL0/EqCb1DMlcs9KmZ0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=P58Zr370/CPJc65Zw5GQdwH88tOtBPG0slS9mc28Lqy/LlHJRRImCaStG2md0dMP4 ifnsRBwYBYgsLcUMet2J+j8nFkyAMCB13sXIiwRX+hFkSVyre1gAaXbJYpCXRQAPTl 10VV5AxzLNmkHegysINs66+cgwmhAdEmU3lIBrmw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:59 +0300 Message-Id: <20190701201504.28487-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 08/13] libcamera: pipeline: uvcvideo: Add controls support X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:31 -0000 From: Kieran Bingham Implement control support in the UVC pipeline handler by dynamically querying the V4L2 device for the supported V4L2 controls and populating the list of camera controls accordingly. Not-signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- Changes since v3: - Fixed error checking when setting controls - Fixed handling of the failure to find a default video device --- src/libcamera/pipeline/uvcvideo.cpp | 124 +++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 10 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 2e22523d7cb1..b2f5b2eeed80 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -6,8 +6,11 @@ */ #include +#include +#include #include +#include #include #include @@ -16,6 +19,7 @@ #include "media_device.h" #include "pipeline_handler.h" #include "utils.h" +#include "v4l2_controls.h" #include "v4l2_videodevice.h" namespace libcamera { @@ -35,6 +39,7 @@ public: delete video_; } + int init(MediaEntity *entity); void bufferReady(Buffer *buffer); V4L2VideoDevice *video_; @@ -71,6 +76,8 @@ public: bool match(DeviceEnumerator *enumerator) override; private: + int processControls(UVCCameraData *data, Request *request); + UVCCameraData *cameraData(const Camera *camera) { return static_cast( @@ -216,6 +223,56 @@ void PipelineHandlerUVC::stop(Camera *camera) PipelineHandler::stop(camera); } +int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) +{ + V4L2ControlList controls; + + for (auto it : request->controls()) { + const ControlInfo *ci = it.first; + ControlValue &value = it.second; + + switch (ci->id()) { + case Brightness: + controls.add(V4L2_CID_BRIGHTNESS, value.getInt()); + break; + + case Contrast: + controls.add(V4L2_CID_CONTRAST, value.getInt()); + break; + + case Saturation: + controls.add(V4L2_CID_SATURATION, value.getInt()); + break; + + case ManualExposure: + controls.add(V4L2_CID_EXPOSURE_AUTO, 1); + controls.add(V4L2_CID_EXPOSURE_ABSOLUTE, value.getInt()); + break; + + case ManualGain: + controls.add(V4L2_CID_GAIN, value.getInt()); + break; + + default: + break; + } + } + + for (const V4L2Control &ctrl : controls) + LOG(UVC, Debug) + << "Setting control 0x" + << std::hex << std::setw(8) << ctrl.id() << std::dec + << " to " << ctrl.value(); + + int ret = data->video_->setControls(&controls); + if (ret) { + LOG(UVC, Error) << "Failed to set controls: " << ret; + return ret < 0 ? ret : -EINVAL; + } + + return ret; +} + int PipelineHandlerUVC::queueRequest(Camera *camera, Request *request) { UVCCameraData *data = cameraData(camera); @@ -227,7 +284,11 @@ int PipelineHandlerUVC::queueRequest(Camera *camera, Request *request) return -ENOENT; } - int ret = data->video_->queueBuffer(buffer); + int ret = processControls(data, request); + if (ret < 0) + return ret; + + ret = data->video_->queueBuffer(buffer); if (ret < 0) return ret; @@ -247,24 +308,20 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) std::unique_ptr data = utils::make_unique(this); - /* Locate and open the default video node. */ + /* Locate and initialise the camera data with the default video node. */ for (MediaEntity *entity : media->entities()) { if (entity->flags() & MEDIA_ENT_FL_DEFAULT) { - data->video_ = new V4L2VideoDevice(entity); + if (data->init(entity)) + return false; break; } } - if (!data->video_) { + if (!data) { LOG(UVC, Error) << "Could not find a default video device"; - return false; + return -ENODEV; } - if (data->video_->open()) - return false; - - data->video_->bufferReady.connect(data.get(), &UVCCameraData::bufferReady); - /* Create and register the camera. */ std::set streams{ &data->stream_ }; std::shared_ptr camera = Camera::create(this, media->model(), streams); @@ -276,6 +333,53 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) return true; } +int UVCCameraData::init(MediaEntity *entity) +{ + int ret; + + /* Create and open the video device. */ + video_ = new V4L2VideoDevice(entity); + ret = video_->open(); + if (ret) + return ret; + + video_->bufferReady.connect(this, &UVCCameraData::bufferReady); + + /* Initialise the supported controls. */ + const V4L2ControlInfoMap &controls = video_->controls(); + for (const auto &ctrl : controls) { + unsigned int v4l2Id = ctrl.first; + const V4L2ControlInfo &info = ctrl.second; + ControlId id; + + switch (v4l2Id) { + case V4L2_CID_BRIGHTNESS: + id = Brightness; + break; + case V4L2_CID_CONTRAST: + id = Contrast; + break; + case V4L2_CID_SATURATION: + id = Saturation; + break; + case V4L2_CID_EXPOSURE_ABSOLUTE: + id = ManualExposure; + break; + case V4L2_CID_GAIN: + id = ManualGain; + break; + default: + continue; + } + + controlInfo_.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple(id, info.min(), info.max())); + } + + return 0; +} + void UVCCameraData::bufferReady(Buffer *buffer) { Request *request = queuedRequests_.front();