[libcamera-devel] [PATCH] libcamera: pipelines: Add VIVID pipeline support

Nicolas Dufresne nicolas at ndufresne.ca
Fri Jun 19 18:35:49 CEST 2020


Le vendredi 19 juin 2020 à 17:19 +0100, Kieran Bingham a écrit :
> Hi Nicolas,
> 
> On 19/06/2020 16:34, Nicolas Dufresne wrote:
> > Le vendredi 19 juin 2020 à 13:02 +0100, Kieran Bingham a écrit :
> > > The VIVID driver supports more pixel formats and properties than the VIMC
> > > driver, and can provide extended testing for libcamera.
> > > 
> > > The VIMC pipeline handler is duplicated and simplified to support the
> > > VIVID device.
> > > 
> > > Unfortuantely, the VIVID device can not be handled by either of the
> > > generic UVC or Simple pipeline handlers.
> > 
> > Can you extend on that ?
> 
> I actually disagreed with myself in my latest reply (@13:14 in my timezone).
> 
> 
> > Perhaps an alternative route to supporting this however would be to make
> > the simple pipeline handler support pipelines which *don't* have a
> > sensor object... though the VIVID controls could be useful to support
> > directly.
> > 
> > Perhaps - inheriting the simple-pipeline handler should be possible, to
> > provide some 'device specific' adjustments for things like device
> > specific controls.
> 
> The simple pipeline expects to walk a media graph and find a sensor.
> VIVID doesn't expose a sensor, nor desire to. It's just a plain video
> device node.

Indeed, the simulated input is meant to be HDMI, SDI, RCA etc. Making these
sensor would be mis-leading. But it has a "webcam" mode too, but I think all
this control clashes too much.

> 
> Perhaps we could extend the simple pipeline handler to support devices
> which don't have a sensor ... or create a "simple-simple-pipeline
> handler" ? :-D
> 
> Equally - there could then be quite a lot of commonality between the UVC
> pipeline handler, though we kept that separate because of expected
> differences with UVC devices ... (in particular the controls for UVC
> have some specific variations already handled there).
> 
> So for testing with vivid, I took the easy option of creating a new
> pipeline for VIVID. But there is so much code duplication already, I'm
> sure we could find some reuse somewhere ...

Thanks, seems fair, often my question are just to make sure we leave a trace, so
in few years for now, if we want to merge it we know exactly why it was split in
the first place.

> 
> --
> Kieran
> 
> 
> > > Signed-off-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> > > ---
> > >  meson_options.txt                        |   2 +-
> > >  src/libcamera/pipeline/vivid/meson.build |   5 +
> > >  src/libcamera/pipeline/vivid/vivid.cpp   | 441 +++++++++++++++++++++++
> > >  3 files changed, 447 insertions(+), 1 deletion(-)
> > >  create mode 100644 src/libcamera/pipeline/vivid/meson.build
> > >  create mode 100644 src/libcamera/pipeline/vivid/vivid.cpp
> > > 
> > > diff --git a/meson_options.txt b/meson_options.txt
> > > index badace151bb6..dc4684df49b2 100644
> > > --- a/meson_options.txt
> > > +++ b/meson_options.txt
> > > @@ -16,7 +16,7 @@ option('gstreamer',
> > >  
> > >  option('pipelines',
> > >          type : 'array',
> > > -        choices : ['ipu3', 'raspberrypi', 'rkisp1', 'simple', 'uvcvideo',
> > > 'vimc'],
> > > +        choices : ['ipu3', 'raspberrypi', 'rkisp1', 'simple', 'uvcvideo',
> > > 'vimc', 'vivid'],
> > >          description : 'Select which pipeline handlers to include')
> > >  
> > >  option('test',
> > > diff --git a/src/libcamera/pipeline/vivid/meson.build
> > > b/src/libcamera/pipeline/vivid/meson.build
> > > new file mode 100644
> > > index 000000000000..086bb825387c
> > > --- /dev/null
> > > +++ b/src/libcamera/pipeline/vivid/meson.build
> > > @@ -0,0 +1,5 @@
> > > +# SPDX-License-Identifier: CC0-1.0
> > > +
> > > +libcamera_sources += files([
> > > +    'vivid.cpp',
> > > +])
> > > diff --git a/src/libcamera/pipeline/vivid/vivid.cpp
> > > b/src/libcamera/pipeline/vivid/vivid.cpp
> > > new file mode 100644
> > > index 000000000000..b811e33a0299
> > > --- /dev/null
> > > +++ b/src/libcamera/pipeline/vivid/vivid.cpp
> > > @@ -0,0 +1,441 @@
> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > > +/*
> > > + * Copyright (C) 2018, Google Inc.
> > > + *
> > > + * vivid.cpp - Pipeline handler for the vivid capture device
> > > + */
> > > +
> > > +#include <algorithm>
> > > +#include <iomanip>
> > > +#include <map>
> > > +#include <math.h>
> > > +#include <tuple>
> > > +
> > > +#include <linux/media-bus-format.h>
> > > +#include <linux/version.h>
> > > +
> > > +#include <libcamera/camera.h>
> > > +#include <libcamera/control_ids.h>
> > > +#include <libcamera/controls.h>
> > > +#include <libcamera/ipa/ipa_interface.h>
> > > +#include <libcamera/ipa/ipa_module_info.h>
> > > +#include <libcamera/request.h>
> > > +#include <libcamera/stream.h>
> > > +
> > > +#include "libcamera/internal/camera_sensor.h"
> > > +#include "libcamera/internal/device_enumerator.h"
> > > +#include "libcamera/internal/ipa_manager.h"
> > > +#include "libcamera/internal/log.h"
> > > +#include "libcamera/internal/media_device.h"
> > > +#include "libcamera/internal/pipeline_handler.h"
> > > +#include "libcamera/internal/utils.h"
> > > +#include "libcamera/internal/v4l2_controls.h"
> > > +#include "libcamera/internal/v4l2_subdevice.h"
> > > +#include "libcamera/internal/v4l2_videodevice.h"
> > > +
> > > +#define VIVID_CID_CUSTOM_BASE           (V4L2_CID_USER_BASE | 0xf000)
> > > +#define VIVID_CID_BUTTON                (VIVID_CID_CUSTOM_BASE + 0)
> > > +#define VIVID_CID_BOOLEAN               (VIVID_CID_CUSTOM_BASE + 1)
> > > +#define VIVID_CID_INTEGER               (VIVID_CID_CUSTOM_BASE + 2)
> > > +#define VIVID_CID_INTEGER64             (VIVID_CID_CUSTOM_BASE + 3)
> > > +#define VIVID_CID_MENU                  (VIVID_CID_CUSTOM_BASE + 4)
> > > +#define VIVID_CID_STRING                (VIVID_CID_CUSTOM_BASE + 5)
> > > +#define VIVID_CID_BITMASK               (VIVID_CID_CUSTOM_BASE + 6)
> > > +#define VIVID_CID_INTMENU               (VIVID_CID_CUSTOM_BASE + 7)
> > > +#define VIVID_CID_U32_ARRAY             (VIVID_CID_CUSTOM_BASE + 8)
> > > +#define VIVID_CID_U16_MATRIX            (VIVID_CID_CUSTOM_BASE + 9)
> > > +#define VIVID_CID_U8_4D_ARRAY           (VIVID_CID_CUSTOM_BASE + 10)
> > > +
> > > +#define VIVID_CID_VIVID_BASE            (0x00f00000 | 0xf000)
> > > +#define VIVID_CID_VIVID_CLASS           (0x00f00000 | 1)
> > > +#define VIVID_CID_TEST_PATTERN          (VIVID_CID_VIVID_BASE + 0)
> > > +#define VIVID_CID_OSD_TEXT_MODE         (VIVID_CID_VIVID_BASE + 1)
> > > +#define VIVID_CID_HOR_MOVEMENT          (VIVID_CID_VIVID_BASE + 2)
> > > +#define VIVID_CID_VERT_MOVEMENT         (VIVID_CID_VIVID_BASE + 3)
> > > +#define VIVID_CID_SHOW_BORDER           (VIVID_CID_VIVID_BASE + 4)
> > > +#define VIVID_CID_SHOW_SQUARE           (VIVID_CID_VIVID_BASE + 5)
> > > +#define VIVID_CID_INSERT_SAV            (VIVID_CID_VIVID_BASE + 6)
> > > +#define VIVID_CID_INSERT_EAV            (VIVID_CID_VIVID_BASE + 7)
> > > +#define VIVID_CID_VBI_CAP_INTERLACED    (VIVID_CID_VIVID_BASE + 8)
> > > +
> > > +#define VIVID_CID_HFLIP                 (VIVID_CID_VIVID_BASE + 20)
> > > +#define VIVID_CID_VFLIP                 (VIVID_CID_VIVID_BASE + 21)
> > > +#define VIVID_CID_STD_ASPECT_RATIO      (VIVID_CID_VIVID_BASE + 22)
> > > +#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO       (VIVID_CID_VIVID_BASE +
> > > 23)
> > > +#define VIVID_CID_TSTAMP_SRC            (VIVID_CID_VIVID_BASE + 24)
> > > +#define VIVID_CID_COLORSPACE            (VIVID_CID_VIVID_BASE + 25)
> > > +#define VIVID_CID_XFER_FUNC             (VIVID_CID_VIVID_BASE + 26)
> > > +#define VIVID_CID_YCBCR_ENC             (VIVID_CID_VIVID_BASE + 27)
> > > +#define VIVID_CID_QUANTIZATION          (VIVID_CID_VIVID_BASE + 28)
> > > +#define VIVID_CID_LIMITED_RGB_RANGE     (VIVID_CID_VIVID_BASE + 29)
> > > +#define VIVID_CID_ALPHA_MODE            (VIVID_CID_VIVID_BASE + 30)
> > > +#define VIVID_CID_HAS_CROP_CAP          (VIVID_CID_VIVID_BASE + 31)
> > > +#define VIVID_CID_HAS_COMPOSE_CAP       (VIVID_CID_VIVID_BASE + 32)
> > > +#define VIVID_CID_HAS_SCALER_CAP        (VIVID_CID_VIVID_BASE + 33)
> > > +#define VIVID_CID_HAS_CROP_OUT          (VIVID_CID_VIVID_BASE + 34)
> > > +#define VIVID_CID_HAS_COMPOSE_OUT       (VIVID_CID_VIVID_BASE + 35)
> > > +#define VIVID_CID_HAS_SCALER_OUT        (VIVID_CID_VIVID_BASE + 36)
> > > +#define VIVID_CID_LOOP_VIDEO            (VIVID_CID_VIVID_BASE + 37)
> > > +#define VIVID_CID_SEQ_WRAP              (VIVID_CID_VIVID_BASE + 38)
> > > +#define VIVID_CID_TIME_WRAP             (VIVID_CID_VIVID_BASE + 39)
> > > +#define VIVID_CID_MAX_EDID_BLOCKS       (VIVID_CID_VIVID_BASE + 40)
> > > +#define VIVID_CID_PERCENTAGE_FILL       (VIVID_CID_VIVID_BASE + 41)
> > > +#define VIVID_CID_REDUCED_FPS           (VIVID_CID_VIVID_BASE + 42)
> > > +#define VIVID_CID_HSV_ENC               (VIVID_CID_VIVID_BASE + 43)
> > > +#define VIVID_CID_DISPLAY_PRESENT       (VIVID_CID_VIVID_BASE + 44)
> > > +
> > > +#define VIVID_CID_STD_SIGNAL_MODE       (VIVID_CID_VIVID_BASE + 60)
> > > +#define VIVID_CID_STANDARD              (VIVID_CID_VIVID_BASE + 61)
> > > +#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE        (VIVID_CID_VIVID_BASE +
> > > 62)
> > > +#define VIVID_CID_DV_TIMINGS            (VIVID_CID_VIVID_BASE + 63)
> > > +#define VIVID_CID_PERC_DROPPED          (VIVID_CID_VIVID_BASE + 64)
> > > +#define VIVID_CID_DISCONNECT            (VIVID_CID_VIVID_BASE + 65)
> > > +#define VIVID_CID_DQBUF_ERROR           (VIVID_CID_VIVID_BASE + 66)
> > > +#define VIVID_CID_QUEUE_SETUP_ERROR     (VIVID_CID_VIVID_BASE + 67)
> > > +#define VIVID_CID_BUF_PREPARE_ERROR     (VIVID_CID_VIVID_BASE + 68)
> > > +#define VIVID_CID_START_STR_ERROR       (VIVID_CID_VIVID_BASE + 69)
> > > +#define VIVID_CID_QUEUE_ERROR           (VIVID_CID_VIVID_BASE + 70)
> > > +#define VIVID_CID_CLEAR_FB              (VIVID_CID_VIVID_BASE + 71)
> > > +#define VIVID_CID_REQ_VALIDATE_ERROR    (VIVID_CID_VIVID_BASE + 72)
> > > +
> > > +#define VIVID_CID_RADIO_SEEK_MODE       (VIVID_CID_VIVID_BASE + 90)
> > > +#define VIVID_CID_RADIO_SEEK_PROG_LIM   (VIVID_CID_VIVID_BASE + 91)
> > > +#define VIVID_CID_RADIO_RX_RDS_RBDS     (VIVID_CID_VIVID_BASE + 92)
> > > +#define VIVID_CID_RADIO_RX_RDS_BLOCKIO  (VIVID_CID_VIVID_BASE + 93)
> > > +
> > > +#define VIVID_CID_RADIO_TX_RDS_BLOCKIO  (VIVID_CID_VIVID_BASE + 94)
> > > +
> > > +#define VIVID_CID_SDR_CAP_FM_DEVIATION  (VIVID_CID_VIVID_BASE + 110)
> > > +
> > > +
> > > +namespace libcamera {
> > > +
> > > +LOG_DEFINE_CATEGORY(VIVID)
> > > +
> > > +class VividCameraData : public CameraData
> > > +{
> > > +public:
> > > +	VividCameraData(PipelineHandler *pipe, MediaDevice *media)
> > > +		: CameraData(pipe), media_(media), video_(nullptr)
> > > +	{
> > > +	}
> > > +
> > > +	~VividCameraData()
> > > +	{
> > > +		delete video_;
> > > +	}
> > > +
> > > +	int init();
> > > +	void bufferReady(FrameBuffer *buffer);
> > > +
> > > +	MediaDevice *media_;
> > > +	V4L2VideoDevice *video_;
> > > +	Stream stream_;
> > > +};
> > > +
> > > +class VividCameraConfiguration : public CameraConfiguration
> > > +{
> > > +public:
> > > +	VividCameraConfiguration();
> > > +
> > > +	Status validate() override;
> > > +};
> > > +
> > > +class PipelineHandlerVivid : public PipelineHandler
> > > +{
> > > +public:
> > > +	PipelineHandlerVivid(CameraManager *manager);
> > > +
> > > +	CameraConfiguration *generateConfiguration(Camera *camera,
> > > +						   const StreamRoles &roles)
> > > override;
> > > +	int configure(Camera *camera, CameraConfiguration *config) override;
> > > +
> > > +	int exportFrameBuffers(Camera *camera, Stream *stream,
> > > +			       std::vector<std::unique_ptr<FrameBuffer>>
> > > *buffers) override;
> > > +
> > > +	int start(Camera *camera) override;
> > > +	void stop(Camera *camera) override;
> > > +
> > > +	int queueRequestDevice(Camera *camera, Request *request) override;
> > > +
> > > +	bool match(DeviceEnumerator *enumerator) override;
> > > +
> > > +private:
> > > +	int processControls(VividCameraData *data, Request *request);
> > > +
> > > +	VividCameraData *cameraData(const Camera *camera)
> > > +	{
> > > +		return static_cast<VividCameraData *>(
> > > +			PipelineHandler::cameraData(camera));
> > > +	}
> > > +};
> > > +
> > > +VividCameraConfiguration::VividCameraConfiguration()
> > > +	: CameraConfiguration()
> > > +{
> > > +}
> > > +
> > > +CameraConfiguration::Status VividCameraConfiguration::validate()
> > > +{
> > > +	Status status = Valid;
> > > +
> > > +	if (config_.empty())
> > > +		return Invalid;
> > > +
> > > +	/* Cap the number of entries to the available streams. */
> > > +	if (config_.size() > 1) {
> > > +		config_.resize(1);
> > > +		status = Adjusted;
> > > +	}
> > > +
> > > +	StreamConfiguration &cfg = config_[0];
> > > +
> > > +	/* Adjust the pixel format. */
> > > +	const std::vector<libcamera::PixelFormat> formats =
> > > cfg.formats().pixelformats();
> > > +	if (std::find(formats.begin(), formats.end(), cfg.pixelFormat) ==
> > > formats.end()) {
> > > +		cfg.pixelFormat = cfg.formats().pixelformats()[0];
> > > +		LOG(VIVID, Debug) << "Adjusting format to " <<
> > > cfg.pixelFormat.toString();
> > > +		status = Adjusted;
> > > +	}
> > > +
> > > +	cfg.bufferCount = 4;
> > > +
> > > +	return status;
> > > +}
> > > +
> > > +PipelineHandlerVivid::PipelineHandlerVivid(CameraManager *manager)
> > > +	: PipelineHandler(manager)
> > > +{
> > > +}
> > > +
> > > +CameraConfiguration *PipelineHandlerVivid::generateConfiguration(Camera
> > > *camera,
> > > +								 const
> > > StreamRoles &roles)
> > > +{
> > > +	CameraConfiguration *config = new VividCameraConfiguration();
> > > +	VividCameraData *data = cameraData(camera);
> > > +
> > > +	if (roles.empty())
> > > +		return config;
> > > +
> > > +	std::map<V4L2PixelFormat, std::vector<SizeRange>> v4l2Formats =
> > > +		data->video_->formats();
> > > +	std::map<PixelFormat, std::vector<SizeRange>> deviceFormats;
> > > +	std::transform(v4l2Formats.begin(), v4l2Formats.end(),
> > > +		       std::inserter(deviceFormats, deviceFormats.begin()),
> > > +		       [&](const decltype(v4l2Formats)::value_type &format) {
> > > +			       return decltype(deviceFormats)::value_type{
> > > +				       format.first.toPixelFormat(),
> > > +				       format.second
> > > +			       };
> > > +		       });
> > > +
> > > +	StreamFormats formats(deviceFormats);
> > > +	StreamConfiguration cfg(formats);
> > > +
> > > +	cfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888);
> > > +	cfg.size = { 1280, 720 };
> > > +	cfg.bufferCount = 4;
> > > +
> > > +	config->addConfiguration(cfg);
> > > +
> > > +	config->validate();
> > > +
> > > +	return config;
> > > +}
> > > +
> > > +int PipelineHandlerVivid::configure(Camera *camera, CameraConfiguration
> > > *config)
> > > +{
> > > +	VividCameraData *data = cameraData(camera);
> > > +	StreamConfiguration &cfg = config->at(0);
> > > +	int ret;
> > > +
> > > +	V4L2DeviceFormat format = {};
> > > +	format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat);
> > > +	format.size = cfg.size;
> > > +
> > > +	ret = data->video_->setFormat(&format);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	if (format.size != cfg.size ||
> > > +	    format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat))
> > > +		return -EINVAL;
> > > +
> > > +	cfg.setStream(&data->stream_);
> > > +	cfg.stride = format.planes[0].bpl;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int PipelineHandlerVivid::exportFrameBuffers(Camera *camera, Stream
> > > *stream,
> > > +					     std::vector<std::unique_ptr<FrameBu
> > > ffer>> *buffers)
> > > +{
> > > +	VividCameraData *data = cameraData(camera);
> > > +	unsigned int count = stream->configuration().bufferCount;
> > > +
> > > +	return data->video_->exportBuffers(count, buffers);
> > > +}
> > > +
> > > +int PipelineHandlerVivid::start(Camera *camera)
> > > +{
> > > +	VividCameraData *data = cameraData(camera);
> > > +	unsigned int count = data->stream_.configuration().bufferCount;
> > > +
> > > +	int ret = data->video_->importBuffers(count);
> > > +	if (ret < 0)
> > > +		return ret;
> > > +
> > > +	ret = data->video_->streamOn();
> > > +	if (ret < 0) {
> > > +		data->ipa_->stop();
> > > +		data->video_->releaseBuffers();
> > > +		return ret;
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +void PipelineHandlerVivid::stop(Camera *camera)
> > > +{
> > > +	VividCameraData *data = cameraData(camera);
> > > +	data->video_->streamOff();
> > > +	data->video_->releaseBuffers();
> > > +}
> > > +
> > > +int PipelineHandlerVivid::processControls(VividCameraData *data, Request
> > > *request)
> > > +{
> > > +	ControlList controls(data->video_->controls());
> > > +
> > > +	for (auto it : request->controls()) {
> > > +		unsigned int id = it.first;
> > > +		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)
> > > +		LOG(VIVID, Debug)
> > > +			<< "Setting control " << utils::hex(ctrl.first)
> > > +			<< " to " << ctrl.second.toString();
> > > +
> > > +	int ret = data->video_->setControls(&controls);
> > > +	if (ret) {
> > > +		LOG(VIVID, Error) << "Failed to set controls: " << ret;
> > > +		return ret < 0 ? ret : -EINVAL;
> > > +	}
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +int PipelineHandlerVivid::queueRequestDevice(Camera *camera, Request
> > > *request)
> > > +{
> > > +	VividCameraData *data = cameraData(camera);
> > > +	FrameBuffer *buffer = request->findBuffer(&data->stream_);
> > > +	if (!buffer) {
> > > +		LOG(VIVID, Error)
> > > +			<< "Attempt to queue request with invalid stream";
> > > +
> > > +		return -ENOENT;
> > > +	}
> > > +
> > > +	int ret = processControls(data, request);
> > > +	if (ret < 0)
> > > +		return ret;
> > > +
> > > +	ret = data->video_->queueBuffer(buffer);
> > > +	if (ret < 0)
> > > +		return ret;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +bool PipelineHandlerVivid::match(DeviceEnumerator *enumerator)
> > > +{
> > > +	DeviceMatch dm("vivid");
> > > +	dm.add("vivid-000-vid-cap");
> > > +
> > > +	MediaDevice *media = acquireMediaDevice(enumerator, dm);
> > > +	if (!media)
> > > +		return false;
> > > +
> > > +	std::unique_ptr<VividCameraData> data =
> > > std::make_unique<VividCameraData>(this, media);
> > > +
> > > +	/* Locate and open the capture video node. */
> > > +	if (data->init())
> > > +		return false;
> > > +
> > > +	/* Create and register the camera. */
> > > +	std::set<Stream *> streams{ &data->stream_ };
> > > +	std::shared_ptr<Camera> camera = Camera::create(this, data->video_-
> > > > deviceName(), streams);
> > > +	registerCamera(std::move(camera), std::move(data));
> > > +
> > > +	return true;
> > > +}
> > > +
> > > +int VividCameraData::init()
> > > +{
> > > +	video_ = new V4L2VideoDevice(media_->getEntityByName("vivid-000-vid-
> > > cap"));
> > > +	if (video_->open())
> > > +		return -ENODEV;
> > > +
> > > +	video_->bufferReady.connect(this, &VividCameraData::bufferReady);
> > > +
> > > +	/* Initialise the supported controls. */
> > > +	const ControlInfoMap &controls = video_->controls();
> > > +	ControlInfoMap::Map ctrls;
> > > +
> > > +	for (const auto &ctrl : controls) {
> > > +		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;
> > > +		}
> > > +
> > > +		ctrls.emplace(id, info);
> > > +	}
> > > +
> > > +	controlInfo_ = std::move(ctrls);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +void VividCameraData::bufferReady(FrameBuffer *buffer)
> > > +{
> > > +	Request *request = buffer->request();
> > > +
> > > +	pipe_->completeBuffer(camera_, request, buffer);
> > > +	pipe_->completeRequest(camera_, request);
> > > +}
> > > +
> > > +REGISTER_PIPELINE_HANDLER(PipelineHandlerVivid);
> > > +
> > > +} /* namespace libcamera */



More information about the libcamera-devel mailing list