[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