[libcamera-devel] [PATCH 04/14] libcamera: Declare generic size and format converter interface

Jacopo Mondi jacopo at jmondi.org
Wed Sep 14 12:46:04 CEST 2022


Hi Xavier
  I would drop "size and format" and use "Converter" in the subject
title.

On Thu, Sep 08, 2022 at 08:48:40PM +0200, Xavier Roumegue via libcamera-devel wrote:
> Declare a converter Abstract Base Class intented to provide generic
> interfaces to hardware offering size and format conversion services on
> streams. This is mainly based on the public interfaces of the current
> converter class implementation found in the simple pipeline handler.
>
> The main change is the introduction of load_configuration() method which
> can be used by the concrete implementation to load hardware specific
> runtime parameters defined by the application.
>
> Signed-off-by: Xavier Roumegue <xavier.roumegue at oss.nxp.com>
> ---
>  include/libcamera/internal/converter.h | 101 ++++++++++++++++++++++++
>  include/libcamera/internal/meson.build |   1 +
>  src/libcamera/converter.cpp            | 102 +++++++++++++++++++++++++
>  src/libcamera/meson.build              |   1 +
>  4 files changed, 205 insertions(+)
>  create mode 100644 include/libcamera/internal/converter.h
>  create mode 100644 src/libcamera/converter.cpp
>
> diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h
> new file mode 100644
> index 00000000..e2237c57
> --- /dev/null
> +++ b/include/libcamera/internal/converter.h
> @@ -0,0 +1,101 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Laurent Pinchart
> + * Copyright 2022 NXP
> + *
> + * converter.h - Generic stream converter infrastructure
> + */
> +
> +#pragma once
> +
> +#include <functional>

I might have missed what is functional included for

> +#include <map>
> +#include <memory>
> +#include <string>
> +#include <tuple>
> +#include <vector>
> +
> +#include <libcamera/base/class.h>
> +#include <libcamera/base/signal.h>
> +
> +#include <libcamera/geometry.h>
> +#include <libcamera/pixel_format.h>
> +
> +namespace libcamera {
> +
> +class FrameBuffer;
> +class MediaDevice;
> +class Size;
> +class SizeRange;
> +struct StreamConfiguration;
> +
> +class Converter
> +{
> +public:
> +	Converter(MediaDevice *media);
> +	virtual ~Converter();

Empty line maybe ?

> +	virtual int loadConfiguration(const std::string &filename) = 0;
> +
> +	virtual bool isValid() const = 0;
> +
> +	virtual std::vector<PixelFormat> formats(PixelFormat input) = 0;
> +	virtual SizeRange sizes(const Size &input) = 0;
> +
> +	virtual std::tuple<unsigned int, unsigned int>
> +	strideAndFrameSize(const PixelFormat &pixelFormat, const Size &size) = 0;
> +
> +	virtual int configure(const StreamConfiguration &inputCfg,
> +			      const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfg) = 0;
> +	virtual int exportBuffers(unsigned int ouput, unsigned int count,
> +				  std::vector<std::unique_ptr<FrameBuffer>> *buffers) = 0;
> +
> +	virtual int start() = 0;
> +	virtual void stop() = 0;
> +
> +	virtual int queueBuffers(FrameBuffer *input,
> +				 const std::map<unsigned int, FrameBuffer *> &outputs) = 0;
> +
> +	std::string deviceNode_;
> +	Signal<FrameBuffer *> inputBufferReady;
> +	Signal<FrameBuffer *> outputBufferReady;
> +};
> +
> +class ConverterFactory
> +{
> +public:
> +	ConverterFactory(const std::string name);
> +	virtual ~ConverterFactory() = default;
> +
> +	static std::unique_ptr<Converter> create(MediaDevice *media);
> +
> +	static void registerType(ConverterFactory *factory);
> +	static std::vector<ConverterFactory *> &factories();
> +	static std::vector<std::string> names();
> +
> +protected:
> +	virtual Converter *createInstance(MediaDevice *media) = 0;
> +	virtual const std::vector<std::string> aliases() const = 0;
> +
> +private:
> +	LIBCAMERA_DISABLE_COPY_AND_MOVE(ConverterFactory)
> +
> +	std::string name_;
> +};
> +
> +#define REGISTER_CONVERTER(name, converter, ...)                            \
> +	class converter##Factory final : public ConverterFactory                \
> +	{                                                                       \
> +	public:                                                                 \
> +		converter##Factory() : ConverterFactory(name) {}                    \
> +                                                                            \
> +	private:                                                                \
> +		Converter *createInstance(MediaDevice *media)                       \
> +		{                                                                   \
> +			return new converter(media);                                    \
> +		}                                                                   \
> +		std::vector<std::string> aliases_ = { __VA_ARGS__ };                \
> +		const std::vector<std::string> aliases() const { return aliases_; } \
> +	};                                                                      \
> +	static converter##Factory global_##converter##Factory;
> +
> +} /* namespace libcamera */
> diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
> index 7a780d48..8f50d755 100644
> --- a/include/libcamera/internal/meson.build
> +++ b/include/libcamera/internal/meson.build
> @@ -19,6 +19,7 @@ libcamera_internal_headers = files([
>      'camera_sensor_properties.h',
>      'control_serializer.h',
>      'control_validator.h',
> +    'converter.h',
>      'delayed_controls.h',
>      'device_enumerator.h',
>      'device_enumerator_sysfs.h',
> diff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp
> new file mode 100644
> index 00000000..89a594d1
> --- /dev/null
> +++ b/src/libcamera/converter.cpp
> @@ -0,0 +1,102 @@
> +

Rogue empty line

> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright 2022 NXP
> + *
> + * converter.cpp - Generic Format converter interface
> + */
> +
> +#include <algorithm>
> +
> +#include <libcamera/base/log.h>
> +
> +#include "libcamera/internal/converter.h"
> +#include "libcamera/internal/media_device.h"
> +
> +namespace libcamera {
> +
> +LOG_DEFINE_CATEGORY(Converter)
> +
> +Converter::Converter(MediaDevice *media)
> +{
> +	const std::vector<MediaEntity *> &entities = media->entities();
> +	auto it = std::find_if(entities.begin(), entities.end(),
> +			       [](MediaEntity *entity) {
> +				       return entity->function() == MEDIA_ENT_F_IO_V4L;
> +			       });
> +	if (it == entities.end())
> +		return;

Should we complain loud and set some state variable that can be
inspected by the isValid() function already ?

> +
> +	deviceNode_ = (*it)->deviceNode();

I'm not sure storing a string here is any useful if not fo debugging
purposes. What if you store a pointer to the entity instead, so
derived classes can use the static fromMediaEntity() function (which
probably have to be added to the M2M device) to open the device node ?

> +}
> +
> +Converter::~Converter()
> +{
> +}
> +
> +ConverterFactory::ConverterFactory(const std::string name)
> +	: name_(name)
> +{
> +	registerType(this);
> +}
> +
> +std::unique_ptr<Converter> ConverterFactory::create(MediaDevice *media)
> +{
> +	std::vector<ConverterFactory *> &factories =
> +		ConverterFactory::factories();

Oh, this is different from the other favtories we have.
The usage here is:

        ConverterFavtory::create()
                for (factory: factories())
                        factory->create();

While other factories (looking at the pipeline handler factory) have a
static method to retrieve factories, and then call create() on them.

My understanding is that this shouldn't change much in regard to the
link order protection realized by declaring factories_ inside the
factories() function, just pointing it out to see if someone else see
an issue here.

> +
> +	for (ConverterFactory *factory : factories) {
> +		std::vector<std::string> aliases = factory->aliases();
> +		auto it = std::find(aliases.begin(), aliases.end(), media->driver());

How do you envision aliases to be used ? I mean, do you expect a
Converter instance to handle different devices ? Probably yes, as a
generic M2M converter will follow in the series and could handle
multiple devices...

> +
> +		if (it == aliases.end() && media->driver() != factory->name_)

what is "media->driver() != factory->name_)" for ? Shouldn't the media
driver name be part of aliases only ?

> +			continue;
> +
> +		LOG(Converter, Debug)
> +			<< "Creating converter from "
> +			<< factory->name_ << " factory with "
> +			<< (it == aliases.end() ? "no" : media->driver()) << " alias.";

How long is this message ? Can it be shortened or the factory name
here is relevant ?

> +
> +		Converter *converter = factory->createInstance(media);
> +		return std::unique_ptr<Converter>(converter);
> +	}
> +
> +	return nullptr;
> +}
> +
> +void ConverterFactory::registerType(ConverterFactory *factory)
> +{
> +	std::vector<ConverterFactory *> &factories =
> +		ConverterFactory::factories();
> +
> +	factories.push_back(factory);
> +}
> +
> +std::vector<std::string> ConverterFactory::names()
> +{
> +	std::vector<std::string> list;
> +
> +	std::vector<ConverterFactory *> &factories =
> +		ConverterFactory::factories();
> +
> +	for (ConverterFactory *factory : factories) {
> +		list.push_back(factory->name_);
> +		for (auto alias : factory->aliases())
> +			list.push_back(alias);
> +	}
> +
> +	return list;
> +}
> +
> +std::vector<ConverterFactory *> &ConverterFactory::factories()
> +{
> +	/*
> +	 * The static factories map is defined inside the function to ensure
> +	 * it gets initialized on first use, without any dependency on link
> +	 * order.
> +	 */
> +	static std::vector<ConverterFactory *> factories;
> +	return factories;
> +}
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 63b47b17..a261d4b4 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -13,6 +13,7 @@ libcamera_sources = files([
>      'controls.cpp',
>      'control_serializer.cpp',
>      'control_validator.cpp',
> +    'converter.cpp',
>      'delayed_controls.cpp',
>      'device_enumerator.cpp',
>      'device_enumerator_sysfs.cpp',
> --
> 2.37.3
>


More information about the libcamera-devel mailing list