[libcamera-devel] [PATCH] libcamera: pipelines: Add VIVID pipeline support
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Tue Jun 23 00:29:07 CEST 2020
Hi Kieran,
On Mon, Jun 22, 2020 at 10:47:39AM +0100, Kieran Bingham wrote:
> On 22/06/2020 02:45, Laurent Pinchart wrote:
> > On Fri, Jun 19, 2020 at 05:19:55PM +0100, Kieran Bingham wrote:
> >> 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.
> >>
> >> 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 ...
> >
> > Thank you for posting this patch. I think it's useful, as vimc currently
> > has a fairly limited set of features compared to vivid. In particular,
> > the lack of YUV format support in vimc (when configuring the pipeline
> > with a Bayer camera sensor as a source) limits our ability to test any
> > use case that requires YUV without real hardware.
>
> The extra format support really was the driving factor here, and vivid
> has much greater coverage for V4L2, so I suspect it might have
> further/different benefits for testing the v4l2 compatibility layers ...
>
> Which is of course why it got posted, because Paul had asked there, and
> I had the vivid handler ready to hand.
>
> > Ideally, I would like vimc to gain support for these features, and avoid
> > adding another pipeline handler for vivid that would duplicate code. We
> > can discuss how to minimize code duplication, either with the simple
> > pipeline handler or the UVC pipeline handler, but the effort to add YUV
> > support in vimc seems fairly low to me, possibly even lower than
> > developing vivid support in libcamera with reduced code duplication. I'm
>
> I don't yet know what's involved in adding extra format support to VIMC,
> but weren't Collabora also looking at such a topic ?
We need to synchronize with Helen and Shuah here.
> > curious to know your opinion on long-term support for vivid in
> > libcamera, compared to enhancing the vimc driver.
> >
> > We could merge this pipeline handler as-is and deal with code sharing
> > later (or possibly even drop it later when vimc support will be better),
>
> I think that's an important consideration. - We can 'drop' it later too
> if required test functionality becomes available elsewhere...
>
> > but we also need to consider that every new pipeline handler increases
> > the maintenance effort, and makes changes to the pipeline handler API
> > more difficult. We need to consider the pros and cons.
>
> Of course, that's why initially I hadn't posted it when /I/ needed it.
> But upon the third send out - I figured that was enough motivation to
> include the mailing-list.
>
> > Regarding code sharing, without having studied the question in details,
> > I feel that the UVC pipeline handler would be a better target, as vimc
> > is media controller-centric, while UVC and vivid are video node-centric.
>
> Yes, there are definitely similarities with UVC, but there are likely
> differences in controls ... but I suspect for VIVID we don't /actually/
> care about those differences anyway.
>
> > I'm even considering supporting vimc with the simple pipeline handler
> > instead of a dedicated pipeline handler, but that would likely require
>
> That's interesting, but how would you handle having the 'test vimc' IPA?
> I suspect VIMC would end up staying external unless perhaps the simple
> pipeline handler would also support IPA matching?
I foresee a need for IPAs for the simple pipeline handler, coupled with
GPU processing of Bayer data (a poor man's ISP in a way). The vimc IPA
could then be integrated with whatever mechanism we implement in the
simple pipeline handler to load IPAs.
> > changes in both the simple pipeline handler and the vimc driver (most
> > notably the vimc scaler, which hardcodes a downscaling ratio of 3).
>
> Yes, that's a painful arbitrary limitation.
>
> Overall, I don't particularly mind too much if this gets integrated or not.
>
> I think it can provide some help for development of libcamera in virtual
> systems which, while we have low hardware support might be more beneficial.
>
> It might be an easy way to provide testing of things like 'multiple
> cameras' on a single pipeline handler too - as you can easily have extra
> capture devices with fairly arbitrary sizes for testing.
>
> Without wide format coverage in VIMC it could help with other plumbing
> aspects too - but equally even if we do integrate it - I could easily
> see a point in the future where it becomes simpler to remove it.
>
> >>>> 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 */
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list