[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