[libcamera-devel,v2,3/6] libcamera: Add V4L2Controls

Message ID 20190610164052.30741-4-jacopo@jmondi.org
State Superseded
Headers show
Series
  • Add support for V4L2 Controls
Related show

Commit Message

Jacopo Mondi June 10, 2019, 4:40 p.m. UTC
Add Libcamera V4L2 control support, implemented using the V4L2 Extended
Control APIs. This patch defines the types used to define and manage controls.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 src/libcamera/include/v4l2_controls.h | 210 +++++++++
 src/libcamera/meson.build             |   1 +
 src/libcamera/v4l2_controls.cpp       | 632 ++++++++++++++++++++++++++
 3 files changed, 843 insertions(+)
 create mode 100644 src/libcamera/include/v4l2_controls.h
 create mode 100644 src/libcamera/v4l2_controls.cpp

Comments

Laurent Pinchart June 11, 2019, 11:41 a.m. UTC | #1
Hi Jacopo,

Thank you for the patch.

On Mon, Jun 10, 2019 at 06:40:49PM +0200, Jacopo Mondi wrote:
> Add Libcamera V4L2 control support, implemented using the V4L2 Extended
> Control APIs. This patch defines the types used to define and manage controls.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  src/libcamera/include/v4l2_controls.h | 210 +++++++++
>  src/libcamera/meson.build             |   1 +
>  src/libcamera/v4l2_controls.cpp       | 632 ++++++++++++++++++++++++++
>  3 files changed, 843 insertions(+)
>  create mode 100644 src/libcamera/include/v4l2_controls.h
>  create mode 100644 src/libcamera/v4l2_controls.cpp
> 
> diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> new file mode 100644
> index 000000000000..bca5ccc29de3
> --- /dev/null
> +++ b/src/libcamera/include/v4l2_controls.h
> @@ -0,0 +1,210 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * v4l2_controls.h - V4L2 Extended Control Support
> + */
> +
> +#ifndef __LIBCAMERA_V4L2_CONTROLS_H__
> +#define __LIBCAMERA_V4L2_CONTROLS_H__
> +
> +#include <cstring>
> +#include <string>
> +#include <vector>
> +
> +#include <stdint.h>
> +
> +#include <linux/v4l2-controls.h>
> +#include <linux/videodev2.h>
> +
> +namespace libcamera {
> +
> +class V4L2Control
> +{
> +public:
> +	virtual ~V4L2Control()
> +	{
> +	}
> +
> +	unsigned int id() { return id_; }
> +	unsigned int size() { return size_; }
> +	enum v4l2_ctrl_type type() const { return type_; }
> +
> +protected:
> +	V4L2Control(unsigned int id, unsigned int size,
> +		    enum v4l2_ctrl_type type)
> +		: id_(id), size_(size), type_(type)
> +	{
> +	}
> +
> +private:
> +	unsigned int id_;
> +	unsigned int size_;
> +	enum v4l2_ctrl_type type_;
> +};
> +
> +template<typename T>
> +class V4L2ControlValue : public V4L2Control
> +{
> +public:
> +	T value() const { return value_; }
> +	T *mem() const { return mem_; }
> +
> +protected:
> +	V4L2ControlValue(unsigned int id, unsigned int size,
> +			 enum v4l2_ctrl_type type, T value)
> +		: V4L2Control(id, size, type)
> +	{
> +		value_ = value;
> +		mem_ = nullptr;
> +	}
> +
> +	V4L2ControlValue(unsigned int id, unsigned int size,
> +			 enum v4l2_ctrl_type type, T *value)
> +		: V4L2Control(id, size, type)
> +	{
> +		value_ = 0;
> +		mem_ = static_cast<T *>(new T[size]);
> +		memcpy(mem_, value, size);
> +	}
> +
> +	~V4L2ControlValue()
> +	{
> +		delete[] mem_;
> +	}
> +
> +private:
> +	T value_;
> +	T *mem_;
> +};
> +
> +class V4L2IntControl : public V4L2ControlValue<int32_t>
> +{
> +private:
> +	friend class V4L2Controls;
> +
> +	V4L2IntControl(unsigned int id, int32_t value)
> +		: V4L2ControlValue<int32_t>(id, sizeof(int32_t),
> +					    V4L2_CTRL_TYPE_INTEGER, value)
> +	{
> +	}
> +};
> +
> +class V4L2Int64Control : public V4L2ControlValue<int64_t>
> +{
> +private:
> +	friend class V4L2Controls;
> +
> +	V4L2Int64Control(unsigned int id, int64_t value)
> +		: V4L2ControlValue<int64_t>(id, sizeof(int64_t),
> +					    V4L2_CTRL_TYPE_INTEGER64, value)
> +	{
> +	}
> +};
> +
> +class V4L2BoolControl : public V4L2ControlValue<bool>
> +{
> +private:
> +	friend class V4L2Controls;
> +
> +	V4L2BoolControl(unsigned int id, bool value)
> +		: V4L2ControlValue<bool>(id, sizeof(bool),
> +					 V4L2_CTRL_TYPE_BOOLEAN, value)
> +	{
> +	}
> +};
> +
> +class V4L2StringControl : public V4L2ControlValue<std::string>
> +{
> +private:
> +	friend class V4L2Controls;
> +
> +	V4L2StringControl(unsigned int id, std::string value)
> +		: V4L2ControlValue<std::string>(id, value.length(),
> +						V4L2_CTRL_TYPE_STRING, value)
> +	{
> +	}
> +};
> +
> +class V4L2U8Control : public V4L2ControlValue<uint8_t>
> +{
> +private:
> +	friend class V4L2Controls;
> +
> +	V4L2U8Control(unsigned int id, unsigned int size, uint8_t *mem)
> +		: V4L2ControlValue<uint8_t>(id, size, V4L2_CTRL_TYPE_U8, mem)
> +	{
> +	}
> +};
> +
> +class V4L2U16Control : public V4L2ControlValue<uint16_t>
> +{
> +private:
> +	friend class V4L2Controls;
> +
> +	V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
> +		: V4L2ControlValue<uint16_t>(id, size, V4L2_CTRL_TYPE_U16, mem)
> +	{
> +	}
> +};
> +
> +class V4L2U32Control : public V4L2ControlValue<uint32_t>
> +{
> +private:
> +	friend class V4L2Controls;
> +
> +	V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
> +		: V4L2ControlValue<uint32_t>(id, size, V4L2_CTRL_TYPE_U32, mem)
> +	{
> +	}
> +};
> +
> +class V4L2Controls {
> +public:
> +	~V4L2Controls()
> +	{
> +		clear();
> +	}
> +
> +	using iterator = std::vector<V4L2Control *>::iterator;
> +	using const_iterator = std::vector<V4L2Control *>::const_iterator;
> +
> +	iterator begin() { return controls_.begin(); }
> +	const_iterator begin() const { return controls_.begin(); }
> +	iterator end() { return controls_.end(); }
> +	const_iterator end() const { return controls_.end(); }
> +
> +	size_t size() { return controls_.size(); }
> +	void clear();

I would move clear() after empty(), to group all the methods the merely
delegate to std::vector together, followed by the custom methods.

> +
> +	V4L2Control *operator[](unsigned int index) const
> +	{
> +		return controls_[index];
> +	}
> +
> +	bool empty() const { return controls_.size() == 0; }

	return controls_.empty();

> +
> +	void set(unsigned int id, unsigned int value);
> +	void set(unsigned int id, int32_t value);
> +	void set(unsigned int id, int64_t value);

This will be quite error-prone, especially the first two variants. Users
of the class will have to be very careful about the type passed to the
function, and C++ type deduction rules are not easy to keep in mind.

> +	void set(unsigned int id, bool value);
> +	void set(unsigned int id, std::string value);
> +	void set(unsigned int id, size_t size, uint8_t *value);
> +	void set(unsigned int id, size_t size, uint16_t *value);
> +	void set(unsigned int id, size_t size, uint32_t *value);
> +
> +	int32_t getInt(unsigned int id);
> +	int64_t getInt64(unsigned int id);
> +	bool getBool(unsigned int id);
> +	std::string getString(unsigned int id);
> +	uint8_t *getU8(unsigned int id);
> +	uint16_t *getU16(unsigned int id);
> +	uint32_t *getU32(unsigned int id);
> +
> +private:
> +	std::vector<V4L2Control *> controls_;

I still dislike storing pointers here, as it means individual
allocation and free. If you add the fact that array control values also
allocate memory internally, that's quite a bit of overhead. However, now
that the details are hidden from the user, it becomes more of an
implementation issue, which can evolve without impacting the users.

> +};
> +
> +}; /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_V4L2_CONTROLS_H__ */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 6d858a22531e..fa1fbcb5faf5 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -22,6 +22,7 @@ libcamera_sources = files([
>      'timer.cpp',
>      'utils.cpp',
>      'v4l2_base.cpp',
> +    'v4l2_controls.cpp',
>      'v4l2_device.cpp',
>      'v4l2_subdevice.cpp',
>  ])
> diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> new file mode 100644
> index 000000000000..bd68d07f37bf
> --- /dev/null
> +++ b/src/libcamera/v4l2_controls.cpp
> @@ -0,0 +1,632 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * v4l2_controls.cpp - V4L2 Extended Control Support
> + */
> +
> +#include "v4l2_controls.h"
> +
> +/**
> + * \file v4l2_controls.h
> + * \brief Support for V4L2 Controls using the V4L2 Extended Controls APIs.
> + *
> + * The V4L2 defined "Control API" allows application to inspect and modify set
> + * of configurable parameters on the video device or subdevice of interest. The
> + * nature of the parameters an application could modify using the control
> + * framework depends on what the driver implements support for, and on the
> + * characteristics of the underlying hardware platform. Generally controls are
> + * used to modify user visible settings, such as the image brightness and
> + * exposure time, or non-standard parameters which cannot be controlled through
> + * the V4L2 format negotiation API.
> + *
> + * Controls are identified by a numerical id, defined by the V4L2 kernel headers
> + * and have an associated type and class. Each control has a 'value', which is
> + * the data that can be modified with a 'V4L2Base::setControl()' operation call
> + * or retrieved with a 'V4L2Base::getControl()' one.
> + *
> + * A control class defines the control purpose while its type (along with the
> + * control's flags) defines the type of the control's value content. Controls
> + * might transport a single data value stored in variable inside the control, or
> + * they might as well deal with more complex data types, such as arrays of
> + * matrices, stored in a contiguous memory locations associated with the control
> + * and called 'the payload'. The content have to be opportunely copied into the
> + * application memory when retrieving a control's value and provided to the V4L2
> + * device when setting it.
> + *
> + * Libcamera supports control using the V4L2 'Extended Control' framework, which
> + * allows easier handling of controls with payloads of arbitrary sizes.
> + *
> + * The Libcamera V4L2 Controls framework operates on lists of controls, wrapped
> + * by the V4L2Controls class, to match the V4L2 extended controls framework.
> + * The interface to set and get control is implemented by the V4L2Base class,
> + * while this file only provides the data type definitions.
> + *
> + * The Libcamera V4L2 control framework define a base class
> + * V4L2Control that contains the fields common to all controls, regardless of
> + * their type, such as the  control's id, its type and the expected control's
> + * value data size. The V4L2Control class is not meant to be instantiated
> + * directly, but is instead used as placeholder to store controls inside the
> + * publicly constructible V4L2Controls class.
> + *
> + * A parametric derived class V4L2ControlValue stores the control's value and
> + * provide accessors to the data values for controls with no payload, or to the
> + * memory area that contains the control's data payload. These classes are not
> + * intended to be directly used and cannot be constructed, but are used instead
> + * to define specialized derived classes which provide accessors to the
> + * control's data values.
> + *
> + * In order to set and get controls, user of the Libcamera V4L2 control
> + * framework should operate on instances of the V4L2Controls class, iterating
> + * on the V4L2Controls it contains, and use the V4L2Controls::set() and
> + * V4L2Controls::get() methods to set or access the control's data
> + * content.
> + *
> + * \todo Support setting controls with data payload.
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class V4L2Control
> + * \brief Base class for V4L2 Controls
> + *
> + * The V4L2Control base class is the base class that contains the fields common
> + * to all controls (id, type and size).
> + *
> + * This class is not meant to be instantiated directly, but is instead used as a
> + * place holder to store controls in arrays or other containers. User of the
> + * libcamera V4L2 control framework should access the controls content by
> + * using accessors provided by the V4L2Controls class.
> + */
> +
> +/**
> + * \fn V4L2Control::V4L2Control
> + * \brief Construct a V4L2Control instance
> + * \param id The control's id
> + * \param size The control's data size
> + * \param type The control's type
> + */
> +
> +/**
> + * \fn V4L2Control::id()
> + * \brief Retrieve the control's id
> + *
> + * Retrieve the control's numerical id value as defined by the V4L2
> + * specification.
> + *
> + * \return The control's id
> + */
> +
> +/**
> + * \fn V4L2Control::size()
> + * \brief Retrieve the control's data value size in bytes
> + *
> + * \todo Better define the value of size() for controls with payload data.
> + *
> + * \return The control's size
> + */
> +
> +/**
> + * \fn V4L2Control::type()
> + * \brief Retrieve the control's type
> + *
> + * Retrieve the control's type as defined by the V4L2 specification.
> + *
> + * \return The control's type
> + */
> +
> +/**
> + * \class V4L2ControlValue
> + * \brief Template base class that represent values of a V4L2 control
> + *
> + * The V4L2ControlValue template base class represents a V4L2 control with
> + * its different value types.
> + *
> + * It provides two operations to access the control's value or the pointer
> + * to the memory location that contains to the control's value data payload.
> + */
> +
> +/**
> + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T value)
> + * \brief Contruct a V4L2ControlValue with a parametric value
> + * \param id The control's id
> + * \param size The control's size
> + * \param type The control's type
> + * \param value The control's value
> + */
> +
> +/**
> + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T* value)
> + * \brief Contruct a V4L2ControlValue with a pointer to a data payload
> + * \param id The control's id
> + * \param size The control's size
> + * \param type The control's type
> + * \param value The pointer to the control's data payload
> + */
> +
> +/**
> + * \fn V4L2ControlValue::~V4L2ControlValue
> + * \brief Release the memory reserved for the control's data payload, if any
> + */
> +
> +/**
> + * \fn V4L2ControlValue::value()
> + * \brief Retrieve the control's value
> + *
> + * Retrieve the control's value. Valid only for controls with no payload.
> + */
> +
> +/**
> + * \fn V4L2ControlValue::mem()
> + * \brief Retrieve a pointer to the memory location of the control's data
> + *
> + * Retrieve a pointer to the memory location that contains the control's data
> + * payload. Valid only for controls with data payload.
> + */
> +
> +/**
> + * \class V4L2IntControl
> + * \brief Specialized V4L2Control class that handles controls of
> + *        V4L2_CTRL_TYPE_INTEGER type.
> + *
> + * Access to the control's data value by using the value() operation is
> + * restricted to the proxy V4L2Controls class.
> + */
> +
> +/**
> + * \fn V4L2IntControl::V4L2IntControl()
> + * \brief Construct a V4L2Control that contains an int value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +
> +/**
> + * \class V4L2Int64Control
> + * \brief Specialized V4L2Control class that handles controls of
> + *        V4L2_CTRL_TYPE_INTEGER64 type.
> + *
> + * Access to the control's data value by using the value() operation is
> + * restricted to the proxy V4L2Controls class.
> + */
> +
> +/**
> + * \fn V4L2Int64Control::V4L2Int64Control()
> + * \brief Construct a V4L2Control that contains an int64 value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +
> +/**
> + * \class V4L2BoolControl
> + * \brief Specialized V4L2Control class that handles controls of
> + *        V4L2_CTRL_TYPE_BOOLEAN type.
> + *
> + *
> + * Access to the control's data value by using the value() operation is
> + * restricted to the proxy V4L2Controls class.
> + */
> +
> +/**
> + * \fn V4L2BoolControl::V4L2BoolControl()
> + * \brief Construct a V4L2Control that contains a boolean value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +
> +/**
> + * \class V4L2StringControl
> + * \brief Specialized V4L2Control class that handles controls of
> + *        V4L2_CTRL_TYPE_STRING type.
> + *
> + * Access to the control's data value by using the value() operation is
> + * restricted to the proxy V4L2Controls class.
> + */
> +
> +/**
> + * \fn V4L2StringControl::V4L2StringControl()
> + * \brief Construct a V4L2Control that contains a string value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +
> +/**
> + * \class V4L2U8Control
> + * \brief Specialized V4L2Control class that handles controls with payload of
> + *        V4L2_CTRL_TYPE_U8 type.
> + *
> + * Access to the control's mem() operation is reserved to the V4L2Controls
> + * proxy class. The size of the payload data can be retrieved with the size()
> + * operation.
> + */
> +
> +/**
> + * \fn V4L2U8Control::V4L2U8Control()
> + * \brief Construct a V4L2Control with payload of uin8_t data
> + * \param id The control's id
> + * \param size The size in bytes of the payload content
> + * \param mem Pointer to the memory location of the payload content
> + *
> + * Memory is reserved in the newly created instance to hold the data payload
> + * and the data content is copied there. The reserved memory is then freed when
> + * the Control is destroyed. The memory where the control's payload was copied
> + * from should be released by the caller.
> + */
> +
> +/**
> + * \class V4L2U16Control
> + * \brief Specialized V4L2Control class that handles controls with payload of
> + *        V4L2_CTRL_TYPE_U16 type.
> + *
> + * Access to the control's mem() operation is reserved to the V4L2Controls
> + * proxy class. The size of the payload data can be retrieved with the size()
> + * operation.
> + */
> +
> +/**
> + * \fn V4L2U16Control::V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
> + * \brief Construct a V4L2Control with payload of uin16_t data
> + * \param id The control's id
> + * \param size The size in bytes of the payload content
> + * \param mem Pointer to the memory location of the payload content
> + *
> + * Memory is reserved in the newly created instance to hold the data payload
> + * and the data content is copied there. The reserved memory is then freed when
> + * the Control is destroyed. The memory where the control's payload was copied
> + * from should be released by the caller.
> + */
> +
> +/**
> + * \class V4L2U32Control
> + * \brief Specialized V4L2Control class that handles controls with payload of
> + *        V4L2_CTRL_TYPE_U32 type.
> + *
> + * Access to the control's mem() operation is reserved to the V4L2Controls
> + * proxy class. The size of the payload data can be retrieved with the size()
> + * operation.
> + */
> +
> +/**
> + * \fn V4L2U32Control::V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
> + * \brief Construct a V4L2Control with payload of uin32_t data
> + * \param id The control's id
> + * \param size The size in bytes of the payload content
> + * \param mem Pointer to the memory location of the payload content
> + *
> + * Memory is reserved in the newly created instance to hold the data payload
> + * and the data content is copied there. The reserved memory is then freed when
> + * the Control is destroyed. The memory where the control's payload was copied
> + * from should be released by the caller.
> + */
> +
> +/**
> + * \class V4L2Controls
> + * \brief Wraps a list of V4L2Control and provide accessors to each control's
> + * data
> + *
> + * The V4L2Controls class works as a wrapper for a list of V4L2Control
> + * instances. The class provides operations to add a new control (set()) and
> + * to get back it's content.
> + *
> + * User of the Libcamera V4L2 control framework which want to set controls on
> + * a video device or subdevice should create instances of the V4L2Controls
> + * class and start filling it with control values. Once ready the instance
> + * should be passed to the V4L2Base::setControls() operation, that applies the
> + * control values to the underlying hardware.
> + *
> + * When reading control, a V4L2Controls instance is passed to the
> + * V4L2Base::getControls() operation, along with a list of control IDs, and it
> + * filled by the V4L2Base operation with V4L2Control instances, the user can
> + * access by ID using on the provided V4L2Controls::get() operations.
> + */
> +
> +/**
> + * \fn V4L2Controls::~V4L2Controls()
> + * \brief Destroy all V4L2Control stored in the instance
> + *
> + * \sa V4L2Controls::clear()
> + */
> +
> +/**
> + * \typedef V4L2Controls::iterator
> + * \brief Iterator on the V4L2 controls contained in the V4L2Controls
> + */
> +
> +/**
> + * \typedef CameraConfiguration::const_iterator
> + * \brief Const iterator on the  V4L2 controls contained in the V4L2Controls
> + */
> +
> +/**
> + * \fn V4L2Controls::begin
> + * \brief Retrieve an iterator to the first V4L2Control in the sequence
> + * \return An iterator to the first V4L2 control
> + */
> +
> +/**
> + * \fn iterator V4L2Controls::begin()
> + * \brief Retrieve an iterator to the first V4L2Control in the sequence
> + * \return An iterator to the first V4L2 control
> + */
> +
> +/**
> + * \fn const_iterator V4L2Controls::begin() const
> + * \brief Retrieve a constant iterator to the first V4L2Control in the sequence
> + * \return A constant iterator to the first V4L2 control
> + */
> +
> +/**
> + * \fn iterator V4L2Controls::end()
> + * \brief Retrieve an iterator pointing to the past-the-end V4L2Control in the
> + * sequence
> + * \return An iterator to the element following the last V4L2 control in the
> + * sequence
> + */
> +
> +/**
> + * \fn const_iterator V4L2Controls::end() const
> + * \brief Retrieve a constant iterator pointing to the past-the-end V4L2Control
> + * in the sequence
> + * \return A constant iterator to the element following the last V4L2 control
> + * in the sequence
> + */
> +
> +/**
> + * \fn V4L2Controls::size()
> + * \brief Retrieve the number on stored controls
> + * \return The number of V4L2Control stored in the instance
> + */
> +
> +/**
> + * \brief Destroy each control stored in the instance
> + *
> + * Destroy all the V4L2Control instances stored in this V4L2Controls instance.
> + * Reset the instance size to 0, and release all memory reserved by each
> + * control.
> + */
> +void V4L2Controls::clear()
> +{
> +	for (unsigned int i = 0; i < controls_.size(); ++i)
> +		delete controls_[i];
> +
> +	controls_.clear();
> +}
> +
> +/**
> + * \fn V4L2Controls::operator[]
> + * \brief Access the control at index \a index
> + * \param index The index to access
> + */
> +
> +/**
> + * \fn V4L2Controls::empty()
> + * \brief Retrieve if the instance is empty
> + * \return True if the instance does not contain any control, false otherwise
> + */
> +
> +/**
> + * \brief Store a new control with integer value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +void V4L2Controls::set(unsigned int id, unsigned int value)
> +{
> +	set(id, static_cast<int32_t>(value));
> +}
> +
> +/**
> + * \brief Store a new control with integer value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +void V4L2Controls::set(unsigned int id, int32_t value)
> +{
> +	V4L2IntControl *c = new V4L2IntControl(id, value);
> +	controls_.push_back(c);
> +}
> +
> +/**
> + * \brief Store a new control with 64-bit integer value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +void V4L2Controls::set(unsigned int id, int64_t value)
> +{
> +	V4L2Int64Control *c = new V4L2Int64Control(id, value);
> +	controls_.push_back(c);
> +}
> +
> +/**
> + * \brief Store a new control with boolean value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +void V4L2Controls::set(unsigned int id, bool value)
> +{
> +	V4L2BoolControl *c = new V4L2BoolControl(id, value);
> +	controls_.push_back(c);
> +}
> +
> +/**
> + * \brief Store a new control with string value
> + * \param id The control's id
> + * \param value The control's value
> + */
> +void V4L2Controls::set(unsigned int id, std::string value)
> +{
> +	V4L2StringControl *c = new V4L2StringControl(id, value);
> +	controls_.push_back(c);
> +}
> +
> +/**
> + * \brief Store a new control with pointer to payload
> + * \param id The control's id
> + * \param size The payload size
> + * \param value The pointer to the data payload
> + */
> +void V4L2Controls::set(unsigned int id, size_t size, uint8_t *value)
> +{
> +	V4L2U8Control *c = new V4L2U8Control(id, size, value);
> +	controls_.push_back(c);
> +}
> +
> +/**
> + * \brief Store a new control with pointer to payload
> + * \param id The control's id
> + * \param size The payload size
> + * \param value The pointer to the data payload
> + */
> +void V4L2Controls::set(unsigned int id, size_t size, uint16_t *value)
> +{
> +	V4L2U16Control *c = new V4L2U16Control(id, size, value);
> +	controls_.push_back(c);
> +}
> +
> +/**
> + * \brief Store a new control with pointer to payload
> + * \param id The control's id
> + * \param size The payload size
> + * \param value The pointer to the data payload
> + */
> +void V4L2Controls::set(unsigned int id, size_t size, uint32_t *value)
> +{
> +	V4L2U32Control *c = new V4L2U32Control(id, size, value);
> +	controls_.push_back(c);
> +
> +}
> +
> +/**
> + * \brief Retrieve the control's integer value
> + * \param id The control's id
> + * \return The value of control with \a id, a negative error code if the control
> + * does not exist in the instance
> + */
> +int32_t V4L2Controls::getInt(unsigned int id)
> +{
> +	for (V4L2Control *c : controls_) {
> +		if (c->id() != id)
> +			continue;
> +
> +		V4L2IntControl *ic = static_cast<V4L2IntControl *>(c);
> +		return ic->value();
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +/**
> + * \brief Retrieve the control's 64-bit integer value
> + * \param id The control's id
> + * \return The value of control with \a id, a negative error code if the control
> + * does not exist in the instance
> + */
> +int64_t V4L2Controls::getInt64(unsigned int id)
> +{
> +	for (V4L2Control *c : controls_) {
> +		if (c->id() != id)
> +			continue;
> +
> +		V4L2Int64Control *ic = static_cast<V4L2Int64Control *>(c);
> +		return ic->value();
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +/**
> + * \brief Retrieve the control's boolean value
> + * \param id The control's id
> + * \return The value of control with \a id, false if the control does not exist
> + * in the instance
> + */
> +bool V4L2Controls::getBool(unsigned int id)
> +{
> +	for (V4L2Control *c : controls_) {
> +		if (c->id() != id)
> +			continue;
> +
> +		V4L2BoolControl *ic = static_cast<V4L2BoolControl *>(c);
> +		return ic->value();
> +	}
> +
> +	return false;
> +}
> +
> +/**
> + * \brief Retrieve the control's string value
> + * \param id The control's id
> + * \return The value of control with \a id, an empty string if the control
> + * does not exist in the instance
> + */
> +std::string V4L2Controls::getString(unsigned int id)
> +{
> +	for (V4L2Control *c : controls_) {
> +		if (c->id() != id)
> +			continue;
> +
> +		V4L2StringControl *ic = static_cast<V4L2StringControl *>(c);
> +		return ic->value();
> +	}
> +
> +	return "";
> +}
> +
> +/**
> + * \brief Retrieve a pointer to the control's payload
> + * \param id The control's id
> + * \return A pointer to the control's payload, nullptr if the control
> + * does not exist in the instance
> + */
> +uint8_t *V4L2Controls::getU8(unsigned int id)
> +{
> +	for (V4L2Control *c : controls_) {
> +		if (c->id() != id)
> +			continue;
> +
> +		V4L2U8Control *ic = static_cast<V4L2U8Control *>(c);
> +		return ic->mem();
> +	}
> +
> +	return nullptr;
> +
> +}
> +
> +/**
> + * \brief Retrieve a pointer to the control's payload
> + * \param id The control's id
> + * \return A pointer to the control's payload, nullptr if the control
> + * does not exist in the instance
> + */
> +uint16_t *V4L2Controls::getU16(unsigned int id)
> +{
> +	for (V4L2Control *c : controls_) {
> +		if (c->id() != id)
> +			continue;
> +
> +		V4L2U16Control *ic = static_cast<V4L2U16Control *>(c);
> +		return ic->mem();
> +	}
> +
> +	return nullptr;
> +}
> +
> +/**
> + * \brief Retrieve a pointer to the control's payload
> + * \param id The control's id
> + * \return A pointer to the control's payload, nullptr if the control
> + * does not exist in the instance
> + */
> +uint32_t *V4L2Controls::getU32(unsigned int id)
> +{
> +	for (V4L2Control *c : controls_) {
> +		if (c->id() != id)
> +			continue;
> +
> +		V4L2U32Control *ic = static_cast<V4L2U32Control *>(c);
> +		return ic->mem();
> +	}
> +
> +	return nullptr;
> +}
> +
> +}; /* namespace libcamera */
Jacopo Mondi June 11, 2019, 1:01 p.m. UTC | #2
Hi Laurent,

On Tue, Jun 11, 2019 at 02:41:57PM +0300, Laurent Pinchart wrote:
> Hi Jacopo,
>
> Thank you for the patch.
>
> On Mon, Jun 10, 2019 at 06:40:49PM +0200, Jacopo Mondi wrote:
> > Add Libcamera V4L2 control support, implemented using the V4L2 Extended
> > Control APIs. This patch defines the types used to define and manage controls.
> >
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >  src/libcamera/include/v4l2_controls.h | 210 +++++++++
> >  src/libcamera/meson.build             |   1 +
> >  src/libcamera/v4l2_controls.cpp       | 632 ++++++++++++++++++++++++++
> >  3 files changed, 843 insertions(+)
> >  create mode 100644 src/libcamera/include/v4l2_controls.h
> >  create mode 100644 src/libcamera/v4l2_controls.cpp
> >
> > diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> > new file mode 100644
> > index 000000000000..bca5ccc29de3
> > --- /dev/null
> > +++ b/src/libcamera/include/v4l2_controls.h
> > @@ -0,0 +1,210 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2019, Google Inc.
> > + *
> > + * v4l2_controls.h - V4L2 Extended Control Support
> > + */
> > +
> > +#ifndef __LIBCAMERA_V4L2_CONTROLS_H__
> > +#define __LIBCAMERA_V4L2_CONTROLS_H__
> > +
> > +#include <cstring>
> > +#include <string>
> > +#include <vector>
> > +
> > +#include <stdint.h>
> > +
> > +#include <linux/v4l2-controls.h>
> > +#include <linux/videodev2.h>
> > +
> > +namespace libcamera {
> > +
> > +class V4L2Control
> > +{
> > +public:
> > +	virtual ~V4L2Control()
> > +	{
> > +	}
> > +
> > +	unsigned int id() { return id_; }
> > +	unsigned int size() { return size_; }
> > +	enum v4l2_ctrl_type type() const { return type_; }
> > +
> > +protected:
> > +	V4L2Control(unsigned int id, unsigned int size,
> > +		    enum v4l2_ctrl_type type)
> > +		: id_(id), size_(size), type_(type)
> > +	{
> > +	}
> > +
> > +private:
> > +	unsigned int id_;
> > +	unsigned int size_;
> > +	enum v4l2_ctrl_type type_;
> > +};
> > +
> > +template<typename T>
> > +class V4L2ControlValue : public V4L2Control
> > +{
> > +public:
> > +	T value() const { return value_; }
> > +	T *mem() const { return mem_; }
> > +
> > +protected:
> > +	V4L2ControlValue(unsigned int id, unsigned int size,
> > +			 enum v4l2_ctrl_type type, T value)
> > +		: V4L2Control(id, size, type)
> > +	{
> > +		value_ = value;
> > +		mem_ = nullptr;
> > +	}
> > +
> > +	V4L2ControlValue(unsigned int id, unsigned int size,
> > +			 enum v4l2_ctrl_type type, T *value)
> > +		: V4L2Control(id, size, type)
> > +	{
> > +		value_ = 0;
> > +		mem_ = static_cast<T *>(new T[size]);
> > +		memcpy(mem_, value, size);
> > +	}
> > +
> > +	~V4L2ControlValue()
> > +	{
> > +		delete[] mem_;
> > +	}
> > +
> > +private:
> > +	T value_;
> > +	T *mem_;
> > +};
> > +
> > +class V4L2IntControl : public V4L2ControlValue<int32_t>
> > +{
> > +private:
> > +	friend class V4L2Controls;
> > +
> > +	V4L2IntControl(unsigned int id, int32_t value)
> > +		: V4L2ControlValue<int32_t>(id, sizeof(int32_t),
> > +					    V4L2_CTRL_TYPE_INTEGER, value)
> > +	{
> > +	}
> > +};
> > +
> > +class V4L2Int64Control : public V4L2ControlValue<int64_t>
> > +{
> > +private:
> > +	friend class V4L2Controls;
> > +
> > +	V4L2Int64Control(unsigned int id, int64_t value)
> > +		: V4L2ControlValue<int64_t>(id, sizeof(int64_t),
> > +					    V4L2_CTRL_TYPE_INTEGER64, value)
> > +	{
> > +	}
> > +};
> > +
> > +class V4L2BoolControl : public V4L2ControlValue<bool>
> > +{
> > +private:
> > +	friend class V4L2Controls;
> > +
> > +	V4L2BoolControl(unsigned int id, bool value)
> > +		: V4L2ControlValue<bool>(id, sizeof(bool),
> > +					 V4L2_CTRL_TYPE_BOOLEAN, value)
> > +	{
> > +	}
> > +};
> > +
> > +class V4L2StringControl : public V4L2ControlValue<std::string>
> > +{
> > +private:
> > +	friend class V4L2Controls;
> > +
> > +	V4L2StringControl(unsigned int id, std::string value)
> > +		: V4L2ControlValue<std::string>(id, value.length(),
> > +						V4L2_CTRL_TYPE_STRING, value)
> > +	{
> > +	}
> > +};
> > +
> > +class V4L2U8Control : public V4L2ControlValue<uint8_t>
> > +{
> > +private:
> > +	friend class V4L2Controls;
> > +
> > +	V4L2U8Control(unsigned int id, unsigned int size, uint8_t *mem)
> > +		: V4L2ControlValue<uint8_t>(id, size, V4L2_CTRL_TYPE_U8, mem)
> > +	{
> > +	}
> > +};
> > +
> > +class V4L2U16Control : public V4L2ControlValue<uint16_t>
> > +{
> > +private:
> > +	friend class V4L2Controls;
> > +
> > +	V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
> > +		: V4L2ControlValue<uint16_t>(id, size, V4L2_CTRL_TYPE_U16, mem)
> > +	{
> > +	}
> > +};
> > +
> > +class V4L2U32Control : public V4L2ControlValue<uint32_t>
> > +{
> > +private:
> > +	friend class V4L2Controls;
> > +
> > +	V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
> > +		: V4L2ControlValue<uint32_t>(id, size, V4L2_CTRL_TYPE_U32, mem)
> > +	{
> > +	}
> > +};
> > +
> > +class V4L2Controls {
> > +public:
> > +	~V4L2Controls()
> > +	{
> > +		clear();
> > +	}
> > +
> > +	using iterator = std::vector<V4L2Control *>::iterator;
> > +	using const_iterator = std::vector<V4L2Control *>::const_iterator;
> > +
> > +	iterator begin() { return controls_.begin(); }
> > +	const_iterator begin() const { return controls_.begin(); }
> > +	iterator end() { return controls_.end(); }
> > +	const_iterator end() const { return controls_.end(); }
> > +
> > +	size_t size() { return controls_.size(); }
> > +	void clear();
>
> I would move clear() after empty(), to group all the methods the merely
> delegate to std::vector together, followed by the custom methods.
>
> > +
> > +	V4L2Control *operator[](unsigned int index) const
> > +	{
> > +		return controls_[index];
> > +	}
> > +
> > +	bool empty() const { return controls_.size() == 0; }
>
> 	return controls_.empty();
>
> > +
> > +	void set(unsigned int id, unsigned int value);
> > +	void set(unsigned int id, int32_t value);
> > +	void set(unsigned int id, int64_t value);
>
> This will be quite error-prone, especially the first two variants. Users
> of the class will have to be very careful about the type passed to the
> function, and C++ type deduction rules are not easy to keep in mind.
>

Indeed, this was my concern as well when I comment your suggestion on
v1. So it's either setInt/setBool etc etc, or we require users to be
very precise about the type. I don't like much any of the two, with a
slight preference for the former (multiple methods)

> > +	void set(unsigned int id, bool value);
> > +	void set(unsigned int id, std::string value);
> > +	void set(unsigned int id, size_t size, uint8_t *value);
> > +	void set(unsigned int id, size_t size, uint16_t *value);
> > +	void set(unsigned int id, size_t size, uint32_t *value);
> > +
> > +	int32_t getInt(unsigned int id);
> > +	int64_t getInt64(unsigned int id);
> > +	bool getBool(unsigned int id);
> > +	std::string getString(unsigned int id);
> > +	uint8_t *getU8(unsigned int id);
> > +	uint16_t *getU16(unsigned int id);
> > +	uint32_t *getU32(unsigned int id);
> > +
> > +private:
> > +	std::vector<V4L2Control *> controls_;
>
> I still dislike storing pointers here, as it means individual
> allocation and free. If you add the fact that array control values also
> allocate memory internally, that's quite a bit of overhead. However, now
> that the details are hidden from the user, it becomes more of an
> implementation issue, which can evolve without impacting the users.
>

The alternative is to create a class with a field for each control
type, and store all of them even if not required. To me that's more
overhead than having to carefully implement allocation/removal of
V4L2Control instances.

As you've said, this now won't be exposed to users of this API, and as
much as it could be not nice to implement and maintain, it's hidden in
the class implementation.

What's your preference?


> > +};
> > +
> > +}; /* namespace libcamera */
> > +
> > +#endif /* __LIBCAMERA_V4L2_CONTROLS_H__ */
> > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> > index 6d858a22531e..fa1fbcb5faf5 100644
> > --- a/src/libcamera/meson.build
> > +++ b/src/libcamera/meson.build
> > @@ -22,6 +22,7 @@ libcamera_sources = files([
> >      'timer.cpp',
> >      'utils.cpp',
> >      'v4l2_base.cpp',
> > +    'v4l2_controls.cpp',
> >      'v4l2_device.cpp',
> >      'v4l2_subdevice.cpp',
> >  ])
> > diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> > new file mode 100644
> > index 000000000000..bd68d07f37bf
> > --- /dev/null
> > +++ b/src/libcamera/v4l2_controls.cpp
> > @@ -0,0 +1,632 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2019, Google Inc.
> > + *
> > + * v4l2_controls.cpp - V4L2 Extended Control Support
> > + */
> > +
> > +#include "v4l2_controls.h"
> > +
> > +/**
> > + * \file v4l2_controls.h
> > + * \brief Support for V4L2 Controls using the V4L2 Extended Controls APIs.
> > + *
> > + * The V4L2 defined "Control API" allows application to inspect and modify set
> > + * of configurable parameters on the video device or subdevice of interest. The
> > + * nature of the parameters an application could modify using the control
> > + * framework depends on what the driver implements support for, and on the
> > + * characteristics of the underlying hardware platform. Generally controls are
> > + * used to modify user visible settings, such as the image brightness and
> > + * exposure time, or non-standard parameters which cannot be controlled through
> > + * the V4L2 format negotiation API.
> > + *
> > + * Controls are identified by a numerical id, defined by the V4L2 kernel headers
> > + * and have an associated type and class. Each control has a 'value', which is
> > + * the data that can be modified with a 'V4L2Base::setControl()' operation call
> > + * or retrieved with a 'V4L2Base::getControl()' one.
> > + *
> > + * A control class defines the control purpose while its type (along with the
> > + * control's flags) defines the type of the control's value content. Controls
> > + * might transport a single data value stored in variable inside the control, or
> > + * they might as well deal with more complex data types, such as arrays of
> > + * matrices, stored in a contiguous memory locations associated with the control
> > + * and called 'the payload'. The content have to be opportunely copied into the
> > + * application memory when retrieving a control's value and provided to the V4L2
> > + * device when setting it.
> > + *
> > + * Libcamera supports control using the V4L2 'Extended Control' framework, which
> > + * allows easier handling of controls with payloads of arbitrary sizes.
> > + *
> > + * The Libcamera V4L2 Controls framework operates on lists of controls, wrapped
> > + * by the V4L2Controls class, to match the V4L2 extended controls framework.
> > + * The interface to set and get control is implemented by the V4L2Base class,
> > + * while this file only provides the data type definitions.
> > + *
> > + * The Libcamera V4L2 control framework define a base class
> > + * V4L2Control that contains the fields common to all controls, regardless of
> > + * their type, such as the  control's id, its type and the expected control's
> > + * value data size. The V4L2Control class is not meant to be instantiated
> > + * directly, but is instead used as placeholder to store controls inside the
> > + * publicly constructible V4L2Controls class.
> > + *
> > + * A parametric derived class V4L2ControlValue stores the control's value and
> > + * provide accessors to the data values for controls with no payload, or to the
> > + * memory area that contains the control's data payload. These classes are not
> > + * intended to be directly used and cannot be constructed, but are used instead
> > + * to define specialized derived classes which provide accessors to the
> > + * control's data values.
> > + *
> > + * In order to set and get controls, user of the Libcamera V4L2 control
> > + * framework should operate on instances of the V4L2Controls class, iterating
> > + * on the V4L2Controls it contains, and use the V4L2Controls::set() and
> > + * V4L2Controls::get() methods to set or access the control's data
> > + * content.
> > + *
> > + * \todo Support setting controls with data payload.
> > + */
> > +
> > +namespace libcamera {
> > +
> > +/**
> > + * \class V4L2Control
> > + * \brief Base class for V4L2 Controls
> > + *
> > + * The V4L2Control base class is the base class that contains the fields common
> > + * to all controls (id, type and size).
> > + *
> > + * This class is not meant to be instantiated directly, but is instead used as a
> > + * place holder to store controls in arrays or other containers. User of the
> > + * libcamera V4L2 control framework should access the controls content by
> > + * using accessors provided by the V4L2Controls class.
> > + */
> > +
> > +/**
> > + * \fn V4L2Control::V4L2Control
> > + * \brief Construct a V4L2Control instance
> > + * \param id The control's id
> > + * \param size The control's data size
> > + * \param type The control's type
> > + */
> > +
> > +/**
> > + * \fn V4L2Control::id()
> > + * \brief Retrieve the control's id
> > + *
> > + * Retrieve the control's numerical id value as defined by the V4L2
> > + * specification.
> > + *
> > + * \return The control's id
> > + */
> > +
> > +/**
> > + * \fn V4L2Control::size()
> > + * \brief Retrieve the control's data value size in bytes
> > + *
> > + * \todo Better define the value of size() for controls with payload data.
> > + *
> > + * \return The control's size
> > + */
> > +
> > +/**
> > + * \fn V4L2Control::type()
> > + * \brief Retrieve the control's type
> > + *
> > + * Retrieve the control's type as defined by the V4L2 specification.
> > + *
> > + * \return The control's type
> > + */
> > +
> > +/**
> > + * \class V4L2ControlValue
> > + * \brief Template base class that represent values of a V4L2 control
> > + *
> > + * The V4L2ControlValue template base class represents a V4L2 control with
> > + * its different value types.
> > + *
> > + * It provides two operations to access the control's value or the pointer
> > + * to the memory location that contains to the control's value data payload.
> > + */
> > +
> > +/**
> > + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T value)
> > + * \brief Contruct a V4L2ControlValue with a parametric value
> > + * \param id The control's id
> > + * \param size The control's size
> > + * \param type The control's type
> > + * \param value The control's value
> > + */
> > +
> > +/**
> > + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T* value)
> > + * \brief Contruct a V4L2ControlValue with a pointer to a data payload
> > + * \param id The control's id
> > + * \param size The control's size
> > + * \param type The control's type
> > + * \param value The pointer to the control's data payload
> > + */
> > +
> > +/**
> > + * \fn V4L2ControlValue::~V4L2ControlValue
> > + * \brief Release the memory reserved for the control's data payload, if any
> > + */
> > +
> > +/**
> > + * \fn V4L2ControlValue::value()
> > + * \brief Retrieve the control's value
> > + *
> > + * Retrieve the control's value. Valid only for controls with no payload.
> > + */
> > +
> > +/**
> > + * \fn V4L2ControlValue::mem()
> > + * \brief Retrieve a pointer to the memory location of the control's data
> > + *
> > + * Retrieve a pointer to the memory location that contains the control's data
> > + * payload. Valid only for controls with data payload.
> > + */
> > +
> > +/**
> > + * \class V4L2IntControl
> > + * \brief Specialized V4L2Control class that handles controls of
> > + *        V4L2_CTRL_TYPE_INTEGER type.
> > + *
> > + * Access to the control's data value by using the value() operation is
> > + * restricted to the proxy V4L2Controls class.
> > + */
> > +
> > +/**
> > + * \fn V4L2IntControl::V4L2IntControl()
> > + * \brief Construct a V4L2Control that contains an int value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +
> > +/**
> > + * \class V4L2Int64Control
> > + * \brief Specialized V4L2Control class that handles controls of
> > + *        V4L2_CTRL_TYPE_INTEGER64 type.
> > + *
> > + * Access to the control's data value by using the value() operation is
> > + * restricted to the proxy V4L2Controls class.
> > + */
> > +
> > +/**
> > + * \fn V4L2Int64Control::V4L2Int64Control()
> > + * \brief Construct a V4L2Control that contains an int64 value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +
> > +/**
> > + * \class V4L2BoolControl
> > + * \brief Specialized V4L2Control class that handles controls of
> > + *        V4L2_CTRL_TYPE_BOOLEAN type.
> > + *
> > + *
> > + * Access to the control's data value by using the value() operation is
> > + * restricted to the proxy V4L2Controls class.
> > + */
> > +
> > +/**
> > + * \fn V4L2BoolControl::V4L2BoolControl()
> > + * \brief Construct a V4L2Control that contains a boolean value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +
> > +/**
> > + * \class V4L2StringControl
> > + * \brief Specialized V4L2Control class that handles controls of
> > + *        V4L2_CTRL_TYPE_STRING type.
> > + *
> > + * Access to the control's data value by using the value() operation is
> > + * restricted to the proxy V4L2Controls class.
> > + */
> > +
> > +/**
> > + * \fn V4L2StringControl::V4L2StringControl()
> > + * \brief Construct a V4L2Control that contains a string value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +
> > +/**
> > + * \class V4L2U8Control
> > + * \brief Specialized V4L2Control class that handles controls with payload of
> > + *        V4L2_CTRL_TYPE_U8 type.
> > + *
> > + * Access to the control's mem() operation is reserved to the V4L2Controls
> > + * proxy class. The size of the payload data can be retrieved with the size()
> > + * operation.
> > + */
> > +
> > +/**
> > + * \fn V4L2U8Control::V4L2U8Control()
> > + * \brief Construct a V4L2Control with payload of uin8_t data
> > + * \param id The control's id
> > + * \param size The size in bytes of the payload content
> > + * \param mem Pointer to the memory location of the payload content
> > + *
> > + * Memory is reserved in the newly created instance to hold the data payload
> > + * and the data content is copied there. The reserved memory is then freed when
> > + * the Control is destroyed. The memory where the control's payload was copied
> > + * from should be released by the caller.
> > + */
> > +
> > +/**
> > + * \class V4L2U16Control
> > + * \brief Specialized V4L2Control class that handles controls with payload of
> > + *        V4L2_CTRL_TYPE_U16 type.
> > + *
> > + * Access to the control's mem() operation is reserved to the V4L2Controls
> > + * proxy class. The size of the payload data can be retrieved with the size()
> > + * operation.
> > + */
> > +
> > +/**
> > + * \fn V4L2U16Control::V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
> > + * \brief Construct a V4L2Control with payload of uin16_t data
> > + * \param id The control's id
> > + * \param size The size in bytes of the payload content
> > + * \param mem Pointer to the memory location of the payload content
> > + *
> > + * Memory is reserved in the newly created instance to hold the data payload
> > + * and the data content is copied there. The reserved memory is then freed when
> > + * the Control is destroyed. The memory where the control's payload was copied
> > + * from should be released by the caller.
> > + */
> > +
> > +/**
> > + * \class V4L2U32Control
> > + * \brief Specialized V4L2Control class that handles controls with payload of
> > + *        V4L2_CTRL_TYPE_U32 type.
> > + *
> > + * Access to the control's mem() operation is reserved to the V4L2Controls
> > + * proxy class. The size of the payload data can be retrieved with the size()
> > + * operation.
> > + */
> > +
> > +/**
> > + * \fn V4L2U32Control::V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
> > + * \brief Construct a V4L2Control with payload of uin32_t data
> > + * \param id The control's id
> > + * \param size The size in bytes of the payload content
> > + * \param mem Pointer to the memory location of the payload content
> > + *
> > + * Memory is reserved in the newly created instance to hold the data payload
> > + * and the data content is copied there. The reserved memory is then freed when
> > + * the Control is destroyed. The memory where the control's payload was copied
> > + * from should be released by the caller.
> > + */
> > +
> > +/**
> > + * \class V4L2Controls
> > + * \brief Wraps a list of V4L2Control and provide accessors to each control's
> > + * data
> > + *
> > + * The V4L2Controls class works as a wrapper for a list of V4L2Control
> > + * instances. The class provides operations to add a new control (set()) and
> > + * to get back it's content.
> > + *
> > + * User of the Libcamera V4L2 control framework which want to set controls on
> > + * a video device or subdevice should create instances of the V4L2Controls
> > + * class and start filling it with control values. Once ready the instance
> > + * should be passed to the V4L2Base::setControls() operation, that applies the
> > + * control values to the underlying hardware.
> > + *
> > + * When reading control, a V4L2Controls instance is passed to the
> > + * V4L2Base::getControls() operation, along with a list of control IDs, and it
> > + * filled by the V4L2Base operation with V4L2Control instances, the user can
> > + * access by ID using on the provided V4L2Controls::get() operations.
> > + */
> > +
> > +/**
> > + * \fn V4L2Controls::~V4L2Controls()
> > + * \brief Destroy all V4L2Control stored in the instance
> > + *
> > + * \sa V4L2Controls::clear()
> > + */
> > +
> > +/**
> > + * \typedef V4L2Controls::iterator
> > + * \brief Iterator on the V4L2 controls contained in the V4L2Controls
> > + */
> > +
> > +/**
> > + * \typedef CameraConfiguration::const_iterator
> > + * \brief Const iterator on the  V4L2 controls contained in the V4L2Controls
> > + */
> > +
> > +/**
> > + * \fn V4L2Controls::begin
> > + * \brief Retrieve an iterator to the first V4L2Control in the sequence
> > + * \return An iterator to the first V4L2 control
> > + */
> > +
> > +/**
> > + * \fn iterator V4L2Controls::begin()
> > + * \brief Retrieve an iterator to the first V4L2Control in the sequence
> > + * \return An iterator to the first V4L2 control
> > + */
> > +
> > +/**
> > + * \fn const_iterator V4L2Controls::begin() const
> > + * \brief Retrieve a constant iterator to the first V4L2Control in the sequence
> > + * \return A constant iterator to the first V4L2 control
> > + */
> > +
> > +/**
> > + * \fn iterator V4L2Controls::end()
> > + * \brief Retrieve an iterator pointing to the past-the-end V4L2Control in the
> > + * sequence
> > + * \return An iterator to the element following the last V4L2 control in the
> > + * sequence
> > + */
> > +
> > +/**
> > + * \fn const_iterator V4L2Controls::end() const
> > + * \brief Retrieve a constant iterator pointing to the past-the-end V4L2Control
> > + * in the sequence
> > + * \return A constant iterator to the element following the last V4L2 control
> > + * in the sequence
> > + */
> > +
> > +/**
> > + * \fn V4L2Controls::size()
> > + * \brief Retrieve the number on stored controls
> > + * \return The number of V4L2Control stored in the instance
> > + */
> > +
> > +/**
> > + * \brief Destroy each control stored in the instance
> > + *
> > + * Destroy all the V4L2Control instances stored in this V4L2Controls instance.
> > + * Reset the instance size to 0, and release all memory reserved by each
> > + * control.
> > + */
> > +void V4L2Controls::clear()
> > +{
> > +	for (unsigned int i = 0; i < controls_.size(); ++i)
> > +		delete controls_[i];
> > +
> > +	controls_.clear();
> > +}
> > +
> > +/**
> > + * \fn V4L2Controls::operator[]
> > + * \brief Access the control at index \a index
> > + * \param index The index to access
> > + */
> > +
> > +/**
> > + * \fn V4L2Controls::empty()
> > + * \brief Retrieve if the instance is empty
> > + * \return True if the instance does not contain any control, false otherwise
> > + */
> > +
> > +/**
> > + * \brief Store a new control with integer value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +void V4L2Controls::set(unsigned int id, unsigned int value)
> > +{
> > +	set(id, static_cast<int32_t>(value));
> > +}
> > +
> > +/**
> > + * \brief Store a new control with integer value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +void V4L2Controls::set(unsigned int id, int32_t value)
> > +{
> > +	V4L2IntControl *c = new V4L2IntControl(id, value);
> > +	controls_.push_back(c);
> > +}
> > +
> > +/**
> > + * \brief Store a new control with 64-bit integer value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +void V4L2Controls::set(unsigned int id, int64_t value)
> > +{
> > +	V4L2Int64Control *c = new V4L2Int64Control(id, value);
> > +	controls_.push_back(c);
> > +}
> > +
> > +/**
> > + * \brief Store a new control with boolean value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +void V4L2Controls::set(unsigned int id, bool value)
> > +{
> > +	V4L2BoolControl *c = new V4L2BoolControl(id, value);
> > +	controls_.push_back(c);
> > +}
> > +
> > +/**
> > + * \brief Store a new control with string value
> > + * \param id The control's id
> > + * \param value The control's value
> > + */
> > +void V4L2Controls::set(unsigned int id, std::string value)
> > +{
> > +	V4L2StringControl *c = new V4L2StringControl(id, value);
> > +	controls_.push_back(c);
> > +}
> > +
> > +/**
> > + * \brief Store a new control with pointer to payload
> > + * \param id The control's id
> > + * \param size The payload size
> > + * \param value The pointer to the data payload
> > + */
> > +void V4L2Controls::set(unsigned int id, size_t size, uint8_t *value)
> > +{
> > +	V4L2U8Control *c = new V4L2U8Control(id, size, value);
> > +	controls_.push_back(c);
> > +}
> > +
> > +/**
> > + * \brief Store a new control with pointer to payload
> > + * \param id The control's id
> > + * \param size The payload size
> > + * \param value The pointer to the data payload
> > + */
> > +void V4L2Controls::set(unsigned int id, size_t size, uint16_t *value)
> > +{
> > +	V4L2U16Control *c = new V4L2U16Control(id, size, value);
> > +	controls_.push_back(c);
> > +}
> > +
> > +/**
> > + * \brief Store a new control with pointer to payload
> > + * \param id The control's id
> > + * \param size The payload size
> > + * \param value The pointer to the data payload
> > + */
> > +void V4L2Controls::set(unsigned int id, size_t size, uint32_t *value)
> > +{
> > +	V4L2U32Control *c = new V4L2U32Control(id, size, value);
> > +	controls_.push_back(c);
> > +
> > +}
> > +
> > +/**
> > + * \brief Retrieve the control's integer value
> > + * \param id The control's id
> > + * \return The value of control with \a id, a negative error code if the control
> > + * does not exist in the instance
> > + */
> > +int32_t V4L2Controls::getInt(unsigned int id)
> > +{
> > +	for (V4L2Control *c : controls_) {
> > +		if (c->id() != id)
> > +			continue;
> > +
> > +		V4L2IntControl *ic = static_cast<V4L2IntControl *>(c);
> > +		return ic->value();
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +
> > +/**
> > + * \brief Retrieve the control's 64-bit integer value
> > + * \param id The control's id
> > + * \return The value of control with \a id, a negative error code if the control
> > + * does not exist in the instance
> > + */
> > +int64_t V4L2Controls::getInt64(unsigned int id)
> > +{
> > +	for (V4L2Control *c : controls_) {
> > +		if (c->id() != id)
> > +			continue;
> > +
> > +		V4L2Int64Control *ic = static_cast<V4L2Int64Control *>(c);
> > +		return ic->value();
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +
> > +/**
> > + * \brief Retrieve the control's boolean value
> > + * \param id The control's id
> > + * \return The value of control with \a id, false if the control does not exist
> > + * in the instance
> > + */
> > +bool V4L2Controls::getBool(unsigned int id)
> > +{
> > +	for (V4L2Control *c : controls_) {
> > +		if (c->id() != id)
> > +			continue;
> > +
> > +		V4L2BoolControl *ic = static_cast<V4L2BoolControl *>(c);
> > +		return ic->value();
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +/**
> > + * \brief Retrieve the control's string value
> > + * \param id The control's id
> > + * \return The value of control with \a id, an empty string if the control
> > + * does not exist in the instance
> > + */
> > +std::string V4L2Controls::getString(unsigned int id)
> > +{
> > +	for (V4L2Control *c : controls_) {
> > +		if (c->id() != id)
> > +			continue;
> > +
> > +		V4L2StringControl *ic = static_cast<V4L2StringControl *>(c);
> > +		return ic->value();
> > +	}
> > +
> > +	return "";
> > +}
> > +
> > +/**
> > + * \brief Retrieve a pointer to the control's payload
> > + * \param id The control's id
> > + * \return A pointer to the control's payload, nullptr if the control
> > + * does not exist in the instance
> > + */
> > +uint8_t *V4L2Controls::getU8(unsigned int id)
> > +{
> > +	for (V4L2Control *c : controls_) {
> > +		if (c->id() != id)
> > +			continue;
> > +
> > +		V4L2U8Control *ic = static_cast<V4L2U8Control *>(c);
> > +		return ic->mem();
> > +	}
> > +
> > +	return nullptr;
> > +
> > +}
> > +
> > +/**
> > + * \brief Retrieve a pointer to the control's payload
> > + * \param id The control's id
> > + * \return A pointer to the control's payload, nullptr if the control
> > + * does not exist in the instance
> > + */
> > +uint16_t *V4L2Controls::getU16(unsigned int id)
> > +{
> > +	for (V4L2Control *c : controls_) {
> > +		if (c->id() != id)
> > +			continue;
> > +
> > +		V4L2U16Control *ic = static_cast<V4L2U16Control *>(c);
> > +		return ic->mem();
> > +	}
> > +
> > +	return nullptr;
> > +}
> > +
> > +/**
> > + * \brief Retrieve a pointer to the control's payload
> > + * \param id The control's id
> > + * \return A pointer to the control's payload, nullptr if the control
> > + * does not exist in the instance
> > + */
> > +uint32_t *V4L2Controls::getU32(unsigned int id)
> > +{
> > +	for (V4L2Control *c : controls_) {
> > +		if (c->id() != id)
> > +			continue;
> > +
> > +		V4L2U32Control *ic = static_cast<V4L2U32Control *>(c);
> > +		return ic->mem();
> > +	}
> > +
> > +	return nullptr;
> > +}
> > +
> > +}; /* namespace libcamera */
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart June 11, 2019, 3 p.m. UTC | #3
Hi Jacopo,

On Tue, Jun 11, 2019 at 03:01:11PM +0200, Jacopo Mondi wrote:
> On Tue, Jun 11, 2019 at 02:41:57PM +0300, Laurent Pinchart wrote:
> > On Mon, Jun 10, 2019 at 06:40:49PM +0200, Jacopo Mondi wrote:
> >> Add Libcamera V4L2 control support, implemented using the V4L2 Extended
> >> Control APIs. This patch defines the types used to define and manage controls.
> >>
> >> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> >> ---
> >>  src/libcamera/include/v4l2_controls.h | 210 +++++++++
> >>  src/libcamera/meson.build             |   1 +
> >>  src/libcamera/v4l2_controls.cpp       | 632 ++++++++++++++++++++++++++
> >>  3 files changed, 843 insertions(+)
> >>  create mode 100644 src/libcamera/include/v4l2_controls.h
> >>  create mode 100644 src/libcamera/v4l2_controls.cpp
> >>
> >> diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> >> new file mode 100644
> >> index 000000000000..bca5ccc29de3
> >> --- /dev/null
> >> +++ b/src/libcamera/include/v4l2_controls.h
> >> @@ -0,0 +1,210 @@
> >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> >> +/*
> >> + * Copyright (C) 2019, Google Inc.
> >> + *
> >> + * v4l2_controls.h - V4L2 Extended Control Support
> >> + */
> >> +
> >> +#ifndef __LIBCAMERA_V4L2_CONTROLS_H__
> >> +#define __LIBCAMERA_V4L2_CONTROLS_H__
> >> +
> >> +#include <cstring>
> >> +#include <string>
> >> +#include <vector>
> >> +
> >> +#include <stdint.h>
> >> +
> >> +#include <linux/v4l2-controls.h>
> >> +#include <linux/videodev2.h>
> >> +
> >> +namespace libcamera {
> >> +
> >> +class V4L2Control
> >> +{
> >> +public:
> >> +	virtual ~V4L2Control()
> >> +	{
> >> +	}
> >> +
> >> +	unsigned int id() { return id_; }
> >> +	unsigned int size() { return size_; }
> >> +	enum v4l2_ctrl_type type() const { return type_; }
> >> +
> >> +protected:
> >> +	V4L2Control(unsigned int id, unsigned int size,
> >> +		    enum v4l2_ctrl_type type)
> >> +		: id_(id), size_(size), type_(type)
> >> +	{
> >> +	}
> >> +
> >> +private:
> >> +	unsigned int id_;
> >> +	unsigned int size_;
> >> +	enum v4l2_ctrl_type type_;
> >> +};
> >> +
> >> +template<typename T>
> >> +class V4L2ControlValue : public V4L2Control
> >> +{
> >> +public:
> >> +	T value() const { return value_; }
> >> +	T *mem() const { return mem_; }
> >> +
> >> +protected:
> >> +	V4L2ControlValue(unsigned int id, unsigned int size,
> >> +			 enum v4l2_ctrl_type type, T value)
> >> +		: V4L2Control(id, size, type)
> >> +	{
> >> +		value_ = value;
> >> +		mem_ = nullptr;
> >> +	}
> >> +
> >> +	V4L2ControlValue(unsigned int id, unsigned int size,
> >> +			 enum v4l2_ctrl_type type, T *value)
> >> +		: V4L2Control(id, size, type)
> >> +	{
> >> +		value_ = 0;
> >> +		mem_ = static_cast<T *>(new T[size]);
> >> +		memcpy(mem_, value, size);
> >> +	}
> >> +
> >> +	~V4L2ControlValue()
> >> +	{
> >> +		delete[] mem_;
> >> +	}
> >> +
> >> +private:
> >> +	T value_;
> >> +	T *mem_;
> >> +};
> >> +
> >> +class V4L2IntControl : public V4L2ControlValue<int32_t>
> >> +{
> >> +private:
> >> +	friend class V4L2Controls;
> >> +
> >> +	V4L2IntControl(unsigned int id, int32_t value)
> >> +		: V4L2ControlValue<int32_t>(id, sizeof(int32_t),
> >> +					    V4L2_CTRL_TYPE_INTEGER, value)
> >> +	{
> >> +	}
> >> +};
> >> +
> >> +class V4L2Int64Control : public V4L2ControlValue<int64_t>
> >> +{
> >> +private:
> >> +	friend class V4L2Controls;
> >> +
> >> +	V4L2Int64Control(unsigned int id, int64_t value)
> >> +		: V4L2ControlValue<int64_t>(id, sizeof(int64_t),
> >> +					    V4L2_CTRL_TYPE_INTEGER64, value)
> >> +	{
> >> +	}
> >> +};
> >> +
> >> +class V4L2BoolControl : public V4L2ControlValue<bool>
> >> +{
> >> +private:
> >> +	friend class V4L2Controls;
> >> +
> >> +	V4L2BoolControl(unsigned int id, bool value)
> >> +		: V4L2ControlValue<bool>(id, sizeof(bool),
> >> +					 V4L2_CTRL_TYPE_BOOLEAN, value)
> >> +	{
> >> +	}
> >> +};
> >> +
> >> +class V4L2StringControl : public V4L2ControlValue<std::string>
> >> +{
> >> +private:
> >> +	friend class V4L2Controls;
> >> +
> >> +	V4L2StringControl(unsigned int id, std::string value)
> >> +		: V4L2ControlValue<std::string>(id, value.length(),
> >> +						V4L2_CTRL_TYPE_STRING, value)
> >> +	{
> >> +	}
> >> +};
> >> +
> >> +class V4L2U8Control : public V4L2ControlValue<uint8_t>
> >> +{
> >> +private:
> >> +	friend class V4L2Controls;
> >> +
> >> +	V4L2U8Control(unsigned int id, unsigned int size, uint8_t *mem)
> >> +		: V4L2ControlValue<uint8_t>(id, size, V4L2_CTRL_TYPE_U8, mem)
> >> +	{
> >> +	}
> >> +};
> >> +
> >> +class V4L2U16Control : public V4L2ControlValue<uint16_t>
> >> +{
> >> +private:
> >> +	friend class V4L2Controls;
> >> +
> >> +	V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
> >> +		: V4L2ControlValue<uint16_t>(id, size, V4L2_CTRL_TYPE_U16, mem)
> >> +	{
> >> +	}
> >> +};
> >> +
> >> +class V4L2U32Control : public V4L2ControlValue<uint32_t>
> >> +{
> >> +private:
> >> +	friend class V4L2Controls;
> >> +
> >> +	V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
> >> +		: V4L2ControlValue<uint32_t>(id, size, V4L2_CTRL_TYPE_U32, mem)
> >> +	{
> >> +	}
> >> +};
> >> +
> >> +class V4L2Controls {
> >> +public:
> >> +	~V4L2Controls()
> >> +	{
> >> +		clear();
> >> +	}
> >> +
> >> +	using iterator = std::vector<V4L2Control *>::iterator;
> >> +	using const_iterator = std::vector<V4L2Control *>::const_iterator;
> >> +
> >> +	iterator begin() { return controls_.begin(); }
> >> +	const_iterator begin() const { return controls_.begin(); }
> >> +	iterator end() { return controls_.end(); }
> >> +	const_iterator end() const { return controls_.end(); }
> >> +
> >> +	size_t size() { return controls_.size(); }
> >> +	void clear();
> >
> > I would move clear() after empty(), to group all the methods the merely
> > delegate to std::vector together, followed by the custom methods.
> >
> >> +
> >> +	V4L2Control *operator[](unsigned int index) const
> >> +	{
> >> +		return controls_[index];
> >> +	}
> >> +
> >> +	bool empty() const { return controls_.size() == 0; }
> >
> > 	return controls_.empty();
> >
> >> +
> >> +	void set(unsigned int id, unsigned int value);
> >> +	void set(unsigned int id, int32_t value);
> >> +	void set(unsigned int id, int64_t value);
> >
> > This will be quite error-prone, especially the first two variants. Users
> > of the class will have to be very careful about the type passed to the
> > function, and C++ type deduction rules are not easy to keep in mind.
> 
> Indeed, this was my concern as well when I comment your suggestion on
> v1. So it's either setInt/setBool etc etc, or we require users to be
> very precise about the type. I don't like much any of the two, with a
> slight preference for the former (multiple methods)

Could we have a single method for integers, based on a 64-bit signe
value, to replace the three methods above ?

> >> +	void set(unsigned int id, bool value);
> >> +	void set(unsigned int id, std::string value);
> >> +	void set(unsigned int id, size_t size, uint8_t *value);
> >> +	void set(unsigned int id, size_t size, uint16_t *value);
> >> +	void set(unsigned int id, size_t size, uint32_t *value);
> >> +
> >> +	int32_t getInt(unsigned int id);
> >> +	int64_t getInt64(unsigned int id);
> >> +	bool getBool(unsigned int id);
> >> +	std::string getString(unsigned int id);
> >> +	uint8_t *getU8(unsigned int id);
> >> +	uint16_t *getU16(unsigned int id);
> >> +	uint32_t *getU32(unsigned int id);
> >> +
> >> +private:
> >> +	std::vector<V4L2Control *> controls_;
> >
> > I still dislike storing pointers here, as it means individual
> > allocation and free. If you add the fact that array control values also
> > allocate memory internally, that's quite a bit of overhead. However, now
> > that the details are hidden from the user, it becomes more of an
> > implementation issue, which can evolve without impacting the users.
> 
> The alternative is to create a class with a field for each control
> type, and store all of them even if not required. To me that's more
> overhead than having to carefully implement allocation/removal of
> V4L2Control instances.
> 
> As you've said, this now won't be exposed to users of this API, and as
> much as it could be not nice to implement and maintain, it's hidden in
> the class implementation.
> 
> What's your preference?

Not sure about the overhead, but it's at least wasted memory. Note that
only non-POD (plain old data) types prevent usage of a union, so in our
case it's just std::string. We could byte the bullet and decide to keep
std::string outside of the union, or we could replace it with a char *.
The latter would require dynamic allocation, as for all the payload
controls. Given how few string controls we'll have to handle (there's
only four of them in the V4L2 spec, all related to RDS, and one in the
solo6x10 driver for OSD), I wonder if we shouldn't just drop support for
string controls and add it later when needed (hopefully never :-)).

> >> +};
> >> +
> >> +}; /* namespace libcamera */
> >> +
> >> +#endif /* __LIBCAMERA_V4L2_CONTROLS_H__ */
> >> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> >> index 6d858a22531e..fa1fbcb5faf5 100644
> >> --- a/src/libcamera/meson.build
> >> +++ b/src/libcamera/meson.build
> >> @@ -22,6 +22,7 @@ libcamera_sources = files([
> >>      'timer.cpp',
> >>      'utils.cpp',
> >>      'v4l2_base.cpp',
> >> +    'v4l2_controls.cpp',
> >>      'v4l2_device.cpp',
> >>      'v4l2_subdevice.cpp',
> >>  ])
> >> diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> >> new file mode 100644
> >> index 000000000000..bd68d07f37bf
> >> --- /dev/null
> >> +++ b/src/libcamera/v4l2_controls.cpp
> >> @@ -0,0 +1,632 @@
> >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> >> +/*
> >> + * Copyright (C) 2019, Google Inc.
> >> + *
> >> + * v4l2_controls.cpp - V4L2 Extended Control Support
> >> + */
> >> +
> >> +#include "v4l2_controls.h"
> >> +
> >> +/**
> >> + * \file v4l2_controls.h
> >> + * \brief Support for V4L2 Controls using the V4L2 Extended Controls APIs.
> >> + *
> >> + * The V4L2 defined "Control API" allows application to inspect and modify set
> >> + * of configurable parameters on the video device or subdevice of interest. The
> >> + * nature of the parameters an application could modify using the control
> >> + * framework depends on what the driver implements support for, and on the
> >> + * characteristics of the underlying hardware platform. Generally controls are
> >> + * used to modify user visible settings, such as the image brightness and
> >> + * exposure time, or non-standard parameters which cannot be controlled through
> >> + * the V4L2 format negotiation API.
> >> + *
> >> + * Controls are identified by a numerical id, defined by the V4L2 kernel headers
> >> + * and have an associated type and class. Each control has a 'value', which is
> >> + * the data that can be modified with a 'V4L2Base::setControl()' operation call
> >> + * or retrieved with a 'V4L2Base::getControl()' one.
> >> + *
> >> + * A control class defines the control purpose while its type (along with the
> >> + * control's flags) defines the type of the control's value content. Controls
> >> + * might transport a single data value stored in variable inside the control, or
> >> + * they might as well deal with more complex data types, such as arrays of
> >> + * matrices, stored in a contiguous memory locations associated with the control
> >> + * and called 'the payload'. The content have to be opportunely copied into the
> >> + * application memory when retrieving a control's value and provided to the V4L2
> >> + * device when setting it.
> >> + *
> >> + * Libcamera supports control using the V4L2 'Extended Control' framework, which
> >> + * allows easier handling of controls with payloads of arbitrary sizes.
> >> + *
> >> + * The Libcamera V4L2 Controls framework operates on lists of controls, wrapped
> >> + * by the V4L2Controls class, to match the V4L2 extended controls framework.
> >> + * The interface to set and get control is implemented by the V4L2Base class,
> >> + * while this file only provides the data type definitions.
> >> + *
> >> + * The Libcamera V4L2 control framework define a base class
> >> + * V4L2Control that contains the fields common to all controls, regardless of
> >> + * their type, such as the  control's id, its type and the expected control's
> >> + * value data size. The V4L2Control class is not meant to be instantiated
> >> + * directly, but is instead used as placeholder to store controls inside the
> >> + * publicly constructible V4L2Controls class.
> >> + *
> >> + * A parametric derived class V4L2ControlValue stores the control's value and
> >> + * provide accessors to the data values for controls with no payload, or to the
> >> + * memory area that contains the control's data payload. These classes are not
> >> + * intended to be directly used and cannot be constructed, but are used instead
> >> + * to define specialized derived classes which provide accessors to the
> >> + * control's data values.
> >> + *
> >> + * In order to set and get controls, user of the Libcamera V4L2 control
> >> + * framework should operate on instances of the V4L2Controls class, iterating
> >> + * on the V4L2Controls it contains, and use the V4L2Controls::set() and
> >> + * V4L2Controls::get() methods to set or access the control's data
> >> + * content.
> >> + *
> >> + * \todo Support setting controls with data payload.
> >> + */
> >> +
> >> +namespace libcamera {
> >> +
> >> +/**
> >> + * \class V4L2Control
> >> + * \brief Base class for V4L2 Controls
> >> + *
> >> + * The V4L2Control base class is the base class that contains the fields common
> >> + * to all controls (id, type and size).
> >> + *
> >> + * This class is not meant to be instantiated directly, but is instead used as a
> >> + * place holder to store controls in arrays or other containers. User of the
> >> + * libcamera V4L2 control framework should access the controls content by
> >> + * using accessors provided by the V4L2Controls class.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Control::V4L2Control
> >> + * \brief Construct a V4L2Control instance
> >> + * \param id The control's id
> >> + * \param size The control's data size
> >> + * \param type The control's type
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Control::id()
> >> + * \brief Retrieve the control's id
> >> + *
> >> + * Retrieve the control's numerical id value as defined by the V4L2
> >> + * specification.
> >> + *
> >> + * \return The control's id
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Control::size()
> >> + * \brief Retrieve the control's data value size in bytes
> >> + *
> >> + * \todo Better define the value of size() for controls with payload data.
> >> + *
> >> + * \return The control's size
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Control::type()
> >> + * \brief Retrieve the control's type
> >> + *
> >> + * Retrieve the control's type as defined by the V4L2 specification.
> >> + *
> >> + * \return The control's type
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2ControlValue
> >> + * \brief Template base class that represent values of a V4L2 control
> >> + *
> >> + * The V4L2ControlValue template base class represents a V4L2 control with
> >> + * its different value types.
> >> + *
> >> + * It provides two operations to access the control's value or the pointer
> >> + * to the memory location that contains to the control's value data payload.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T value)
> >> + * \brief Contruct a V4L2ControlValue with a parametric value
> >> + * \param id The control's id
> >> + * \param size The control's size
> >> + * \param type The control's type
> >> + * \param value The control's value
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T* value)
> >> + * \brief Contruct a V4L2ControlValue with a pointer to a data payload
> >> + * \param id The control's id
> >> + * \param size The control's size
> >> + * \param type The control's type
> >> + * \param value The pointer to the control's data payload
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2ControlValue::~V4L2ControlValue
> >> + * \brief Release the memory reserved for the control's data payload, if any
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2ControlValue::value()
> >> + * \brief Retrieve the control's value
> >> + *
> >> + * Retrieve the control's value. Valid only for controls with no payload.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2ControlValue::mem()
> >> + * \brief Retrieve a pointer to the memory location of the control's data
> >> + *
> >> + * Retrieve a pointer to the memory location that contains the control's data
> >> + * payload. Valid only for controls with data payload.
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2IntControl
> >> + * \brief Specialized V4L2Control class that handles controls of
> >> + *        V4L2_CTRL_TYPE_INTEGER type.
> >> + *
> >> + * Access to the control's data value by using the value() operation is
> >> + * restricted to the proxy V4L2Controls class.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2IntControl::V4L2IntControl()
> >> + * \brief Construct a V4L2Control that contains an int value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2Int64Control
> >> + * \brief Specialized V4L2Control class that handles controls of
> >> + *        V4L2_CTRL_TYPE_INTEGER64 type.
> >> + *
> >> + * Access to the control's data value by using the value() operation is
> >> + * restricted to the proxy V4L2Controls class.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Int64Control::V4L2Int64Control()
> >> + * \brief Construct a V4L2Control that contains an int64 value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2BoolControl
> >> + * \brief Specialized V4L2Control class that handles controls of
> >> + *        V4L2_CTRL_TYPE_BOOLEAN type.
> >> + *
> >> + *
> >> + * Access to the control's data value by using the value() operation is
> >> + * restricted to the proxy V4L2Controls class.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2BoolControl::V4L2BoolControl()
> >> + * \brief Construct a V4L2Control that contains a boolean value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2StringControl
> >> + * \brief Specialized V4L2Control class that handles controls of
> >> + *        V4L2_CTRL_TYPE_STRING type.
> >> + *
> >> + * Access to the control's data value by using the value() operation is
> >> + * restricted to the proxy V4L2Controls class.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2StringControl::V4L2StringControl()
> >> + * \brief Construct a V4L2Control that contains a string value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2U8Control
> >> + * \brief Specialized V4L2Control class that handles controls with payload of
> >> + *        V4L2_CTRL_TYPE_U8 type.
> >> + *
> >> + * Access to the control's mem() operation is reserved to the V4L2Controls
> >> + * proxy class. The size of the payload data can be retrieved with the size()
> >> + * operation.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2U8Control::V4L2U8Control()
> >> + * \brief Construct a V4L2Control with payload of uin8_t data
> >> + * \param id The control's id
> >> + * \param size The size in bytes of the payload content
> >> + * \param mem Pointer to the memory location of the payload content
> >> + *
> >> + * Memory is reserved in the newly created instance to hold the data payload
> >> + * and the data content is copied there. The reserved memory is then freed when
> >> + * the Control is destroyed. The memory where the control's payload was copied
> >> + * from should be released by the caller.
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2U16Control
> >> + * \brief Specialized V4L2Control class that handles controls with payload of
> >> + *        V4L2_CTRL_TYPE_U16 type.
> >> + *
> >> + * Access to the control's mem() operation is reserved to the V4L2Controls
> >> + * proxy class. The size of the payload data can be retrieved with the size()
> >> + * operation.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2U16Control::V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
> >> + * \brief Construct a V4L2Control with payload of uin16_t data
> >> + * \param id The control's id
> >> + * \param size The size in bytes of the payload content
> >> + * \param mem Pointer to the memory location of the payload content
> >> + *
> >> + * Memory is reserved in the newly created instance to hold the data payload
> >> + * and the data content is copied there. The reserved memory is then freed when
> >> + * the Control is destroyed. The memory where the control's payload was copied
> >> + * from should be released by the caller.
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2U32Control
> >> + * \brief Specialized V4L2Control class that handles controls with payload of
> >> + *        V4L2_CTRL_TYPE_U32 type.
> >> + *
> >> + * Access to the control's mem() operation is reserved to the V4L2Controls
> >> + * proxy class. The size of the payload data can be retrieved with the size()
> >> + * operation.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2U32Control::V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
> >> + * \brief Construct a V4L2Control with payload of uin32_t data
> >> + * \param id The control's id
> >> + * \param size The size in bytes of the payload content
> >> + * \param mem Pointer to the memory location of the payload content
> >> + *
> >> + * Memory is reserved in the newly created instance to hold the data payload
> >> + * and the data content is copied there. The reserved memory is then freed when
> >> + * the Control is destroyed. The memory where the control's payload was copied
> >> + * from should be released by the caller.
> >> + */
> >> +
> >> +/**
> >> + * \class V4L2Controls
> >> + * \brief Wraps a list of V4L2Control and provide accessors to each control's
> >> + * data
> >> + *
> >> + * The V4L2Controls class works as a wrapper for a list of V4L2Control
> >> + * instances. The class provides operations to add a new control (set()) and
> >> + * to get back it's content.
> >> + *
> >> + * User of the Libcamera V4L2 control framework which want to set controls on
> >> + * a video device or subdevice should create instances of the V4L2Controls
> >> + * class and start filling it with control values. Once ready the instance
> >> + * should be passed to the V4L2Base::setControls() operation, that applies the
> >> + * control values to the underlying hardware.
> >> + *
> >> + * When reading control, a V4L2Controls instance is passed to the
> >> + * V4L2Base::getControls() operation, along with a list of control IDs, and it
> >> + * filled by the V4L2Base operation with V4L2Control instances, the user can
> >> + * access by ID using on the provided V4L2Controls::get() operations.
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Controls::~V4L2Controls()
> >> + * \brief Destroy all V4L2Control stored in the instance
> >> + *
> >> + * \sa V4L2Controls::clear()
> >> + */
> >> +
> >> +/**
> >> + * \typedef V4L2Controls::iterator
> >> + * \brief Iterator on the V4L2 controls contained in the V4L2Controls
> >> + */
> >> +
> >> +/**
> >> + * \typedef CameraConfiguration::const_iterator
> >> + * \brief Const iterator on the  V4L2 controls contained in the V4L2Controls
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Controls::begin
> >> + * \brief Retrieve an iterator to the first V4L2Control in the sequence
> >> + * \return An iterator to the first V4L2 control
> >> + */
> >> +
> >> +/**
> >> + * \fn iterator V4L2Controls::begin()
> >> + * \brief Retrieve an iterator to the first V4L2Control in the sequence
> >> + * \return An iterator to the first V4L2 control
> >> + */
> >> +
> >> +/**
> >> + * \fn const_iterator V4L2Controls::begin() const
> >> + * \brief Retrieve a constant iterator to the first V4L2Control in the sequence
> >> + * \return A constant iterator to the first V4L2 control
> >> + */
> >> +
> >> +/**
> >> + * \fn iterator V4L2Controls::end()
> >> + * \brief Retrieve an iterator pointing to the past-the-end V4L2Control in the
> >> + * sequence
> >> + * \return An iterator to the element following the last V4L2 control in the
> >> + * sequence
> >> + */
> >> +
> >> +/**
> >> + * \fn const_iterator V4L2Controls::end() const
> >> + * \brief Retrieve a constant iterator pointing to the past-the-end V4L2Control
> >> + * in the sequence
> >> + * \return A constant iterator to the element following the last V4L2 control
> >> + * in the sequence
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Controls::size()
> >> + * \brief Retrieve the number on stored controls
> >> + * \return The number of V4L2Control stored in the instance
> >> + */
> >> +
> >> +/**
> >> + * \brief Destroy each control stored in the instance
> >> + *
> >> + * Destroy all the V4L2Control instances stored in this V4L2Controls instance.
> >> + * Reset the instance size to 0, and release all memory reserved by each
> >> + * control.
> >> + */
> >> +void V4L2Controls::clear()
> >> +{
> >> +	for (unsigned int i = 0; i < controls_.size(); ++i)
> >> +		delete controls_[i];
> >> +
> >> +	controls_.clear();
> >> +}
> >> +
> >> +/**
> >> + * \fn V4L2Controls::operator[]
> >> + * \brief Access the control at index \a index
> >> + * \param index The index to access
> >> + */
> >> +
> >> +/**
> >> + * \fn V4L2Controls::empty()
> >> + * \brief Retrieve if the instance is empty
> >> + * \return True if the instance does not contain any control, false otherwise
> >> + */
> >> +
> >> +/**
> >> + * \brief Store a new control with integer value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +void V4L2Controls::set(unsigned int id, unsigned int value)
> >> +{
> >> +	set(id, static_cast<int32_t>(value));
> >> +}
> >> +
> >> +/**
> >> + * \brief Store a new control with integer value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +void V4L2Controls::set(unsigned int id, int32_t value)
> >> +{
> >> +	V4L2IntControl *c = new V4L2IntControl(id, value);
> >> +	controls_.push_back(c);
> >> +}
> >> +
> >> +/**
> >> + * \brief Store a new control with 64-bit integer value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +void V4L2Controls::set(unsigned int id, int64_t value)
> >> +{
> >> +	V4L2Int64Control *c = new V4L2Int64Control(id, value);
> >> +	controls_.push_back(c);
> >> +}
> >> +
> >> +/**
> >> + * \brief Store a new control with boolean value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +void V4L2Controls::set(unsigned int id, bool value)
> >> +{
> >> +	V4L2BoolControl *c = new V4L2BoolControl(id, value);
> >> +	controls_.push_back(c);
> >> +}
> >> +
> >> +/**
> >> + * \brief Store a new control with string value
> >> + * \param id The control's id
> >> + * \param value The control's value
> >> + */
> >> +void V4L2Controls::set(unsigned int id, std::string value)
> >> +{
> >> +	V4L2StringControl *c = new V4L2StringControl(id, value);
> >> +	controls_.push_back(c);
> >> +}
> >> +
> >> +/**
> >> + * \brief Store a new control with pointer to payload
> >> + * \param id The control's id
> >> + * \param size The payload size
> >> + * \param value The pointer to the data payload
> >> + */
> >> +void V4L2Controls::set(unsigned int id, size_t size, uint8_t *value)
> >> +{
> >> +	V4L2U8Control *c = new V4L2U8Control(id, size, value);
> >> +	controls_.push_back(c);
> >> +}
> >> +
> >> +/**
> >> + * \brief Store a new control with pointer to payload
> >> + * \param id The control's id
> >> + * \param size The payload size
> >> + * \param value The pointer to the data payload
> >> + */
> >> +void V4L2Controls::set(unsigned int id, size_t size, uint16_t *value)
> >> +{
> >> +	V4L2U16Control *c = new V4L2U16Control(id, size, value);
> >> +	controls_.push_back(c);
> >> +}
> >> +
> >> +/**
> >> + * \brief Store a new control with pointer to payload
> >> + * \param id The control's id
> >> + * \param size The payload size
> >> + * \param value The pointer to the data payload
> >> + */
> >> +void V4L2Controls::set(unsigned int id, size_t size, uint32_t *value)
> >> +{
> >> +	V4L2U32Control *c = new V4L2U32Control(id, size, value);
> >> +	controls_.push_back(c);
> >> +
> >> +}
> >> +
> >> +/**
> >> + * \brief Retrieve the control's integer value
> >> + * \param id The control's id
> >> + * \return The value of control with \a id, a negative error code if the control
> >> + * does not exist in the instance
> >> + */
> >> +int32_t V4L2Controls::getInt(unsigned int id)
> >> +{
> >> +	for (V4L2Control *c : controls_) {
> >> +		if (c->id() != id)
> >> +			continue;
> >> +
> >> +		V4L2IntControl *ic = static_cast<V4L2IntControl *>(c);
> >> +		return ic->value();
> >> +	}
> >> +
> >> +	return -EINVAL;
> >> +}
> >> +
> >> +/**
> >> + * \brief Retrieve the control's 64-bit integer value
> >> + * \param id The control's id
> >> + * \return The value of control with \a id, a negative error code if the control
> >> + * does not exist in the instance
> >> + */
> >> +int64_t V4L2Controls::getInt64(unsigned int id)
> >> +{
> >> +	for (V4L2Control *c : controls_) {
> >> +		if (c->id() != id)
> >> +			continue;
> >> +
> >> +		V4L2Int64Control *ic = static_cast<V4L2Int64Control *>(c);
> >> +		return ic->value();
> >> +	}
> >> +
> >> +	return -EINVAL;
> >> +}
> >> +
> >> +/**
> >> + * \brief Retrieve the control's boolean value
> >> + * \param id The control's id
> >> + * \return The value of control with \a id, false if the control does not exist
> >> + * in the instance
> >> + */
> >> +bool V4L2Controls::getBool(unsigned int id)
> >> +{
> >> +	for (V4L2Control *c : controls_) {
> >> +		if (c->id() != id)
> >> +			continue;
> >> +
> >> +		V4L2BoolControl *ic = static_cast<V4L2BoolControl *>(c);
> >> +		return ic->value();
> >> +	}
> >> +
> >> +	return false;
> >> +}
> >> +
> >> +/**
> >> + * \brief Retrieve the control's string value
> >> + * \param id The control's id
> >> + * \return The value of control with \a id, an empty string if the control
> >> + * does not exist in the instance
> >> + */
> >> +std::string V4L2Controls::getString(unsigned int id)
> >> +{
> >> +	for (V4L2Control *c : controls_) {
> >> +		if (c->id() != id)
> >> +			continue;
> >> +
> >> +		V4L2StringControl *ic = static_cast<V4L2StringControl *>(c);
> >> +		return ic->value();
> >> +	}
> >> +
> >> +	return "";
> >> +}
> >> +
> >> +/**
> >> + * \brief Retrieve a pointer to the control's payload
> >> + * \param id The control's id
> >> + * \return A pointer to the control's payload, nullptr if the control
> >> + * does not exist in the instance
> >> + */
> >> +uint8_t *V4L2Controls::getU8(unsigned int id)
> >> +{
> >> +	for (V4L2Control *c : controls_) {
> >> +		if (c->id() != id)
> >> +			continue;
> >> +
> >> +		V4L2U8Control *ic = static_cast<V4L2U8Control *>(c);
> >> +		return ic->mem();
> >> +	}
> >> +
> >> +	return nullptr;
> >> +
> >> +}
> >> +
> >> +/**
> >> + * \brief Retrieve a pointer to the control's payload
> >> + * \param id The control's id
> >> + * \return A pointer to the control's payload, nullptr if the control
> >> + * does not exist in the instance
> >> + */
> >> +uint16_t *V4L2Controls::getU16(unsigned int id)
> >> +{
> >> +	for (V4L2Control *c : controls_) {
> >> +		if (c->id() != id)
> >> +			continue;
> >> +
> >> +		V4L2U16Control *ic = static_cast<V4L2U16Control *>(c);
> >> +		return ic->mem();
> >> +	}
> >> +
> >> +	return nullptr;
> >> +}
> >> +
> >> +/**
> >> + * \brief Retrieve a pointer to the control's payload
> >> + * \param id The control's id
> >> + * \return A pointer to the control's payload, nullptr if the control
> >> + * does not exist in the instance
> >> + */
> >> +uint32_t *V4L2Controls::getU32(unsigned int id)
> >> +{
> >> +	for (V4L2Control *c : controls_) {
> >> +		if (c->id() != id)
> >> +			continue;
> >> +
> >> +		V4L2U32Control *ic = static_cast<V4L2U32Control *>(c);
> >> +		return ic->mem();
> >> +	}
> >> +
> >> +	return nullptr;
> >> +}
> >> +
> >> +}; /* namespace libcamera */

Patch

diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
new file mode 100644
index 000000000000..bca5ccc29de3
--- /dev/null
+++ b/src/libcamera/include/v4l2_controls.h
@@ -0,0 +1,210 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * v4l2_controls.h - V4L2 Extended Control Support
+ */
+
+#ifndef __LIBCAMERA_V4L2_CONTROLS_H__
+#define __LIBCAMERA_V4L2_CONTROLS_H__
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include <stdint.h>
+
+#include <linux/v4l2-controls.h>
+#include <linux/videodev2.h>
+
+namespace libcamera {
+
+class V4L2Control
+{
+public:
+	virtual ~V4L2Control()
+	{
+	}
+
+	unsigned int id() { return id_; }
+	unsigned int size() { return size_; }
+	enum v4l2_ctrl_type type() const { return type_; }
+
+protected:
+	V4L2Control(unsigned int id, unsigned int size,
+		    enum v4l2_ctrl_type type)
+		: id_(id), size_(size), type_(type)
+	{
+	}
+
+private:
+	unsigned int id_;
+	unsigned int size_;
+	enum v4l2_ctrl_type type_;
+};
+
+template<typename T>
+class V4L2ControlValue : public V4L2Control
+{
+public:
+	T value() const { return value_; }
+	T *mem() const { return mem_; }
+
+protected:
+	V4L2ControlValue(unsigned int id, unsigned int size,
+			 enum v4l2_ctrl_type type, T value)
+		: V4L2Control(id, size, type)
+	{
+		value_ = value;
+		mem_ = nullptr;
+	}
+
+	V4L2ControlValue(unsigned int id, unsigned int size,
+			 enum v4l2_ctrl_type type, T *value)
+		: V4L2Control(id, size, type)
+	{
+		value_ = 0;
+		mem_ = static_cast<T *>(new T[size]);
+		memcpy(mem_, value, size);
+	}
+
+	~V4L2ControlValue()
+	{
+		delete[] mem_;
+	}
+
+private:
+	T value_;
+	T *mem_;
+};
+
+class V4L2IntControl : public V4L2ControlValue<int32_t>
+{
+private:
+	friend class V4L2Controls;
+
+	V4L2IntControl(unsigned int id, int32_t value)
+		: V4L2ControlValue<int32_t>(id, sizeof(int32_t),
+					    V4L2_CTRL_TYPE_INTEGER, value)
+	{
+	}
+};
+
+class V4L2Int64Control : public V4L2ControlValue<int64_t>
+{
+private:
+	friend class V4L2Controls;
+
+	V4L2Int64Control(unsigned int id, int64_t value)
+		: V4L2ControlValue<int64_t>(id, sizeof(int64_t),
+					    V4L2_CTRL_TYPE_INTEGER64, value)
+	{
+	}
+};
+
+class V4L2BoolControl : public V4L2ControlValue<bool>
+{
+private:
+	friend class V4L2Controls;
+
+	V4L2BoolControl(unsigned int id, bool value)
+		: V4L2ControlValue<bool>(id, sizeof(bool),
+					 V4L2_CTRL_TYPE_BOOLEAN, value)
+	{
+	}
+};
+
+class V4L2StringControl : public V4L2ControlValue<std::string>
+{
+private:
+	friend class V4L2Controls;
+
+	V4L2StringControl(unsigned int id, std::string value)
+		: V4L2ControlValue<std::string>(id, value.length(),
+						V4L2_CTRL_TYPE_STRING, value)
+	{
+	}
+};
+
+class V4L2U8Control : public V4L2ControlValue<uint8_t>
+{
+private:
+	friend class V4L2Controls;
+
+	V4L2U8Control(unsigned int id, unsigned int size, uint8_t *mem)
+		: V4L2ControlValue<uint8_t>(id, size, V4L2_CTRL_TYPE_U8, mem)
+	{
+	}
+};
+
+class V4L2U16Control : public V4L2ControlValue<uint16_t>
+{
+private:
+	friend class V4L2Controls;
+
+	V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
+		: V4L2ControlValue<uint16_t>(id, size, V4L2_CTRL_TYPE_U16, mem)
+	{
+	}
+};
+
+class V4L2U32Control : public V4L2ControlValue<uint32_t>
+{
+private:
+	friend class V4L2Controls;
+
+	V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
+		: V4L2ControlValue<uint32_t>(id, size, V4L2_CTRL_TYPE_U32, mem)
+	{
+	}
+};
+
+class V4L2Controls {
+public:
+	~V4L2Controls()
+	{
+		clear();
+	}
+
+	using iterator = std::vector<V4L2Control *>::iterator;
+	using const_iterator = std::vector<V4L2Control *>::const_iterator;
+
+	iterator begin() { return controls_.begin(); }
+	const_iterator begin() const { return controls_.begin(); }
+	iterator end() { return controls_.end(); }
+	const_iterator end() const { return controls_.end(); }
+
+	size_t size() { return controls_.size(); }
+	void clear();
+
+	V4L2Control *operator[](unsigned int index) const
+	{
+		return controls_[index];
+	}
+
+	bool empty() const { return controls_.size() == 0; }
+
+	void set(unsigned int id, unsigned int value);
+	void set(unsigned int id, int32_t value);
+	void set(unsigned int id, int64_t value);
+	void set(unsigned int id, bool value);
+	void set(unsigned int id, std::string value);
+	void set(unsigned int id, size_t size, uint8_t *value);
+	void set(unsigned int id, size_t size, uint16_t *value);
+	void set(unsigned int id, size_t size, uint32_t *value);
+
+	int32_t getInt(unsigned int id);
+	int64_t getInt64(unsigned int id);
+	bool getBool(unsigned int id);
+	std::string getString(unsigned int id);
+	uint8_t *getU8(unsigned int id);
+	uint16_t *getU16(unsigned int id);
+	uint32_t *getU32(unsigned int id);
+
+private:
+	std::vector<V4L2Control *> controls_;
+};
+
+}; /* namespace libcamera */
+
+#endif /* __LIBCAMERA_V4L2_CONTROLS_H__ */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 6d858a22531e..fa1fbcb5faf5 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -22,6 +22,7 @@  libcamera_sources = files([
     'timer.cpp',
     'utils.cpp',
     'v4l2_base.cpp',
+    'v4l2_controls.cpp',
     'v4l2_device.cpp',
     'v4l2_subdevice.cpp',
 ])
diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
new file mode 100644
index 000000000000..bd68d07f37bf
--- /dev/null
+++ b/src/libcamera/v4l2_controls.cpp
@@ -0,0 +1,632 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * v4l2_controls.cpp - V4L2 Extended Control Support
+ */
+
+#include "v4l2_controls.h"
+
+/**
+ * \file v4l2_controls.h
+ * \brief Support for V4L2 Controls using the V4L2 Extended Controls APIs.
+ *
+ * The V4L2 defined "Control API" allows application to inspect and modify set
+ * of configurable parameters on the video device or subdevice of interest. The
+ * nature of the parameters an application could modify using the control
+ * framework depends on what the driver implements support for, and on the
+ * characteristics of the underlying hardware platform. Generally controls are
+ * used to modify user visible settings, such as the image brightness and
+ * exposure time, or non-standard parameters which cannot be controlled through
+ * the V4L2 format negotiation API.
+ *
+ * Controls are identified by a numerical id, defined by the V4L2 kernel headers
+ * and have an associated type and class. Each control has a 'value', which is
+ * the data that can be modified with a 'V4L2Base::setControl()' operation call
+ * or retrieved with a 'V4L2Base::getControl()' one.
+ *
+ * A control class defines the control purpose while its type (along with the
+ * control's flags) defines the type of the control's value content. Controls
+ * might transport a single data value stored in variable inside the control, or
+ * they might as well deal with more complex data types, such as arrays of
+ * matrices, stored in a contiguous memory locations associated with the control
+ * and called 'the payload'. The content have to be opportunely copied into the
+ * application memory when retrieving a control's value and provided to the V4L2
+ * device when setting it.
+ *
+ * Libcamera supports control using the V4L2 'Extended Control' framework, which
+ * allows easier handling of controls with payloads of arbitrary sizes.
+ *
+ * The Libcamera V4L2 Controls framework operates on lists of controls, wrapped
+ * by the V4L2Controls class, to match the V4L2 extended controls framework.
+ * The interface to set and get control is implemented by the V4L2Base class,
+ * while this file only provides the data type definitions.
+ *
+ * The Libcamera V4L2 control framework define a base class
+ * V4L2Control that contains the fields common to all controls, regardless of
+ * their type, such as the  control's id, its type and the expected control's
+ * value data size. The V4L2Control class is not meant to be instantiated
+ * directly, but is instead used as placeholder to store controls inside the
+ * publicly constructible V4L2Controls class.
+ *
+ * A parametric derived class V4L2ControlValue stores the control's value and
+ * provide accessors to the data values for controls with no payload, or to the
+ * memory area that contains the control's data payload. These classes are not
+ * intended to be directly used and cannot be constructed, but are used instead
+ * to define specialized derived classes which provide accessors to the
+ * control's data values.
+ *
+ * In order to set and get controls, user of the Libcamera V4L2 control
+ * framework should operate on instances of the V4L2Controls class, iterating
+ * on the V4L2Controls it contains, and use the V4L2Controls::set() and
+ * V4L2Controls::get() methods to set or access the control's data
+ * content.
+ *
+ * \todo Support setting controls with data payload.
+ */
+
+namespace libcamera {
+
+/**
+ * \class V4L2Control
+ * \brief Base class for V4L2 Controls
+ *
+ * The V4L2Control base class is the base class that contains the fields common
+ * to all controls (id, type and size).
+ *
+ * This class is not meant to be instantiated directly, but is instead used as a
+ * place holder to store controls in arrays or other containers. User of the
+ * libcamera V4L2 control framework should access the controls content by
+ * using accessors provided by the V4L2Controls class.
+ */
+
+/**
+ * \fn V4L2Control::V4L2Control
+ * \brief Construct a V4L2Control instance
+ * \param id The control's id
+ * \param size The control's data size
+ * \param type The control's type
+ */
+
+/**
+ * \fn V4L2Control::id()
+ * \brief Retrieve the control's id
+ *
+ * Retrieve the control's numerical id value as defined by the V4L2
+ * specification.
+ *
+ * \return The control's id
+ */
+
+/**
+ * \fn V4L2Control::size()
+ * \brief Retrieve the control's data value size in bytes
+ *
+ * \todo Better define the value of size() for controls with payload data.
+ *
+ * \return The control's size
+ */
+
+/**
+ * \fn V4L2Control::type()
+ * \brief Retrieve the control's type
+ *
+ * Retrieve the control's type as defined by the V4L2 specification.
+ *
+ * \return The control's type
+ */
+
+/**
+ * \class V4L2ControlValue
+ * \brief Template base class that represent values of a V4L2 control
+ *
+ * The V4L2ControlValue template base class represents a V4L2 control with
+ * its different value types.
+ *
+ * It provides two operations to access the control's value or the pointer
+ * to the memory location that contains to the control's value data payload.
+ */
+
+/**
+ * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T value)
+ * \brief Contruct a V4L2ControlValue with a parametric value
+ * \param id The control's id
+ * \param size The control's size
+ * \param type The control's type
+ * \param value The control's value
+ */
+
+/**
+ * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T* value)
+ * \brief Contruct a V4L2ControlValue with a pointer to a data payload
+ * \param id The control's id
+ * \param size The control's size
+ * \param type The control's type
+ * \param value The pointer to the control's data payload
+ */
+
+/**
+ * \fn V4L2ControlValue::~V4L2ControlValue
+ * \brief Release the memory reserved for the control's data payload, if any
+ */
+
+/**
+ * \fn V4L2ControlValue::value()
+ * \brief Retrieve the control's value
+ *
+ * Retrieve the control's value. Valid only for controls with no payload.
+ */
+
+/**
+ * \fn V4L2ControlValue::mem()
+ * \brief Retrieve a pointer to the memory location of the control's data
+ *
+ * Retrieve a pointer to the memory location that contains the control's data
+ * payload. Valid only for controls with data payload.
+ */
+
+/**
+ * \class V4L2IntControl
+ * \brief Specialized V4L2Control class that handles controls of
+ *        V4L2_CTRL_TYPE_INTEGER type.
+ *
+ * Access to the control's data value by using the value() operation is
+ * restricted to the proxy V4L2Controls class.
+ */
+
+/**
+ * \fn V4L2IntControl::V4L2IntControl()
+ * \brief Construct a V4L2Control that contains an int value
+ * \param id The control's id
+ * \param value The control's value
+ */
+
+/**
+ * \class V4L2Int64Control
+ * \brief Specialized V4L2Control class that handles controls of
+ *        V4L2_CTRL_TYPE_INTEGER64 type.
+ *
+ * Access to the control's data value by using the value() operation is
+ * restricted to the proxy V4L2Controls class.
+ */
+
+/**
+ * \fn V4L2Int64Control::V4L2Int64Control()
+ * \brief Construct a V4L2Control that contains an int64 value
+ * \param id The control's id
+ * \param value The control's value
+ */
+
+/**
+ * \class V4L2BoolControl
+ * \brief Specialized V4L2Control class that handles controls of
+ *        V4L2_CTRL_TYPE_BOOLEAN type.
+ *
+ *
+ * Access to the control's data value by using the value() operation is
+ * restricted to the proxy V4L2Controls class.
+ */
+
+/**
+ * \fn V4L2BoolControl::V4L2BoolControl()
+ * \brief Construct a V4L2Control that contains a boolean value
+ * \param id The control's id
+ * \param value The control's value
+ */
+
+/**
+ * \class V4L2StringControl
+ * \brief Specialized V4L2Control class that handles controls of
+ *        V4L2_CTRL_TYPE_STRING type.
+ *
+ * Access to the control's data value by using the value() operation is
+ * restricted to the proxy V4L2Controls class.
+ */
+
+/**
+ * \fn V4L2StringControl::V4L2StringControl()
+ * \brief Construct a V4L2Control that contains a string value
+ * \param id The control's id
+ * \param value The control's value
+ */
+
+/**
+ * \class V4L2U8Control
+ * \brief Specialized V4L2Control class that handles controls with payload of
+ *        V4L2_CTRL_TYPE_U8 type.
+ *
+ * Access to the control's mem() operation is reserved to the V4L2Controls
+ * proxy class. The size of the payload data can be retrieved with the size()
+ * operation.
+ */
+
+/**
+ * \fn V4L2U8Control::V4L2U8Control()
+ * \brief Construct a V4L2Control with payload of uin8_t data
+ * \param id The control's id
+ * \param size The size in bytes of the payload content
+ * \param mem Pointer to the memory location of the payload content
+ *
+ * Memory is reserved in the newly created instance to hold the data payload
+ * and the data content is copied there. The reserved memory is then freed when
+ * the Control is destroyed. The memory where the control's payload was copied
+ * from should be released by the caller.
+ */
+
+/**
+ * \class V4L2U16Control
+ * \brief Specialized V4L2Control class that handles controls with payload of
+ *        V4L2_CTRL_TYPE_U16 type.
+ *
+ * Access to the control's mem() operation is reserved to the V4L2Controls
+ * proxy class. The size of the payload data can be retrieved with the size()
+ * operation.
+ */
+
+/**
+ * \fn V4L2U16Control::V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem)
+ * \brief Construct a V4L2Control with payload of uin16_t data
+ * \param id The control's id
+ * \param size The size in bytes of the payload content
+ * \param mem Pointer to the memory location of the payload content
+ *
+ * Memory is reserved in the newly created instance to hold the data payload
+ * and the data content is copied there. The reserved memory is then freed when
+ * the Control is destroyed. The memory where the control's payload was copied
+ * from should be released by the caller.
+ */
+
+/**
+ * \class V4L2U32Control
+ * \brief Specialized V4L2Control class that handles controls with payload of
+ *        V4L2_CTRL_TYPE_U32 type.
+ *
+ * Access to the control's mem() operation is reserved to the V4L2Controls
+ * proxy class. The size of the payload data can be retrieved with the size()
+ * operation.
+ */
+
+/**
+ * \fn V4L2U32Control::V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem)
+ * \brief Construct a V4L2Control with payload of uin32_t data
+ * \param id The control's id
+ * \param size The size in bytes of the payload content
+ * \param mem Pointer to the memory location of the payload content
+ *
+ * Memory is reserved in the newly created instance to hold the data payload
+ * and the data content is copied there. The reserved memory is then freed when
+ * the Control is destroyed. The memory where the control's payload was copied
+ * from should be released by the caller.
+ */
+
+/**
+ * \class V4L2Controls
+ * \brief Wraps a list of V4L2Control and provide accessors to each control's
+ * data
+ *
+ * The V4L2Controls class works as a wrapper for a list of V4L2Control
+ * instances. The class provides operations to add a new control (set()) and
+ * to get back it's content.
+ *
+ * User of the Libcamera V4L2 control framework which want to set controls on
+ * a video device or subdevice should create instances of the V4L2Controls
+ * class and start filling it with control values. Once ready the instance
+ * should be passed to the V4L2Base::setControls() operation, that applies the
+ * control values to the underlying hardware.
+ *
+ * When reading control, a V4L2Controls instance is passed to the
+ * V4L2Base::getControls() operation, along with a list of control IDs, and it
+ * filled by the V4L2Base operation with V4L2Control instances, the user can
+ * access by ID using on the provided V4L2Controls::get() operations.
+ */
+
+/**
+ * \fn V4L2Controls::~V4L2Controls()
+ * \brief Destroy all V4L2Control stored in the instance
+ *
+ * \sa V4L2Controls::clear()
+ */
+
+/**
+ * \typedef V4L2Controls::iterator
+ * \brief Iterator on the V4L2 controls contained in the V4L2Controls
+ */
+
+/**
+ * \typedef CameraConfiguration::const_iterator
+ * \brief Const iterator on the  V4L2 controls contained in the V4L2Controls
+ */
+
+/**
+ * \fn V4L2Controls::begin
+ * \brief Retrieve an iterator to the first V4L2Control in the sequence
+ * \return An iterator to the first V4L2 control
+ */
+
+/**
+ * \fn iterator V4L2Controls::begin()
+ * \brief Retrieve an iterator to the first V4L2Control in the sequence
+ * \return An iterator to the first V4L2 control
+ */
+
+/**
+ * \fn const_iterator V4L2Controls::begin() const
+ * \brief Retrieve a constant iterator to the first V4L2Control in the sequence
+ * \return A constant iterator to the first V4L2 control
+ */
+
+/**
+ * \fn iterator V4L2Controls::end()
+ * \brief Retrieve an iterator pointing to the past-the-end V4L2Control in the
+ * sequence
+ * \return An iterator to the element following the last V4L2 control in the
+ * sequence
+ */
+
+/**
+ * \fn const_iterator V4L2Controls::end() const
+ * \brief Retrieve a constant iterator pointing to the past-the-end V4L2Control
+ * in the sequence
+ * \return A constant iterator to the element following the last V4L2 control
+ * in the sequence
+ */
+
+/**
+ * \fn V4L2Controls::size()
+ * \brief Retrieve the number on stored controls
+ * \return The number of V4L2Control stored in the instance
+ */
+
+/**
+ * \brief Destroy each control stored in the instance
+ *
+ * Destroy all the V4L2Control instances stored in this V4L2Controls instance.
+ * Reset the instance size to 0, and release all memory reserved by each
+ * control.
+ */
+void V4L2Controls::clear()
+{
+	for (unsigned int i = 0; i < controls_.size(); ++i)
+		delete controls_[i];
+
+	controls_.clear();
+}
+
+/**
+ * \fn V4L2Controls::operator[]
+ * \brief Access the control at index \a index
+ * \param index The index to access
+ */
+
+/**
+ * \fn V4L2Controls::empty()
+ * \brief Retrieve if the instance is empty
+ * \return True if the instance does not contain any control, false otherwise
+ */
+
+/**
+ * \brief Store a new control with integer value
+ * \param id The control's id
+ * \param value The control's value
+ */
+void V4L2Controls::set(unsigned int id, unsigned int value)
+{
+	set(id, static_cast<int32_t>(value));
+}
+
+/**
+ * \brief Store a new control with integer value
+ * \param id The control's id
+ * \param value The control's value
+ */
+void V4L2Controls::set(unsigned int id, int32_t value)
+{
+	V4L2IntControl *c = new V4L2IntControl(id, value);
+	controls_.push_back(c);
+}
+
+/**
+ * \brief Store a new control with 64-bit integer value
+ * \param id The control's id
+ * \param value The control's value
+ */
+void V4L2Controls::set(unsigned int id, int64_t value)
+{
+	V4L2Int64Control *c = new V4L2Int64Control(id, value);
+	controls_.push_back(c);
+}
+
+/**
+ * \brief Store a new control with boolean value
+ * \param id The control's id
+ * \param value The control's value
+ */
+void V4L2Controls::set(unsigned int id, bool value)
+{
+	V4L2BoolControl *c = new V4L2BoolControl(id, value);
+	controls_.push_back(c);
+}
+
+/**
+ * \brief Store a new control with string value
+ * \param id The control's id
+ * \param value The control's value
+ */
+void V4L2Controls::set(unsigned int id, std::string value)
+{
+	V4L2StringControl *c = new V4L2StringControl(id, value);
+	controls_.push_back(c);
+}
+
+/**
+ * \brief Store a new control with pointer to payload
+ * \param id The control's id
+ * \param size The payload size
+ * \param value The pointer to the data payload
+ */
+void V4L2Controls::set(unsigned int id, size_t size, uint8_t *value)
+{
+	V4L2U8Control *c = new V4L2U8Control(id, size, value);
+	controls_.push_back(c);
+}
+
+/**
+ * \brief Store a new control with pointer to payload
+ * \param id The control's id
+ * \param size The payload size
+ * \param value The pointer to the data payload
+ */
+void V4L2Controls::set(unsigned int id, size_t size, uint16_t *value)
+{
+	V4L2U16Control *c = new V4L2U16Control(id, size, value);
+	controls_.push_back(c);
+}
+
+/**
+ * \brief Store a new control with pointer to payload
+ * \param id The control's id
+ * \param size The payload size
+ * \param value The pointer to the data payload
+ */
+void V4L2Controls::set(unsigned int id, size_t size, uint32_t *value)
+{
+	V4L2U32Control *c = new V4L2U32Control(id, size, value);
+	controls_.push_back(c);
+
+}
+
+/**
+ * \brief Retrieve the control's integer value
+ * \param id The control's id
+ * \return The value of control with \a id, a negative error code if the control
+ * does not exist in the instance
+ */
+int32_t V4L2Controls::getInt(unsigned int id)
+{
+	for (V4L2Control *c : controls_) {
+		if (c->id() != id)
+			continue;
+
+		V4L2IntControl *ic = static_cast<V4L2IntControl *>(c);
+		return ic->value();
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * \brief Retrieve the control's 64-bit integer value
+ * \param id The control's id
+ * \return The value of control with \a id, a negative error code if the control
+ * does not exist in the instance
+ */
+int64_t V4L2Controls::getInt64(unsigned int id)
+{
+	for (V4L2Control *c : controls_) {
+		if (c->id() != id)
+			continue;
+
+		V4L2Int64Control *ic = static_cast<V4L2Int64Control *>(c);
+		return ic->value();
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * \brief Retrieve the control's boolean value
+ * \param id The control's id
+ * \return The value of control with \a id, false if the control does not exist
+ * in the instance
+ */
+bool V4L2Controls::getBool(unsigned int id)
+{
+	for (V4L2Control *c : controls_) {
+		if (c->id() != id)
+			continue;
+
+		V4L2BoolControl *ic = static_cast<V4L2BoolControl *>(c);
+		return ic->value();
+	}
+
+	return false;
+}
+
+/**
+ * \brief Retrieve the control's string value
+ * \param id The control's id
+ * \return The value of control with \a id, an empty string if the control
+ * does not exist in the instance
+ */
+std::string V4L2Controls::getString(unsigned int id)
+{
+	for (V4L2Control *c : controls_) {
+		if (c->id() != id)
+			continue;
+
+		V4L2StringControl *ic = static_cast<V4L2StringControl *>(c);
+		return ic->value();
+	}
+
+	return "";
+}
+
+/**
+ * \brief Retrieve a pointer to the control's payload
+ * \param id The control's id
+ * \return A pointer to the control's payload, nullptr if the control
+ * does not exist in the instance
+ */
+uint8_t *V4L2Controls::getU8(unsigned int id)
+{
+	for (V4L2Control *c : controls_) {
+		if (c->id() != id)
+			continue;
+
+		V4L2U8Control *ic = static_cast<V4L2U8Control *>(c);
+		return ic->mem();
+	}
+
+	return nullptr;
+
+}
+
+/**
+ * \brief Retrieve a pointer to the control's payload
+ * \param id The control's id
+ * \return A pointer to the control's payload, nullptr if the control
+ * does not exist in the instance
+ */
+uint16_t *V4L2Controls::getU16(unsigned int id)
+{
+	for (V4L2Control *c : controls_) {
+		if (c->id() != id)
+			continue;
+
+		V4L2U16Control *ic = static_cast<V4L2U16Control *>(c);
+		return ic->mem();
+	}
+
+	return nullptr;
+}
+
+/**
+ * \brief Retrieve a pointer to the control's payload
+ * \param id The control's id
+ * \return A pointer to the control's payload, nullptr if the control
+ * does not exist in the instance
+ */
+uint32_t *V4L2Controls::getU32(unsigned int id)
+{
+	for (V4L2Control *c : controls_) {
+		if (c->id() != id)
+			continue;
+
+		V4L2U32Control *ic = static_cast<V4L2U32Control *>(c);
+		return ic->mem();
+	}
+
+	return nullptr;
+}
+
+}; /* namespace libcamera */