From patchwork Tue Sep 24 17:24:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2000 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D7CDD60BCF for ; Tue, 24 Sep 2019 19:23:28 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 9017F60005 for ; Tue, 24 Sep 2019 17:23:28 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:43 +0200 Message-Id: <20190924172503.30864-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/21] libcamera: utils: Provide an ALIGN macro X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:29 -0000 Signed-off-by: Jacopo Mondi --- src/libcamera/include/utils.h | 2 ++ src/libcamera/utils.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/libcamera/include/utils.h b/src/libcamera/include/utils.h index 52eee8ac2804..08323966b44e 100644 --- a/src/libcamera/include/utils.h +++ b/src/libcamera/include/utils.h @@ -63,6 +63,8 @@ using time_point = std::chrono::steady_clock::time_point; struct timespec duration_to_timespec(const duration &value); std::string time_point_to_string(const time_point &time); +#define ALIGN(_s, _a) (((_s) + (_a - 1)) & ~(_a - 1)) + } /* namespace utils */ } /* namespace libcamera */ diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp index 928db254ec67..c3188bfff03d 100644 --- a/src/libcamera/utils.cpp +++ b/src/libcamera/utils.cpp @@ -143,6 +143,17 @@ std::string time_point_to_string(const time_point &time) return ossTimestamp.str(); } +/** + * \def ALIGN(_s, _a) + * \brief Align a size to a boundary + * \param[in] _s The size to align + * \param[in] _a The boundary to align size to + * + * Align the provide size \a _s to a the provided boundary. The request + * alignement should be a power of 2, and the aligned size is up aligned to + * the given boundary. + */ + } /* namespace utils */ } /* namespace libcamera */ From patchwork Tue Sep 24 17:24:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2001 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7C93762379 for ; Tue, 24 Sep 2019 19:23:29 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 0FD0360005 for ; Tue, 24 Sep 2019 17:23:28 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:44 +0200 Message-Id: <20190924172503.30864-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/21] libcamera: Define interface for serializable data types X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:29 -0000 Define an interface to be implemented by data types that support serialization and deserialization of their data to a memory buffer. Signed-off-by: Jacopo Mondi --- include/libcamera/meson.build | 1 + include/libcamera/serializable.h | 44 +++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/serializable.cpp | 110 +++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 include/libcamera/serializable.h create mode 100644 src/libcamera/serializable.cpp diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index e3f3ad504446..7790bfb4907b 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -13,6 +13,7 @@ libcamera_api = files([ 'object.h', 'request.h', 'signal.h', + 'serializable.h', 'stream.h', 'timer.h', ]) diff --git a/include/libcamera/serializable.h b/include/libcamera/serializable.h new file mode 100644 index 000000000000..fae2ea0fb8fe --- /dev/null +++ b/include/libcamera/serializable.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * serializable.h - Serializable data types + */ +#ifndef __LIBCAMERA_SERIALIZABLE_H__ +#define __LIBCAMERA_SERIALIZABLE_H__ + +#include +#include + +#include + +namespace libcamera { + +class DataBlob +{ +public: + DataBlob(size_t blobSize); + ~DataBlob(); + + uint8_t *data() const { return data_; } + size_t size() const { return size_; } + bool valid() const { return valid_; } + +private: + uint8_t *data_; + size_t size_; + bool valid_; +}; + +class Serializable +{ +public: + virtual ~Serializable() {} + + virtual std::unique_ptr serialize() const = 0; + virtual int deserialize(uint8_t *data, size_t len) = 0; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_SERIALIZABLE_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index c4fcd0569bd7..973b20269943 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -27,6 +27,7 @@ libcamera_sources = files([ 'process.cpp', 'request.cpp', 'signal.cpp', + 'serializable.cpp', 'stream.cpp', 'thread.cpp', 'timer.cpp', diff --git a/src/libcamera/serializable.cpp b/src/libcamera/serializable.cpp new file mode 100644 index 000000000000..4e075baca56a --- /dev/null +++ b/src/libcamera/serializable.cpp @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * serializable.cpp - Serializable data types + */ + +#include + +#include + +/** + * \file serializable.h + * \brief Interface for serializable data types + */ + +namespace libcamera { + +/** + * \class DataBlob + * \brief Wraps a memory buffer containing serialized data to provide automatic + * allocation and deletion + */ + +/** + * \brief Construct a DataBlob reserving a buffer of size \a blobSize + * \param[in] blobSize The data buffer memory size + * + * Constructing a DataBlob allocates the memory area where to serialize + * data. If memory allocation is successful the data blob is valid and its size + * is set to \a blobSize. + */ +DataBlob::DataBlob(size_t blobSize) + : data_(nullptr), size_(0), valid_(false) +{ + data_ = new uint8_t[blobSize]; + if (!data_) + return; + + ::memset(data_, 0, blobSize); + + valid_ = true; + size_ = blobSize; +} + +/** + * \brief Destroy the DataBlob and release the memory area it wraps + */ +DataBlob::~DataBlob() +{ + if (data_) + delete[] data_; +} + +/** + * \fn DataBlob::data() + * \brief Retrieve a pointer to the memory area the DataBlob wraps + * \return A pointer to the wrapped memory area + */ + +/** + * \fn DataBlob::size() + * \brief Retrieve the size of the wrapped memory area + * \return The size of the wrapped memory area in bytes, 0 if memory reservation + * failed + */ + +/** + * \fn DataBlob::valid() + * \brief Retrieve if a DataBlob is valid + * \return True if the memory area was correctly reserved, false otherwise + */ + +/** + * \class Serializable + * \brief Interface for serializable data types + * + * Classes that can be serialized to a binary memory buffer shall implement + * the interface defined by this class. + */ + +/** + * \fn Serializable::serialize() + * \brief Serialize data to a memory buffer + * + * Implementations of this pure virtual operation serialize the content of + * the derived class to a memory buffer. + * + * The ownership of the DataBlob containing the serialized data is returned to + * the caller, which is responsible for its life cycle management. + */ + +/** + * \fn Serializable::deserialize() + * \brief Deserialize from data in a memory buffer + * \param[in] data The memory buffer containing serialized control info data + * \param[in] len The memory buffer length in bytes + * + * + * Implementations of this pure virtual operation de-serialize the content of + * the derived class from a memory buffer. + * + * The ownership of the DataBlob \a blob containing data to de-serialize is + * passed to this operation which destroys its content after having + * de-serialized it. + * + * \return 0 on success, a negative error coder otherwise + */ + +} /* namespace libcamera */ From patchwork Tue Sep 24 17:24:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2002 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9EF7A6237C for ; Tue, 24 Sep 2019 19:23:30 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id ACB8E60009 for ; Tue, 24 Sep 2019 17:23:29 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:45 +0200 Message-Id: <20190924172503.30864-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/21] libcamera: Implement serialization helper class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:30 -0000 Define and implement a Serializer class which provides static operations used to serialize and de-serialize DataValue and DataInfo instances to and from a memory buffers. The helpers implementation define the binary serialization format to which data are dumped to and restored from. Signed-off-by: Jacopo Mondi --- src/libcamera/include/meson.build | 1 + src/libcamera/include/serializer.h | 93 +++++++ src/libcamera/meson.build | 1 + src/libcamera/serializer.cpp | 420 +++++++++++++++++++++++++++++ 4 files changed, 515 insertions(+) create mode 100644 src/libcamera/include/serializer.h create mode 100644 src/libcamera/serializer.cpp diff --git a/src/libcamera/include/meson.build b/src/libcamera/include/meson.build index 933be8543a8d..3bec594c3b3d 100644 --- a/src/libcamera/include/meson.build +++ b/src/libcamera/include/meson.build @@ -15,6 +15,7 @@ libcamera_headers = files([ 'message.h', 'pipeline_handler.h', 'process.h', + 'serializer.h', 'thread.h', 'utils.h', 'v4l2_controls.h', diff --git a/src/libcamera/include/serializer.h b/src/libcamera/include/serializer.h new file mode 100644 index 000000000000..19978bc0375f --- /dev/null +++ b/src/libcamera/include/serializer.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * serializer.h - Data serializer helpers + */ +#ifndef __LIBCAMERA_SERIALIZER_H__ +#define __LIBCAMERA_SERIALIZER_H__ + +#include +#include +#include + +#include + +#include "utils.h" + +namespace libcamera { + +class Serializer +{ +public: + static constexpr unsigned int BLOB_ALIGN_BYTES = 8; + static constexpr unsigned int BLOB_ALIGN(size_t s) + { + return ALIGN(s, BLOB_ALIGN_BYTES); + } + + /* + * These offset define the serialization format. + * Keep the total headers size 8 bytes aligned. + */ + static constexpr unsigned int VALUE_BLOB_TYPE_OFFS = 4; + static constexpr uint8_t *VALUE_BLOB_TYPE(uint8_t *b) + { + + return b + VALUE_BLOB_TYPE_OFFS; + } + + static constexpr unsigned int VALUE_BLOB_SIZE_OFFS = 8; + static constexpr uint8_t *VALUE_BLOB_SIZE(uint8_t *b) + { + return b + VALUE_BLOB_SIZE_OFFS; + } + + static constexpr unsigned int VALUE_BLOB_DATA_OFFS = 16; + static constexpr uint8_t *VALUE_BLOB_DATA(uint8_t *b) + { + return b + VALUE_BLOB_DATA_OFFS; + } + + static constexpr unsigned int INFO_BLOB_TYPE_OFFS = 4; + static constexpr uint8_t *INFO_BLOB_TYPE(uint8_t *b) + { + return b + INFO_BLOB_TYPE_OFFS; + } + + static constexpr unsigned int INFO_BLOB_SIZE_OFFS = 8; + static constexpr uint8_t *INFO_BLOB_SIZE(uint8_t *b) + { + return b + INFO_BLOB_SIZE_OFFS; + } + + static constexpr unsigned int INFO_BLOB_DATA_OFFS = 16; + static constexpr uint8_t *INFO_BLOB_DATA(uint8_t *b) + { + return b + INFO_BLOB_DATA_OFFS; + } + + using DataValueTuple = std::tuple; + using DataInfoTuple = std::tuple; + + static int serialize(unsigned int id, const DataValue &value, + uint8_t *buffer); + static DataValueTuple deserializeValue(uint8_t *buffer); + + static int serialize(unsigned int id, const DataInfo &info, + uint8_t *buffer); + static DataInfoTuple deserializeInfo(uint8_t *buffer); + + static unsigned int size(const DataValue &value); + static unsigned int size(const DataInfo &value); + +private: + static unsigned int dumpValue(const DataValue &value, DataType type, + uint8_t *b); + static DataValue loadValue(DataType type, uint8_t *b); + static DataInfo loadInfo(DataType type, uint8_t *b); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_SERIALIZER_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 973b20269943..0f6f97305e4f 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -28,6 +28,7 @@ libcamera_sources = files([ 'request.cpp', 'signal.cpp', 'serializable.cpp', + 'serializer.cpp', 'stream.cpp', 'thread.cpp', 'timer.cpp', diff --git a/src/libcamera/serializer.cpp b/src/libcamera/serializer.cpp new file mode 100644 index 000000000000..d624d277434b --- /dev/null +++ b/src/libcamera/serializer.cpp @@ -0,0 +1,420 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * serializer.h - Data serializer helpers + */ + +#include "serializer.h" + +#include + +#include + +/** + * \file serializer.h + * \brief Helper class for serialization of values and information + */ + +namespace libcamera { + +/** + * \class Serializer + * \brief Helper class that provides operations to serialize values and + * information to memory buffers + * + * The Serializer class provides helper methods to serialize to binary format + * DataValue and DataInfo associated with a numerical identifier. + * + * A data is serialized to a memory buffer using the serialize() operation. It + * is responsability of the caller to provide a pointer to an opportunely + * allocated memory area, with enough space reserved to contain the whole data + * blob representation. The memory size required to contain all serialized data + * could be esitameted by using the size() operation when iterating on them. + */ + +/** + * \var Serializer::BLOB_ALIGN_BYTES + * \brief The blob alignement, in bytes + */ + +/** + * \fn Serializer::BLOB_ALIGN() + * \brief Align a size \a s to BLOB_ALIGN_BYTES + * \param[in] s The size to align + * \return Size \a s aligned to BLOB_ALIGN_BYTES + */ + +/** + * \var Serializer::VALUE_BLOB_TYPE_OFFS + * \brief The offset from the blob start where the value type is encoded + */ + +/** + * \fn Serializer::VALUE_BLOB_TYPE() + * \brief Return the memory location where the value type is encoded in buffer + * \a b + * \param[in] b The memory buffer containing a serialized value + * \return The memory location in buffer \b where the type information is + * encoded + */ + +/** + * \var Serializer::VALUE_BLOB_SIZE_OFFS + * \brief The offset from the blob start where the value size is encoded + */ + +/** + * \fn Serializer::VALUE_BLOB_SIZE() + * \brief Return the memory location where the value size is encoded in buffer + * \a b + * \param[in] b The memory buffer containing a serialized value + * \return The memory location in buffer \b where the size information is + * encoded + */ + +/** + * \var Serializer::VALUE_BLOB_DATA_OFFS + * \brief The offset from the blob start where the value data is encoded + */ + +/** + * \fn Serializer::VALUE_BLOB_DATA() + * \brief Return the memory location where the value data is encoded in buffer + * \a b + * \param[in] b The memory buffer containing a serialized value + * \return The memory location in buffer \b where the data information is + * encoded + */ + +/** + * \var Serializer::INFO_BLOB_TYPE_OFFS + * \brief The offset from the blob start where the value type is encoded + */ + +/** + * \fn Serializer::INFO_BLOB_TYPE() + * \brief Return the memory location where the value type is encoded in buffer + * \a b + * \param[in] b The memory buffer containing a serialized value + * \return The memory location in buffer \b where the type information is + * encoded + */ + +/** + * \var Serializer::INFO_BLOB_SIZE_OFFS + * \brief The offset from the blob start where the value size is encoded + */ + +/** + * \fn Serializer::INFO_BLOB_SIZE() + * \brief Return the memory location where the value size is encoded in buffer + * \a b + * \param[in] b The memory buffer containing a serialized value + * \return The memory location in buffer \b where the size information is + * encoded + */ + +/** + * \var Serializer::INFO_BLOB_DATA_OFFS + * \brief The offset from the blob start where the value data is encoded + */ + +/** + * \fn Serializer::INFO_BLOB_DATA() + * \brief Return the memory location where the value data is encoded in buffer + * \a b + * \param[in] b The memory buffer containing a serialized value + * \return The memory location in buffer \b where the data information is + * encoded + */ + +/** + * \typedef Serializer::DataValueTuple + * \brief A tuple that contains a numeric id, a DataValue and a size + * + * DataTupleValue is used to return the content of a DataValue de-serialization + * operation. + */ + +/** + * \typedef Serializer::DataInfoTuple + * \brief A tuple that contains a numeric id, a DataInfo and a size + * + * DataTupleInfo is used to return the content of a DataInfo de-serialization + * operation. + */ + +/** + * \var Serializer::BLOB_ALIGN_BYTES + * \brief Memory alignement of the serialized data in bytes + */ + +/** + * \brief Serialize a data value into a memory buffer + * \param[in] id The identifier associated with the DataValue + * \param[in] value The DataValue to serialize + * \param[in] buffer The memory area where to serialize the data blob + * + * A data value is serialized to the following binary sections: + * - id: the identifier provided to the operation + * - type: the DataType of the DataValue provided to the operation + * - size: the size in bytes of the data contained in the DataValue provided + * the operation + * - data: the data contained in the DataValue provided to the operation + * - padding (optional): padding bytes to guarantee alignment to 64-bits + * boundary + * + * The data value is serialized to the following binary format: + * + * Bytes + * Offset: 0 4 8 16 [16 + size] + * +----+----+--------+----- ... -----+--- ... ----+ + * Entry: | id |type| size | data | padding | + * +----+----+--------+----- ... ------+--- ... ---+ + * + * \----- HEADER ----\---- DATA ----\--- PADDING ---\ + * + * The operation returns the total number of data written into \a buffer, + * which is guaranteed to be aligned to Serializer::BLOB_ALIGN_BYTES boundary. + * + * The memory buffer pointer \a b is not advanced during serialization, and is + * responsibility of the caller to advance it using the returned size to the + * next memory location where to serialize data. + * + * \return The number of bytes written in \a buffer, or a negative error code + * in case of errors + */ +int Serializer::serialize(unsigned int id, const DataValue &value, + uint8_t *buffer) +{ + if (!buffer) + return -ENOMEM; + + DataType type = value.type(); + uint8_t *b = buffer; + + *reinterpret_cast(b) = id; + *reinterpret_cast(VALUE_BLOB_TYPE(b)) = type; + *reinterpret_cast(VALUE_BLOB_SIZE(b)) = BLOB_ALIGN(value.size()); + + dumpValue(value, type, VALUE_BLOB_DATA(b)); + + return Serializer::size(value); +} + +/** + * \brief De-serialize a memory buffer to a tuple containing a DataValue + * \param[in] buffer The buffer containing data to de-serialize + * + * De-serialize a data value and its associated id from the memory buffer + * \a b. The de-serialized data are expected to be have been serialized using + * the serialize(unsigned int id, const DataValue &value, uint8_t *buffer) + * operation, which dumps data to the memory in the format known to this + * operation. + * + * The de-serialized data are returned in a tuple which contains: + * - id: the id associated with the de-serialized DataValue + * - value: the de-serialized DataValue + * - size: the size (in bytes) occupied by the serialized data in the memory + * buffer + * + * The memory buffer pointer \a b is not advanced during de-serialization, and + * it is responsibility of the caller to advance it using the returned size to + * the next memory location containing data to de-serialize. + * + * \return A tuple containing the id associated with the de-serialized data, the + * data value itself and the size of the size of the de-serialized memory area + */ +Serializer::DataValueTuple Serializer::deserializeValue(uint8_t *buffer) +{ + if (!buffer) + return {}; + + uint8_t *b = buffer; + unsigned int id = *reinterpret_cast(b); + DataType type = *reinterpret_cast(VALUE_BLOB_TYPE(b)); + size_t size = *reinterpret_cast(VALUE_BLOB_SIZE(b)); + + b = VALUE_BLOB_DATA(b); + return std::make_tuple( + std::forward(id), loadValue(type, b), + std::forward(size + VALUE_BLOB_DATA_OFFS)); +} + +/** + * \brief Serialize a data info into a memory buffer + * \param[in] id The identifier associated with the DataValue + * \param[in] info The DataInfo to serialize + * \param[in] buffer The memory area where to serialize the data blob + * + * A data info is serialized to the following binary sections: + * - id: the identifier provided to the operation + * - type: the DataType of the data this info refers to + * - size: the size in bytes of the data contained in the DataInfo provided + * to the operation + * - data: the data contained in the DataInfo provided to the operation: + * - min (DataValue of type 'type') + * - max (DataValue of type 'type') + * + * The data value is serialized to the following binary format: + * + * Bytes + * Offset: 0 4 8 16 [16 + size] + * +----+----+--------+- ... -+- ... -+ + * Entry: | id |type| size | min | max | + * +----+----+--------+- ... -+- ... -+ + * + * \----- HEADER -----\---- DATA ----\ + * + * The operation returns the total number of data written into \a buffer, + * which is guaranteed to be aligned to Serializer::BLOB_ALIGN_BYTES boundary. + * + * \return The number of bytes written in \a buffer, or a negative error code + * in case of errors + */ +int Serializer::serialize(unsigned int id, const DataInfo &info, + uint8_t *buffer) +{ + if (!buffer) + return -ENOMEM; + + DataType type = info.min().type(); + uint8_t *b = buffer; + + *reinterpret_cast(b) = id; + *reinterpret_cast(INFO_BLOB_TYPE(b)) = type; + *reinterpret_cast(INFO_BLOB_SIZE(b)) = BLOB_ALIGN(DataSize[type]) + + BLOB_ALIGN(DataSize[type]); + + b = INFO_BLOB_DATA(b); + b += dumpValue(info.min(), type, b); + b += dumpValue(info.max(), type, b); + + return Serializer::size(info); +} + +/** + * \brief De-serialize a memory buffer to a tuple containing a DataInfo + * \param[in] buffer The buffer containing data to de-serialize + * + * De-serialize a data value and its associated id from the memory buffer + * \a b. The de-serialized data are expected to be have been serialized using + * the serialize(unsigned int id, const DataInfo &info, uint8_t *buffer) + * operation, which dumps data to the memory in the format known to this + * operation. + * + * The de-serialized data are returned in a tuple which contains: + * - id: the id associated with the de-serialized DataValue + * - info: the de-serialized DataInfo + * - size: the size (in bytes) occupied by the serialized data in the memory + * buffer + * + * The memory buffer pointer \a b is not advanced during de-serialization, and + * it is responsibility of the caller to advance it using the returned size to + * the next memory location containing data to de-serialize. + * + * \return A tuple containing the id associated with the de-serialized data, the + * data value itself and the size of the size of the de-serialized memory area + */ +Serializer::DataInfoTuple Serializer::deserializeInfo(uint8_t *buffer) +{ + if (!buffer) + return {}; + + uint8_t *b = buffer; + unsigned int id = *reinterpret_cast(b); + DataType type = *reinterpret_cast((INFO_BLOB_TYPE(b))); + size_t size = *reinterpret_cast(INFO_BLOB_SIZE(b)); + + b = INFO_BLOB_DATA(b); + return std::make_tuple( + std::forward(id), loadInfo(type, b), + std::forward(size + INFO_BLOB_DATA_OFFS)); +} + +/** + * \brief Calculate the size of the data value once serialized to binary form + * + * Calculate the data value size in bytes comprising header, data and padding + * bytes to guarantee alignement to 64 bits boundary. + * + * The returned size is the actual byte size occupied by the data blob once + * serialized to a memory buffer. + * + * \return The blob size in bytes, aligned to Serializer::BLOB_ALIGN_BYTES + * boundary + */ +unsigned int Serializer::size(const DataValue &value) +{ + return VALUE_BLOB_DATA_OFFS + BLOB_ALIGN(value.size()); +} + +/** + * \brief Calculate the size of the data info once serialized to binary form + * + * Calculate the data info size in bytes comprising header, data and padding + * bytes to guarantee alignement to 64 bits boundary. + * + * The returned size is the actual byte size occupied by the data blob once + * serialized to a memory buffer. + * + * \return The blob size in bytes, aligned to Serializer::BLOB_ALIGN_BYTES + * boundary + */ +unsigned int Serializer::size(const DataInfo &info) +{ + /* + * Header is aligned as well as the transported data + * + * \todo If any non-DataValue field is added to DataInfo, the + * total size of the serialized package should be aligned with the + * ALIGN() macro. + */ + DataType type = info.min().type(); + return INFO_BLOB_DATA_OFFS + BLOB_ALIGN(DataSize[type]) + + BLOB_ALIGN(DataSize[type]); +} + +unsigned int Serializer::dumpValue(const DataValue &value, DataType type, + uint8_t *b) +{ + switch (type) { + case DataTypeBool: + *reinterpret_cast(b) = value.getBool(); + break; + case DataTypeInteger: + *reinterpret_cast(b) = value.getInt(); + break; + case DataTypeInteger64: + *reinterpret_cast(b) = value.getInt64(); + break; + default: + *b = 0; + break; + } + + return DataSize[type]; +} + +DataValue Serializer::loadValue(DataType type, uint8_t *b) +{ + switch (type) { + case DataTypeBool: + return DataValue(*reinterpret_cast(b)); + case DataTypeInteger: + return DataValue(*reinterpret_cast(b)); + case DataTypeInteger64: + return DataValue(*reinterpret_cast(b)); + default: + return DataValue(); + } +} + +DataInfo Serializer::loadInfo(DataType type, uint8_t *b) +{ + return DataInfo(loadValue(type, b), + loadValue(type, b + BLOB_ALIGN(DataSize[type]))); +} + +} /* namespace libcamera */ From patchwork Tue Sep 24 17:24:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2003 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3C2ED62381 for ; Tue, 24 Sep 2019 19:23:31 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id CA7786000A for ; Tue, 24 Sep 2019 17:23:30 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:46 +0200 Message-Id: <20190924172503.30864-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/21] libcamera: controls: Implement ControlList serialization X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:31 -0000 Make the ControlList class implement the Serializable interface and implement the serialize() and deserialize() operations to dumps all control values registered in the list to a memory blob and to re-create a ControlList from a memory buffer. Signed-off-by: Jacopo Mondi --- include/libcamera/controls.h | 7 +++- src/libcamera/controls.cpp | 73 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index c299ed94d9e2..8a7ddc510497 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -15,6 +15,8 @@ #include #include +#include + namespace libcamera { class Camera; @@ -44,7 +46,7 @@ using ControlInfoMap = std::unordered_map; using ControlValue = DataValue; -class ControlList +class ControlList : public Serializable { private: using ControlMap = std::unordered_map; @@ -71,6 +73,9 @@ public: bool merge(const ControlList &list); + std::unique_ptr serialize() const override; + int deserialize(uint8_t *data, size_t len) override; + private: const ControlInfoMap &infoMap_; ControlMap controls_; diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index 65001259a3df..ee19eb6dc014 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -10,6 +10,7 @@ #include #include "log.h" +#include "serializer.h" #include "utils.h" /** @@ -398,4 +399,76 @@ bool ControlList::merge(const ControlList &other) return true; } +/** + * \brief Serialize a ControlList to a memory buffer + * + * Serialize the control list to a DataBlob and return the ownership + * of the blob to the caller. + * + * The memory format used to serialize each control to memory is defined by + * the Serializer helper class. + * + * \sa Serializer::serialize() + * + * \return A unique pointer to a DataBlob containing the serialized control + * list + */ +std::unique_ptr ControlList::serialize() const +{ + unsigned int bufferSize = 0; + for (auto it : controls_) + bufferSize += Serializer::size(it.second); + + std::unique_ptr blob(new DataBlob(bufferSize)); + if (!blob->valid()) + return nullptr; + + uint8_t *b = blob->data(); + for (auto it : controls_) + b += Serializer::serialize(it.first->id(), it.second, b); + + return blob; +} + +/** + * \brief De-serialize a ControlList from a memory buffer + * \param[in] data The memory buffer containing serialized control info data + * \param[in] len The memory buffer length in bytes + * + * De-serialize the content of the control list from a memory buffer. The memory + * buffer is expected to having been serialized from the + * ControlList::serialize() operation. + * + * \sa Serializer::deserializeData() + * + * \return 0 on success, a negative error code otherwise + */ +int ControlList::deserialize(uint8_t *data, size_t len) +{ + uint8_t *b = data; + size_t dataSize = 0; + + while (dataSize < len) { + unsigned int id; + DataValue value; + size_t size; + std::tie(id, value, size) = Serializer::deserializeValue(b); + + const auto info = infoMap_.find(static_cast(id)); + if (info == infoMap_.end()) { + LOG(Controls, Error) + << "Control id " << id << "not supported: " + << "Abort deserialization"; + return -EINVAL; + } + + controls_[&info->second] = value; + + dataSize += size; + b += size; + } + + return 0; +} + } /* namespace libcamera */ From patchwork Tue Sep 24 17:24:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2004 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C338D62378 for ; Tue, 24 Sep 2019 19:23:31 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 5B78560005 for ; Tue, 24 Sep 2019 17:23:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:47 +0200 Message-Id: <20190924172503.30864-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/21] libcamera: controls: Make ControlInfoMap a class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:31 -0000 Make a class out of ControlInfoMap to be able to serialize its content. Signed-off-by: Jacopo Mondi --- include/libcamera/controls.h | 24 +++++++++- src/libcamera/controls.cpp | 68 ++++++++++++++++++++++++++++- src/libcamera/pipeline/uvcvideo.cpp | 4 +- src/libcamera/pipeline/vimc.cpp | 4 +- 4 files changed, 92 insertions(+), 8 deletions(-) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index 8a7ddc510497..79731c4932ae 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -42,7 +42,29 @@ private: const struct ControlMetadata *meta_; }; -using ControlInfoMap = std::unordered_map; +class ControlInfoMap +{ +private: + using InfoMap = std::unordered_map; + +public: + using iterator = InfoMap::iterator; + using const_iterator = InfoMap::const_iterator; + + iterator begin() { return map_.begin(); } + iterator end() { return map_.end(); } + const_iterator begin() const { return map_.begin(); } + const_iterator end() const { return map_.end(); } + + iterator find(ControlId id) { return map_.find(id); } + const_iterator find(ControlId id) const { return map_.find(id); } + + void emplace(const ControlId id, const DataValue &min, + const DataValue &max); + +private: + InfoMap map_; +}; using ControlValue = DataValue; diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index ee19eb6dc014..ec7ac7ba9ed6 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -169,10 +169,76 @@ std::string ControlInfo::toString() const } /** - * \typedef ControlInfoMap + * \class ControlInfoMap * \brief A map of ControlId to ControlInfo */ +/** + * \typedef ControlInfoMap::iterator + * \brief Iterator for the controls contained within the list + */ + +/** + * \typedef ControlInfoMap::const_iterator + * \brief Const iterator for the controls contained within the list + */ + +/** + * \fn iterator ControlInfoMap::begin() + * \brief Retrieve an iterator to the first Control in the list + * \return An iterator to the first Control in the list + */ + +/** + * \fn const_iterator ControlInfoMap::begin() const + * \brief Retrieve a const_iterator to the first Control in the list + * \return A const_iterator to the first Control in the list + */ + +/** + * \fn iterator ControlInfoMap::end() + * \brief Retrieve an iterator pointing to the past-the-end control in the list + * \return An iterator to the element following the last control in the list + */ + +/** + * \fn const_iterator ControlInfoMap::end() const + * \brief Retrieve a const iterator pointing to the past-the-end control in the + * list + * \return A const iterator to the element following the last control in the + * list + */ + +/** + * \fn iterator ControlInfoMap::find(ControlId id) + * \brief Find ControlInfo with \a id + * \param id The control identifier + * \return An interator to the ControlInfo with key \a id or the + * past-the-end iterator if no element with key \a id exists + */ + +/** + * \fn const_iterator ControlInfoMap::find(ControlId id) const + * \brief Find ControlInfo with \a id + * \param id The control identifier + * \return A const interator to the ControlInfo with key \a id or the + * past-the-end iterator if no element with key \a id exists + */ + +/** + * \brief Insert a new element in the map constructed in-place + * \param[in] id The control ID + * \param[in] min The control minimum value + * \param[in] max The control maximum value + */ +void ControlInfoMap::emplace(const ControlId id, const DataValue &min, + const DataValue &max) +{ + map_.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple(id, min, max)); +} + /** * \typedef ControlValue * \brief A control value stored in the ControlList class diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 8965210550d2..02455d1ac675 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -374,9 +374,7 @@ int UVCCameraData::init(MediaEntity *entity) continue; } - controlInfo_.emplace(std::piecewise_construct, - std::forward_as_tuple(id), - std::forward_as_tuple(id, info.min(), info.max())); + controlInfo_.emplace(id, info.min(), info.max()); } return 0; diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index f26a91f86ec1..5515704df14c 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -443,9 +443,7 @@ int VimcCameraData::init(MediaDevice *media) continue; } - controlInfo_.emplace(std::piecewise_construct, - std::forward_as_tuple(id), - std::forward_as_tuple(id, info.min(), info.max())); + controlInfo_.emplace(id, info.min(), info.max()); } return 0; From patchwork Tue Sep 24 17:24:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2005 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 84DBE62378 for ; Tue, 24 Sep 2019 19:23:32 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 2E07460005 for ; Tue, 24 Sep 2019 17:23:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:48 +0200 Message-Id: <20190924172503.30864-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/21] libcamera: controls: Implement ControlInfoMap serialization X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:32 -0000 Make ControlInfoMap class implement the Serializable interface and implement the serializable() and deserialize() operations that dumps all control info to a memory blob and re-create a ControlInfoMap from a memory buffer. Signed-off-by: Jacopo Mondi --- include/libcamera/controls.h | 5 ++- src/libcamera/controls.cpp | 67 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index 79731c4932ae..a5b5f245ef60 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -42,7 +42,7 @@ private: const struct ControlMetadata *meta_; }; -class ControlInfoMap +class ControlInfoMap : public Serializable { private: using InfoMap = std::unordered_map; @@ -62,6 +62,9 @@ public: void emplace(const ControlId id, const DataValue &min, const DataValue &max); + std::unique_ptr serialize() const override; + int deserialize(uint8_t *data, size_t len) override; + private: InfoMap map_; }; diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index ec7ac7ba9ed6..4d51efd53fab 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -239,6 +239,73 @@ void ControlInfoMap::emplace(const ControlId id, const DataValue &min, std::forward_as_tuple(id, min, max)); } +/** + * \brief Serialize a ControlInfoMap to a memory buffer + * + * Serialize the control info map to a DataBlob and return the ownership + * of the blob to the caller. + * + * The memory format used to serialize each control to memory is defined by + * the Serializer helper class. + * + * \sa Serializer::serialize() + * + * \return A unique pointer to a DataBlob containing the serialized control + * info map + */ +std::unique_ptr ControlInfoMap::serialize() const +{ + unsigned int bufferSize = 0; + for (auto it : map_) + bufferSize += Serializer::size(it.second); + + std::unique_ptr blob(new DataBlob(bufferSize)); + if (!blob->valid()) + return nullptr; + + uint8_t *b = blob->data(); + for (auto it : map_) + b += Serializer::serialize(it.first, it.second, b); + + return blob; +} + +/** + * \brief De-serialize a ControlInfoMap from a memory buffer + * \param[in] data The memory buffer containing serialized control info data + * \param[in] len The memory buffer length in bytes + * + * De-serialize the content of the control info map from a memory buffer. The + * memory buffer is expected to having been serialized from the + * ControlInfoMap::serialize() operation. + * + * \sa Serializer::deserializeInfo() + * + * \return 0 on success, a negative error code otherwise + */ +int ControlInfoMap::deserialize(uint8_t *data, size_t len) +{ + uint8_t *b = data; + size_t dataSize = 0; + + while (dataSize < len) { + unsigned int id; + DataInfo info; + size_t size; + std::tie(id, info, size) = Serializer::deserializeInfo(b); + + ControlId cId = static_cast(id); + map_.emplace(std::piecewise_construct, + std::forward_as_tuple(cId), + std::forward_as_tuple(cId, info.min(), info.max())); + + dataSize += size; + b += size; + } + + return 0; +} + /** * \typedef ControlValue * \brief A control value stored in the ControlList class From patchwork Tue Sep 24 17:24:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2006 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 22E2960BCF for ; Tue, 24 Sep 2019 19:23:33 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id B039D60005 for ; Tue, 24 Sep 2019 17:23:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:49 +0200 Message-Id: <20190924172503.30864-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/21] libcamera: v4l2_controls: Make V4L2Control a DataValue X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:33 -0000 In order to be able to easily serialize a V4L2ControlList which contains controls, make the V4L2Control class a DataValue. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_controls.h | 11 ++++------ src/libcamera/pipeline/uvcvideo.cpp | 2 +- src/libcamera/pipeline/vimc.cpp | 2 +- src/libcamera/v4l2_controls.cpp | 29 +-------------------------- src/libcamera/v4l2_device.cpp | 8 ++++---- 5 files changed, 11 insertions(+), 41 deletions(-) diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h index 27b855f3407f..8b1a23f37204 100644 --- a/src/libcamera/include/v4l2_controls.h +++ b/src/libcamera/include/v4l2_controls.h @@ -32,21 +32,18 @@ private: using V4L2ControlInfoMap = std::map; -class V4L2Control +class V4L2Control : public DataValue { public: V4L2Control(unsigned int id, int value = 0) - : id_(id), value_(value) {} - - DataType type() const { return value_.type(); } - int64_t value() const { return value_.getInt64(); } - void setValue(int64_t value) { value_ = value; } + : DataValue(value), id_(id) + { + } unsigned int id() const { return id_; } private: unsigned int id_; - DataValue value_; }; class V4L2ControlList diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 02455d1ac675..6c7238e8a245 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -264,7 +264,7 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) LOG(UVC, Debug) << "Setting control 0x" << std::hex << std::setw(8) << ctrl.id() << std::dec - << " to " << ctrl.value(); + << " to " << ctrl.getInt(); int ret = data->video_->setControls(&controls); if (ret) { diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 5515704df14c..80a71f7cd5fd 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -308,7 +308,7 @@ int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request) LOG(VIMC, Debug) << "Setting control 0x" << std::hex << std::setw(8) << ctrl.id() << std::dec - << " to " << ctrl.value(); + << " to " << ctrl.getInt(); int ret = data->sensor_->setControls(&controls); if (ret) { diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp index 9bc4929cbd76..864b0be1e96f 100644 --- a/src/libcamera/v4l2_controls.cpp +++ b/src/libcamera/v4l2_controls.cpp @@ -103,8 +103,7 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl) * V4L2Device::setControls() and V4L2Device::getControls() operations. * * \todo Currently all V4L2Controls are integers. For the sake of keeping the - * implementation as simpler as possible treat all values as int64. The value() - * and setValue() operations use that single data type for now. + * implementation as simpler as possible treat all values as int64. */ /** @@ -114,32 +113,6 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl) * \param value The control value */ -/** - * \fn V4L2Control::type() - * \brief Retrieve the type of the control - * \return The control type - */ - -/** - * \fn V4L2Control::value() - * \brief Retrieve the value of the control - * - * This method returns the cached control value, initially set by - * V4L2ControlList::add() and then updated when the controls are read or - * written with V4L2Device::getControls() and V4L2Device::setControls(). - * - * \return The V4L2 control value - */ - -/** - * \fn V4L2Control::setValue() - * \brief Set the value of the control - * \param value The new V4L2 control value - * - * This method stores the control value, which will be applied to the - * device when calling V4L2Device::setControls(). - */ - /** * \fn V4L2Control::id() * \brief Retrieve the control ID this instance refers to diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index e87863af6a66..e1a715edec13 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -260,14 +260,14 @@ int V4L2Device::setControls(V4L2ControlList *ctrls) /* Set the v4l2_ext_control value for the write operation. */ switch (ctrl->type()) { case DataTypeInteger64: - v4l2Ctrls[i].value64 = ctrl->value(); + v4l2Ctrls[i].value64 = ctrl->getInt(); break; default: /* * \todo To be changed when support for string and * compound controls will be added. */ - v4l2Ctrls[i].value = ctrl->value(); + v4l2Ctrls[i].value = ctrl->getInt64(); break; } } @@ -386,14 +386,14 @@ void V4L2Device::updateControls(V4L2ControlList *ctrls, switch (ctrl->type()) { case DataTypeInteger64: - ctrl->setValue(v4l2Ctrls[i].value64); + ctrl->set(static_cast(v4l2Ctrls[i].value64)); break; default: /* * \todo To be changed when support for string and * compound controls will be added. */ - ctrl->setValue(v4l2Ctrls[i].value); + ctrl->set(static_cast(v4l2Ctrls[i].value)); break; } } From patchwork Tue Sep 24 17:24:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2007 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A5AC162379 for ; Tue, 24 Sep 2019 19:23:33 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 4DA0E60005 for ; Tue, 24 Sep 2019 17:23:33 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:50 +0200 Message-Id: <20190924172503.30864-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/21] libcamera: v4l2_controls: Implement V4L2ControlList serialization X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:34 -0000 Make V4L2ControlList implement the Serializable interface and implement control list serialization and de-serialization operations. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_controls.h | 6 ++- src/libcamera/v4l2_controls.cpp | 68 +++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h index 8b1a23f37204..739f9f131923 100644 --- a/src/libcamera/include/v4l2_controls.h +++ b/src/libcamera/include/v4l2_controls.h @@ -17,6 +17,7 @@ #include #include +#include namespace libcamera { @@ -46,7 +47,7 @@ private: unsigned int id_; }; -class V4L2ControlList +class V4L2ControlList : public Serializable { public: using iterator = std::vector::iterator; @@ -66,6 +67,9 @@ public: V4L2Control *getByIndex(unsigned int index); V4L2Control *operator[](unsigned int id); + std::unique_ptr serialize() const override; + int deserialize(uint8_t *data, size_t len) override; + private: std::vector controls_; }; diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp index 864b0be1e96f..b386d313bc4a 100644 --- a/src/libcamera/v4l2_controls.cpp +++ b/src/libcamera/v4l2_controls.cpp @@ -7,6 +7,10 @@ #include "v4l2_controls.h" +#include + +#include "serializer.h" + /** * \file v4l2_controls.h * \brief Support for V4L2 Controls using the V4L2 Extended Controls APIs @@ -255,4 +259,68 @@ V4L2Control *V4L2ControlList::operator[](unsigned int id) return nullptr; } +/** + * \brief Serialize a V4L2ControlList to a memory buffer + * + * Serialize the control list to a DataBlob and return the ownership + * of the blob to the caller. + * + * The memory format used to serialize each control to memory is defined by + * the Serializer helper class. + * + * \sa Serializer::serialize() + * + * \return A unique pointer to a DataBlob containing the serialized control + * list + */ +std::unique_ptr V4L2ControlList::serialize() const +{ + unsigned int bufferSize = 0; + for (auto it : controls_) + bufferSize += Serializer::size(it); + + std::unique_ptr blob(new DataBlob(bufferSize)); + if (!blob->valid()) + return nullptr; + + uint8_t *b = blob->data(); + for (auto it : controls_) + b += Serializer::serialize(it.id(), it, b); + + return blob; +} + +/** + * \brief De-serialize a V4L2ControlList from a memory buffer + * \param[in] data The memory buffer containing serialized control info data + * \param[in] len The memory buffer length in bytes + * + * De-serialize the content of the control list from a memory buffer. The memory + * buffer is expected to having been serialized from the + * V4L2ControlList::serialize() operation. + * + * \sa Serializer::deserializeData() + * + * \return 0 on success, a negative error code otherwise + */ +int V4L2ControlList::deserialize(uint8_t *data, size_t len) +{ + uint8_t *b = data; + size_t dataSize = 0; + + while (dataSize < len) { + unsigned int id; + DataValue value; + size_t size; + std::tie(id, value, size) = Serializer::deserializeValue(b); + + add(id, value.getInt()); + + dataSize += size; + b += size; + } + + return 0; +} + } /* namespace libcamera */ From patchwork Tue Sep 24 17:24:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2008 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4A9BE62379 for ; Tue, 24 Sep 2019 19:23:34 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id D546960006 for ; Tue, 24 Sep 2019 17:23:33 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:51 +0200 Message-Id: <20190924172503.30864-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/21] libcamera: v4l2_controls: Make V4L2ControlInfoMap a class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:34 -0000 Make V4L2ControlInfoMap a class to be able to serialize its content. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_controls.h | 25 ++++++++- src/libcamera/v4l2_controls.cpp | 79 ++++++++++++++++++++++++++- src/libcamera/v4l2_device.cpp | 3 +- 3 files changed, 103 insertions(+), 4 deletions(-) diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h index 739f9f131923..5b583b9dfda6 100644 --- a/src/libcamera/include/v4l2_controls.h +++ b/src/libcamera/include/v4l2_controls.h @@ -24,6 +24,8 @@ namespace libcamera { class V4L2ControlInfo : public DataInfo { public: + V4L2ControlInfo(unsigned int id, const DataValue &min = 0, + const DataValue &max = 0); V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl); unsigned int id() const { return id_; } @@ -31,7 +33,28 @@ private: unsigned int id_; }; -using V4L2ControlInfoMap = std::map; +class V4L2ControlInfoMap +{ +private: + using InfoMap = std::map; + +public: + using iterator = InfoMap::iterator; + using const_iterator = InfoMap::const_iterator; + + iterator begin() { return map_.begin(); } + iterator end() { return map_.end(); } + const_iterator begin() const { return map_.begin(); } + const_iterator end() const { return map_.end(); } + + iterator find(unsigned int id) { return map_.find(id); } + const_iterator find(unsigned int id) const { return map_.find(id); } + + void emplace(unsigned int id, const struct v4l2_query_ext_ctrl &ctrl); + +private: + InfoMap map_; +}; class V4L2Control : public DataValue { diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp index b386d313bc4a..c046f88bc7d3 100644 --- a/src/libcamera/v4l2_controls.cpp +++ b/src/libcamera/v4l2_controls.cpp @@ -68,6 +68,18 @@ namespace libcamera { * the first time the control information is accessed. */ +/** + * \brief Contruct a V4L2ControlInfo from with a min and max values + * \param[in] id The v4l2 control id + * \param[in] min The v4l2 control minimum value + * \param[in] max The v4l2 control maximum value + */ +V4L2ControlInfo::V4L2ControlInfo(unsigned int id, const DataValue &min, + const DataValue &max) + : DataInfo(min, max), id_(id) +{ +} + /** * \brief Construct a V4L2ControlInfo from a struct v4l2_query_ext_ctrl * \param ctrl The struct v4l2_query_ext_ctrl as returned by the kernel @@ -86,10 +98,75 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl) */ /** - * \typedef V4L2ControlInfoMap + * \class V4L2ControlInfoMap * \brief A map of control ID to V4L2ControlInfo */ +/** + * \typedef V4L2ControlInfoMap::iterator + * \brief Iterator for the controls contained within the list + */ + +/** + * \typedef V4L2ControlInfoMap::const_iterator + * \brief Const iterator for the controls contained within the list + */ + +/** + * \fn iterator V4L2ControlInfoMap::begin() + * \brief Retrieve an iterator to the first control in the list + * \return An iterator to the first Control in the list + */ + +/** + * \fn const_iterator V4L2ControlInfoMap::begin() const + * \brief Retrieve a const_iterator to the first control in the list + * \return A const_iterator to the first Control in the list + */ + +/** + * \fn iterator V4L2ControlInfoMap::end() + * \brief Retrieve an iterator pointing to the past-the-end control in the list + * \return An iterator to the element following the last control in the list + */ + +/** + * \fn const_iterator V4L2ControlInfoMap::end() const + * \brief Retrieve a const iterator pointing to the past-the-end control in the + * list + * \return A const iterator to the element following the last control in the + * list + */ + +/** + * \fn iterator V4L2ControlInfoMap::find(unsigned int id) + * \brief Find V4L2ControlInfo with \a id + * \param id The control identifier + * \return An interator to the V4L2ControlInfo with key \a id or the + * past-the-end iterator if no element with key \a id exists + */ + +/** + * \fn const_iterator V4L2ControlInfoMap::find(unsigned int id) const + * \brief Find V4L2ControlInfo with \a id + * \param id The control identifier + * \return A const interator to the V4L2ControlInfo with key \a id or the + * past-the-end iterator if no element with key \a id exists + */ + +/** + * \brief Insert a new element in the map constructed in-place + * \param[in] id The control identifier + * \param[in] ctrl The v4l2_query_ext_ctrl containing info on the control + */ +void V4L2ControlInfoMap::emplace(unsigned int id, + const struct v4l2_query_ext_ctrl &ctrl) +{ + map_.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple(ctrl)); +} + /** * \class V4L2Control * \brief A V4L2 control value diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index e1a715edec13..f89f4cd6c505 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -364,8 +364,7 @@ void V4L2Device::listControls() continue; } - V4L2ControlInfo info(ctrl); - controls_.emplace(ctrl.id, info); + controls_.emplace(ctrl.id, ctrl); } } From patchwork Tue Sep 24 17:24:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2009 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CE04262387 for ; Tue, 24 Sep 2019 19:23:34 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 7610D60005 for ; Tue, 24 Sep 2019 17:23:34 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:52 +0200 Message-Id: <20190924172503.30864-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/21] libcamera: v4l2_controls: Implement V4L2ControlInfoMap serialization X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:35 -0000 Make V4L2ControlInfoMap implement the serializable interface and implement the serialization and deserialization operations. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_controls.h | 5 +- src/libcamera/v4l2_controls.cpp | 66 +++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h index 5b583b9dfda6..3694bb888f2a 100644 --- a/src/libcamera/include/v4l2_controls.h +++ b/src/libcamera/include/v4l2_controls.h @@ -33,7 +33,7 @@ private: unsigned int id_; }; -class V4L2ControlInfoMap +class V4L2ControlInfoMap : public Serializable { private: using InfoMap = std::map; @@ -52,6 +52,9 @@ public: void emplace(unsigned int id, const struct v4l2_query_ext_ctrl &ctrl); + std::unique_ptr serialize() const override; + int deserialize(uint8_t *data, size_t len) override; + private: InfoMap map_; }; diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp index c046f88bc7d3..5e1db79e1b96 100644 --- a/src/libcamera/v4l2_controls.cpp +++ b/src/libcamera/v4l2_controls.cpp @@ -167,6 +167,72 @@ void V4L2ControlInfoMap::emplace(unsigned int id, std::forward_as_tuple(ctrl)); } +/** + * \brief Serialize a V4L2ControlInfoMap to a memory buffer + * + * Serialize the v4l2 control info map to a DataBlob and return the ownership + * of the blob to the caller. + * + * The memory format used to serialize each control to memory is defined by + * the Serializer helper class. + * + * \sa Serializer::serialize() + * + * \return A unique pointer to a DataBlob containing the serialized control + * info map + */ +std::unique_ptr V4L2ControlInfoMap::serialize() const +{ + unsigned int bufferSize = 0; + for (auto it : map_) + bufferSize += Serializer::size(it.second); + + std::unique_ptr blob(new DataBlob(bufferSize)); + if (!blob->valid()) + return nullptr; + + uint8_t *b = blob->data(); + for (auto it : map_) + b += Serializer::serialize(it.first, it.second, b); + + return blob; +} + +/** + * \brief De-serialize a V4L2ControlInfoMap from a memory buffer + * \param[in] data The memory buffer containing serialized control info data + * \param[in] len The memory buffer length in bytes + * + * De-serialize the content of the control info map from a memory buffer. The + * memory buffer is expected to having been serialized from the + * V4L2ControlInfoMap::serialize() operation. + * + * \sa Serializer::deserializeInfo() + * + * \return 0 on success, a negative error code otherwise + */ +int V4L2ControlInfoMap::deserialize(uint8_t *data, size_t len) +{ + uint8_t *b = data; + size_t dataSize = 0; + + while (dataSize < len) { + unsigned int id; + DataInfo info; + size_t size; + std::tie(id, info, size) = Serializer::deserializeInfo(b); + + map_.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple(id, info.min(), info.max())); + + dataSize += size; + b += size; + } + + return 0; +} + /** * \class V4L2Control * \brief A V4L2 control value From patchwork Tue Sep 24 17:24:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2010 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4F14B6238D for ; Tue, 24 Sep 2019 19:23:35 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 0471260006 for ; Tue, 24 Sep 2019 17:23:34 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:53 +0200 Message-Id: <20190924172503.30864-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 11/21] libcamera: controls: Remove explicit from ControlInfo constructor X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:35 -0000 With more than one argument, no need for explicit keyword. Signed-off-by: Jacopo Mondi --- include/libcamera/controls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index a5b5f245ef60..0aeb01927584 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -30,7 +30,7 @@ struct ControlMetadata { class ControlInfo : public DataInfo { public: - explicit ControlInfo(ControlId id, const DataValue &min = 0, + ControlInfo(ControlId id, const DataValue &min = 0, const DataValue &max = 0); ControlId id() const { return meta_->id; } const char *name() const { return meta_->name; } From patchwork Tue Sep 24 17:24:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2011 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2EB6662378 for ; Tue, 24 Sep 2019 19:23:36 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 77B0D60006 for ; Tue, 24 Sep 2019 17:23:35 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:54 +0200 Message-Id: <20190924172503.30864-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 12/21] test: serialization: Add control serialization test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:36 -0000 Test the serialization procedure of a ControlList by manually unwrapping a serialized data blob containing controls supported by the VIMC camera and verify its content. Signed-off-by: Jacopo Mondi --- test/meson.build | 1 + test/serialization/control_list.cpp | 101 ++++++++++++ test/serialization/meson.build | 11 ++ test/serialization/serialization_test.cpp | 189 ++++++++++++++++++++++ test/serialization/serialization_test.h | 65 ++++++++ 5 files changed, 367 insertions(+) create mode 100644 test/serialization/control_list.cpp create mode 100644 test/serialization/meson.build create mode 100644 test/serialization/serialization_test.cpp create mode 100644 test/serialization/serialization_test.h diff --git a/test/meson.build b/test/meson.build index 19e3031244a3..6d43273ca112 100644 --- a/test/meson.build +++ b/test/meson.build @@ -8,6 +8,7 @@ subdir('log') subdir('media_device') subdir('pipeline') subdir('process') +subdir('serialization') subdir('stream') subdir('v4l2_subdevice') subdir('v4l2_videodevice') diff --git a/test/serialization/control_list.cpp b/test/serialization/control_list.cpp new file mode 100644 index 000000000000..2cefec0cdc00 --- /dev/null +++ b/test/serialization/control_list.cpp @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_list.cpp - Serialize and de-serialize a list of controls + */ + +#include + +#include +#include +#include + +#include "serialization_test.h" +#include "serializer.h" +#include "test.h" + +using namespace std; +using namespace libcamera; + +class ControlListSerializeTest : public SerializationTest +{ +private: + void initializeValidationMatrix() + { + valueValidationMatrix[0][0] = Saturation; + valueValidationMatrix[0][1] = DataTypeInteger; + valueValidationMatrix[0][2] = 8; + valueValidationMatrix[0][3] = 50; + valueValidationMatrix[0][4] = false; + valueValidationMatrix[1][0] = Contrast; + valueValidationMatrix[1][1] = DataTypeInteger; + valueValidationMatrix[1][2] = 8; + valueValidationMatrix[1][3] = 128; + valueValidationMatrix[1][4] = false; + valueValidationMatrix[2][0] = Brightness; + valueValidationMatrix[2][1] = DataTypeInteger; + valueValidationMatrix[2][2] = 8; + valueValidationMatrix[2][3] = 255; + valueValidationMatrix[2][4] = false; + + numCtrls_ = 3; + } + + int init() + { + return SerializationTest::init(); + } + + int run() + { + ControlList list(camera_->controls()); + + /* + * Set a 3 controls and manually unroll the serialized + * buffer to verify its content. + * + * \todo Test less trivial control types once we have them. + */ + list[Brightness] = 255; + list[Contrast] = 128; + list[Saturation] = 50; + + initializeValidationMatrix(); + + /* Serialize and verify the produced blob size. */ + std::unique_ptr blob = list.serialize(); + if (!blob) { + cerr << "Failed to serialize the control list" << endl; + return TestFail; + } + + int ret = validateValueBlobSize(blob.get()); + if (ret) + return ret; + + /* Validate each serialized data value. */ + uint8_t *b = blob->data(); + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (!validateValueBlob(b)) + return TestFail; + + b += VALUE_BLOB_SIZE; + } + + /* De-serialize a control list and re-validate it. */ + ControlList newList(camera_->controls()); + newList.deserialize(blob->data(), blob->size()); + for (auto it : newList) { + const ControlInfo *info = it.first; + ControlValue &control = it.second; + + if (!validateDataValue(info->id(), control)) + return TestFail; + } + + return TestPass; + } +}; + +TEST_REGISTER(ControlListSerializeTest) diff --git a/test/serialization/meson.build b/test/serialization/meson.build new file mode 100644 index 000000000000..511f05cbbd1f --- /dev/null +++ b/test/serialization/meson.build @@ -0,0 +1,11 @@ +serialization_tests = [ + [ 'control_list', 'control_list.cpp' ], +] + +foreach t : serialization_tests + exe = executable(t[0], [t[1], 'serialization_test.cpp'], + dependencies : libcamera_dep, + link_with : test_libraries, + include_directories : test_includes_internal) + test(t[0], exe, suite : 'serialization', is_parallel : true) +endforeach diff --git a/test/serialization/serialization_test.cpp b/test/serialization/serialization_test.cpp new file mode 100644 index 000000000000..8db70bb1de02 --- /dev/null +++ b/test/serialization/serialization_test.cpp @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * serialization_test.cpp - Base class for serialization tests + */ + +#include "serialization_test.h" + +#include + +#include +#include +#include + +#include "test.h" +#include "serializer.h" + +using namespace std; +using namespace libcamera; + +SerializationTest::SerializationTest() + : sensor_(nullptr), numCtrls_(0), cm_(nullptr) +{ +} + +int SerializationTest::init() +{ + cm_ = new CameraManager(); + + if (cm_->start()) { + cerr << "Failed to start camera manager" << endl; + return TestFail; + } + + camera_ = cm_->get("VIMC Sensor B"); + if (!camera_) { + cerr << "Can not find VIMC camera" << endl; + return TestSkip; + } + + return TestPass; +} + +void SerializationTest::cleanup() +{ + delete sensor_; + + if (camera_) { + camera_->release(); + camera_.reset(); + } + + cm_->stop(); + delete cm_; +} + +int SerializationTest::initSubdevice() +{ + enumerator_ = DeviceEnumerator::create(); + if (!enumerator_) { + cerr << "Failed to create device enumerator" << endl; + return TestFail; + } + + if (enumerator_->enumerate()) { + cerr << "Failed to enumerate media devices" << endl; + return TestFail; + } + + DeviceMatch dm("vimc"); + media_ = enumerator_->search(dm); + if (!media_) { + cerr << "Unable to find \'vimc\' media device node" << endl; + return TestSkip; + } + + sensor_ = V4L2Subdevice::fromEntityName(media_.get(), "Sensor B"); + if (sensor_->open()) { + cerr << "Unable to open video subdevice \"Sensor B\"" + << endl; + return TestFail; + } + + return TestPass; +} + +int SerializationTest::validateValueBlobSize(DataBlob *blob) +{ + size_t blobSize = blob->size(); + if (blobSize % Serializer::BLOB_ALIGN_BYTES) { + cerr << "Serialized control list has incorrect alignement" + << endl; + return TestFail; + } + + size_t expectedSize = VALUE_BLOB_SIZE * numCtrls_; + if (blobSize != expectedSize) { + cerr << "Serialized control list has incorrect size: " + << " expected size " << expectedSize + << " got " << blobSize << endl; + return TestFail; + } + + return TestPass; +} + +bool SerializationTest::validateValueBlob(uint8_t *blob) +{ + uint32_t id = *(reinterpret_cast(blob)); + uint32_t type = *(reinterpret_cast(Serializer::VALUE_BLOB_TYPE(blob))); + uint32_t size = *(reinterpret_cast(Serializer::VALUE_BLOB_SIZE(blob))); + uint32_t value = *(reinterpret_cast(Serializer::VALUE_BLOB_DATA(blob))); + bool found = false; + + cout << "Testing serialized control: " << id << " - " + << type << " - " << size << " - " << value << endl; + + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (valueValidationMatrix[i][VALUE_CTRL_ID] != id) + continue; + + found = true; + + unsigned int *entry = valueValidationMatrix[i]; + if (entry[VALUE_CTRL_FLAG]) { + cerr << "The control with id " << id + << " has been serialized twice" << endl; + return false; + } + entry[VALUE_CTRL_FLAG] = true; + + if (entry[VALUE_CTRL_TYPE] != type || + entry[VALUE_CTRL_SIZE] != size || + entry[VALUE_CTRL_VALUE] != value) { + cerr << "The control with id " << id + << " has been wrongly serialized" << endl; + return false; + } + } + + if (!found) { + cerr << "Non-existing control with id " << id << endl; + return false; + } + + cout << "Serialization of control: " << id << " = Success." + << endl; + + return true; +} + +bool SerializationTest::validateDataValue(unsigned int id, const DataValue &dataValue) +{ + uint32_t value = dataValue.getInt(); + DataType type = dataValue.type(); + size_t dataSize = DataSize[type]; + size_t size = dataValue.size(); + bool found = false; + + cout << "Testing de-serialized control: " << id << " - " + << type << " - " << size << " - " << value << endl; + + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (valueValidationMatrix[i][VALUE_CTRL_ID] != id) + continue; + + found = true; + + unsigned int *entry = valueValidationMatrix[i]; + if (entry[VALUE_CTRL_TYPE] != dataValue.type() || + dataSize != dataValue.size() || + entry[VALUE_CTRL_VALUE] != value) { + cerr << "The control with id " << id + << " has been wrongly de-serialized" << endl; + return false; + } + } + + if (!found) { + cerr << "Non-existing control with id " << id << endl; + return false; + } + + cout << "De-serialization of control: " << id << " = Success." + << endl; + + return true; +} diff --git a/test/serialization/serialization_test.h b/test/serialization/serialization_test.h new file mode 100644 index 000000000000..87dc5a84a505 --- /dev/null +++ b/test/serialization/serialization_test.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * serialization_test.h - Base class for serialization tests + */ +#ifndef __LIBCAMERA_SERIALIZATION_TEST_H__ +#define __LIBCAMERA_SERIALIZATION_TEST_H__ + +#include +#include +#include + +#include "device_enumerator.h" +#include "media_device.h" +#include "serializer.h" +#include "test.h" +#include "v4l2_subdevice.h" + +using namespace libcamera; + +class SerializationTest : public Test +{ +public: + SerializationTest(); + +protected: + static constexpr unsigned int CTRL_MAX = 10; + + /* Value validation matrix */ + unsigned int valueValidationMatrix[3][5]; + + /* Indices on the validation matrix */ + static constexpr unsigned int VALUE_CTRL_ID = 0; + static constexpr unsigned int VALUE_CTRL_TYPE = 1; + static constexpr unsigned int VALUE_CTRL_SIZE = 2; + static constexpr unsigned int VALUE_CTRL_VALUE = 3; + static constexpr unsigned int VALUE_CTRL_FLAG = 4; + + /* + * Serialized values sizes. + * \todo Assume a serialized value is 24 bytes as all control + * values are simple integers. + */ + static constexpr unsigned int VALUE_BLOB_DATA_SIZE = 8; + static constexpr unsigned int VALUE_BLOB_SIZE = 24; + + int init(); + void cleanup(); + + int initSubdevice(); + + int validateValueBlobSize(DataBlob *blob); + bool validateValueBlob(uint8_t *dataBlob); + bool validateDataValue(unsigned int id, const DataValue &dataValue); + + std::unique_ptr enumerator_; + std::shared_ptr media_; + std::shared_ptr camera_; + V4L2Subdevice *sensor_; + unsigned int numCtrls_; + CameraManager *cm_; +}; + +#endif /* __LIBCAMERA_SERIALIZATION_TEST_H__ */ From patchwork Tue Sep 24 17:24:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2012 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0170162378 for ; Tue, 24 Sep 2019 19:23:37 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 5A31560006 for ; Tue, 24 Sep 2019 17:23:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:55 +0200 Message-Id: <20190924172503.30864-14-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 13/21] test: serialization: Add control info serialization test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:37 -0000 Test the serialization procedure of a ControlInfoMap by manually unwrapping a serialized data blob containing control info and validate them against the sensor subdevice reported ones. Signed-off-by: Jacopo Mondi --- test/serialization/control_info_list.cpp | 122 ++++++++++++++++++++++ test/serialization/meson.build | 1 + test/serialization/serialization_test.cpp | 103 ++++++++++++++++++ test/serialization/serialization_test.h | 21 ++++ 4 files changed, 247 insertions(+) create mode 100644 test/serialization/control_info_list.cpp diff --git a/test/serialization/control_info_list.cpp b/test/serialization/control_info_list.cpp new file mode 100644 index 000000000000..270f84cf7422 --- /dev/null +++ b/test/serialization/control_info_list.cpp @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_info.cpp - Serialize and de-serialize a list of control info + */ + +#include + +#include +#include +#include + +#include "device_enumerator.h" +#include "media_device.h" +#include "serializer.h" +#include "test.h" +#include "v4l2_subdevice.h" + +#include "serialization_test.h" + +using namespace std; +using namespace libcamera; + +class ControlInfoListSerializeTest : public SerializationTest +{ +public: + ControlInfoListSerializeTest() + : SerializationTest() + { + } + +private: + void initValidationMatrix() + { + const V4L2ControlInfoMap &controls = sensor_->controls(); + + unsigned int i = 0; + for (const auto &ctrl : controls) { + unsigned int v4l2Id = ctrl.first; + const V4L2ControlInfo &info = ctrl.second; + ControlId id; + + switch (v4l2Id) { + case V4L2_CID_BRIGHTNESS: + id = Brightness; + break; + case V4L2_CID_CONTRAST: + id = Contrast; + break; + case V4L2_CID_SATURATION: + id = Saturation; + break; + default: + continue; + } + + infoValidationMatrix[i][INFO_CTRL_ID] = id; + /* \todo Assume all controls have integers values. */ + infoValidationMatrix[i][INFO_CTRL_MIN] = info.min().getInt(); + infoValidationMatrix[i][INFO_CTRL_MAX] = info.max().getInt(); + infoValidationMatrix[i][INFO_CTRL_FLAG] = 0; + + numCtrls_++; + i++; + } + } + + int init() + { + int ret = SerializationTest::init(); + if (ret != TestPass) + return ret; + + ret = initSubdevice(); + if (ret < 0) + return ret; + + initValidationMatrix(); + + return TestPass; + } + + int run() + { + const ControlInfoMap &controls = camera_->controls(); + + std::unique_ptr blob = controls.serialize(); + if (!blob) { + cerr << "Failed to serialize the control info" << endl; + return TestFail; + } + + int ret = validateInfoBlobSize(blob.get()); + if (ret != TestPass) + return ret; + + /* Validate each serialized info data. */ + uint8_t *b = blob->data(); + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (!validateInfoBlob(b)) + return TestFail; + + b += INFO_BLOB_SIZE; + } + + /* De-serialize a control info list and re-validate it. */ + ControlInfoMap newInfoMap; + newInfoMap.deserialize(blob->data(), blob->size()); + for (auto it : newInfoMap) { + ControlId id = it.first; + ControlInfo &info = it.second; + + if (!validateInfoValue(id, info)) + return TestFail; + } + + return TestPass; + } +}; + +TEST_REGISTER(ControlInfoListSerializeTest) diff --git a/test/serialization/meson.build b/test/serialization/meson.build index 511f05cbbd1f..510bd8c30d38 100644 --- a/test/serialization/meson.build +++ b/test/serialization/meson.build @@ -1,5 +1,6 @@ serialization_tests = [ [ 'control_list', 'control_list.cpp' ], + [ 'control_info_list', 'control_info_list.cpp' ], ] foreach t : serialization_tests diff --git a/test/serialization/serialization_test.cpp b/test/serialization/serialization_test.cpp index 8db70bb1de02..f0a9427d7b79 100644 --- a/test/serialization/serialization_test.cpp +++ b/test/serialization/serialization_test.cpp @@ -187,3 +187,106 @@ bool SerializationTest::validateDataValue(unsigned int id, const DataValue &data return true; } + +int SerializationTest::validateInfoBlobSize(DataBlob *blob) +{ + size_t blobSize = blob->size(); + if (blobSize % Serializer::BLOB_ALIGN_BYTES) { + cerr << "Serialized control info has incorrect alignement" + << endl; + return TestFail; + } + + size_t expectedSize = INFO_BLOB_SIZE * numCtrls_; + if (blobSize != expectedSize) { + cerr << "Serialized info list has incorrect size: " + << " expected size " << expectedSize + << " got " << blobSize << endl; + return TestFail; + } + + return TestPass; +} + +bool SerializationTest::validateInfoBlob(uint8_t *info) +{ + uint32_t id = *(reinterpret_cast(info)); + uint32_t size = *(reinterpret_cast(Serializer::INFO_BLOB_SIZE(info))); + + /* Manually access min and max assuming they're 32-bits integers. */ + uint32_t min = *(reinterpret_cast(info + 16)); + uint32_t max = *(reinterpret_cast(info + 24)); + bool found = false; + + cout << "Testing serialized info: " << id << " - " + << size << " - " << min << " - " << max << endl; + + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (infoValidationMatrix[i][INFO_CTRL_ID] != id) + continue; + + found = true; + + unsigned int *entry = infoValidationMatrix[i]; + if (entry[INFO_CTRL_FLAG]) { + cerr << "The info with id " << id + << " has been serialized twice" << endl; + return false; + } + entry[INFO_CTRL_FLAG] = true; + + if (entry[INFO_CTRL_MIN] != min || + entry[INFO_CTRL_MAX] != max || + size != INFO_BLOB_DATA_SIZE) { + cerr << "The info with id " << id + << " has been wrongly serialized" << endl; + return false; + } + } + + if (!found) { + cerr << "Non-existing info with id " << id << endl; + return false; + } + + cout << "Serialization of info: " << id << " = Success." + << endl; + + return true; +} + +bool SerializationTest::validateInfoValue(unsigned int id, + const DataInfo &info) +{ + bool found = false; + uint32_t min = info.min().getInt(); + uint32_t max = info.max().getInt(); + + cout << "Testing de-serialized info: " << id + << " - " << min << " - " << max << endl; + + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (infoValidationMatrix[i][INFO_CTRL_ID] != id) + continue; + + found = true; + + unsigned int *controlValidation = infoValidationMatrix[i]; + if (controlValidation[INFO_CTRL_MIN] != min || + controlValidation[INFO_CTRL_MAX] != max) { + cerr << "The info with id " << id + << " has been wrongly serialized" << endl; + return false; + } + } + + if (!found) { + cerr << "Non-existing info with id " << id << endl; + return false; + } + + cout << "De-serialization of info: " << id << " = Success." + << endl; + + return true; +} diff --git a/test/serialization/serialization_test.h b/test/serialization/serialization_test.h index 87dc5a84a505..7085f79ac0a7 100644 --- a/test/serialization/serialization_test.h +++ b/test/serialization/serialization_test.h @@ -45,6 +45,23 @@ protected: static constexpr unsigned int VALUE_BLOB_DATA_SIZE = 8; static constexpr unsigned int VALUE_BLOB_SIZE = 24; + /* Info validation matrix */ + unsigned int infoValidationMatrix[CTRL_MAX][4]; + + /* Indices on the info validation matrix fields. */ + static constexpr unsigned int INFO_CTRL_ID = 0; + static constexpr unsigned int INFO_CTRL_MIN = 1; + static constexpr unsigned int INFO_CTRL_MAX = 2; + static constexpr unsigned int INFO_CTRL_FLAG = 3; + + /* + * Serialized info sizes. + * \todo Assume a serialized info is 32 bytes in total (header + + * DataInfo), as values are simple integers. + */ + static constexpr unsigned int INFO_BLOB_DATA_SIZE = 16; + static constexpr unsigned int INFO_BLOB_SIZE = 32; + int init(); void cleanup(); @@ -54,6 +71,10 @@ protected: bool validateValueBlob(uint8_t *dataBlob); bool validateDataValue(unsigned int id, const DataValue &dataValue); + int validateInfoBlobSize(DataBlob *blob); + bool validateInfoBlob(uint8_t *infoBlob); + bool validateInfoValue(unsigned int id, const DataInfo &dataInfo); + std::unique_ptr enumerator_; std::shared_ptr media_; std::shared_ptr camera_; From patchwork Tue Sep 24 17:24:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2013 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8B54A62378 for ; Tue, 24 Sep 2019 19:23:37 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 2C82760006 for ; Tue, 24 Sep 2019 17:23:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:56 +0200 Message-Id: <20190924172503.30864-15-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 14/21] test: serialization: Add V4L2ControlList serialization test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:37 -0000 Add test to serialize and de-serialize a V4L2ControlList. Signed-off-by: Jacopo Mondi --- test/serialization/meson.build | 1 + test/serialization/v4l2_control_list.cpp | 114 +++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 test/serialization/v4l2_control_list.cpp diff --git a/test/serialization/meson.build b/test/serialization/meson.build index 510bd8c30d38..65ecdf2cf249 100644 --- a/test/serialization/meson.build +++ b/test/serialization/meson.build @@ -1,6 +1,7 @@ serialization_tests = [ [ 'control_list', 'control_list.cpp' ], [ 'control_info_list', 'control_info_list.cpp' ], + [ 'v4l2_control_list', 'v4l2_control_list.cpp' ], ] foreach t : serialization_tests diff --git a/test/serialization/v4l2_control_list.cpp b/test/serialization/v4l2_control_list.cpp new file mode 100644 index 000000000000..338ca4dadc78 --- /dev/null +++ b/test/serialization/v4l2_control_list.cpp @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_control_list.cpp - Serialize and de-serialize a list of v4l2 controls + */ + +#include + +#include +#include +#include + +#include "test.h" +#include "serializer.h" +#include "serialization_test.h" +#include "v4l2_controls.h" + +using namespace std; +using namespace libcamera; + +class V4L2ControlListSerializeTest : public SerializationTest +{ +private: + void initializeValidationMatrix() + { + valueValidationMatrix[0][0] = V4L2_CID_SATURATION; + valueValidationMatrix[0][1] = DataTypeInteger; + valueValidationMatrix[0][2] = 8; + valueValidationMatrix[0][3] = 50; + valueValidationMatrix[0][4] = false; + valueValidationMatrix[1][0] = V4L2_CID_CONTRAST; + valueValidationMatrix[1][1] = DataTypeInteger; + valueValidationMatrix[1][2] = 8; + valueValidationMatrix[1][3] = 128; + valueValidationMatrix[1][4] = false; + valueValidationMatrix[2][0] = V4L2_CID_BRIGHTNESS; + valueValidationMatrix[2][1] = DataTypeInteger; + valueValidationMatrix[2][2] = 8; + valueValidationMatrix[2][3] = 255; + valueValidationMatrix[2][4] = false; + + numCtrls_ = 3; + } + + int init() + { + int ret = SerializationTest::init(); + if (ret != TestPass) + return ret; + + ret = initSubdevice(); + if (ret < 0) + return ret; + + return TestPass; + } + + int run() + { + V4L2ControlList controls; + + controls.add(V4L2_CID_BRIGHTNESS, 255); + controls.add(V4L2_CID_CONTRAST, 128); + controls.add(V4L2_CID_SATURATION, 50); + + int ret = sensor_->setControls(&controls); + if (ret) { + cerr << "Failed to set controls" << endl; + return ret; + } + + initializeValidationMatrix(); + + /* Serialize and verify the produced blob size. */ + std::unique_ptr blob = controls.serialize(); + if (!blob) { + cerr << "Failed to serialize the control list" << endl; + return TestFail; + } + + ret = validateValueBlobSize(blob.get()); + if (ret) + return ret; + + /* Validate each serialized data value. */ + uint8_t *b = blob->data(); + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (!validateValueBlob(b)) + return TestFail; + + b += VALUE_BLOB_SIZE; + } + + /* De-serialize a control list and re-validate it. */ + V4L2ControlList newList; + newList.deserialize(blob->data(), blob->size()); + for (auto it : newList) { + if (!validateDataValue(it.id(), it)) + return TestFail; + } + + /* Does it still work when re-applied to a subdevice? */ + ret = sensor_->setControls(&newList); + if (ret) { + cerr << "Failed to set controls" << endl; + return ret; + } + + return TestPass; + } +}; + +TEST_REGISTER(V4L2ControlListSerializeTest) From patchwork Tue Sep 24 17:24:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2014 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 170A16237C for ; Tue, 24 Sep 2019 19:23:38 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id B148A60006 for ; Tue, 24 Sep 2019 17:23:37 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:57 +0200 Message-Id: <20190924172503.30864-16-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 15/21] test: serialization: Add V4L2ControlInfoList serialization test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:38 -0000 Add test to serialize and de-serialize a V4L2ControlInfoList. Signed-off-by: Jacopo Mondi --- test/serialization/meson.build | 1 + test/serialization/v4l2_control_info_list.cpp | 107 ++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 test/serialization/v4l2_control_info_list.cpp diff --git a/test/serialization/meson.build b/test/serialization/meson.build index 65ecdf2cf249..5cb25b39583b 100644 --- a/test/serialization/meson.build +++ b/test/serialization/meson.build @@ -2,6 +2,7 @@ serialization_tests = [ [ 'control_list', 'control_list.cpp' ], [ 'control_info_list', 'control_info_list.cpp' ], [ 'v4l2_control_list', 'v4l2_control_list.cpp' ], + [ 'v4l2_control_info_list', 'v4l2_control_info_list.cpp' ], ] foreach t : serialization_tests diff --git a/test/serialization/v4l2_control_info_list.cpp b/test/serialization/v4l2_control_info_list.cpp new file mode 100644 index 000000000000..60ee9e43561b --- /dev/null +++ b/test/serialization/v4l2_control_info_list.cpp @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_control_info_list.cpp - Serialize and de-serialize a list of v4l2 + * control info + */ + +#include + +#include +#include +#include + +#include "device_enumerator.h" +#include "media_device.h" +#include "serializer.h" +#include "test.h" +#include "v4l2_subdevice.h" + +#include "serialization_test.h" + +using namespace std; +using namespace libcamera; + +class V4L2ControlInfoListSerializeTest : public SerializationTest +{ +public: + V4L2ControlInfoListSerializeTest() + : SerializationTest() + { + } + +private: + void initValidationMatrix() + { + const V4L2ControlInfoMap &controls = sensor_->controls(); + + unsigned int i = 0; + for (const auto &ctrl : controls) { + unsigned int v4l2Id = ctrl.first; + const V4L2ControlInfo &info = ctrl.second; + + infoValidationMatrix[i][INFO_CTRL_ID] = v4l2Id; + infoValidationMatrix[i][INFO_CTRL_MIN] = info.min().getInt(); + infoValidationMatrix[i][INFO_CTRL_MAX] = info.max().getInt(); + infoValidationMatrix[i][INFO_CTRL_FLAG] = 0; + + numCtrls_++; + i++; + } + } + + int init() + { + int ret = SerializationTest::init(); + if (ret != TestPass) + return ret; + + ret = initSubdevice(); + if (ret < 0) + return ret; + + initValidationMatrix(); + + return TestPass; + } + + int run() + { + const V4L2ControlInfoMap &controls = sensor_->controls(); + + std::unique_ptr blob = controls.serialize(); + if (!blob) { + cerr << "Failed to serialize the control info" << endl; + return TestFail; + } + + int ret = validateInfoBlobSize(blob.get()); + if (ret != TestPass) + return ret; + + /* Validate each serialized data info. */ + uint8_t *b = blob->data(); + for (unsigned int i = 0; i < numCtrls_; ++i) { + if (!validateInfoBlob(b)) + return TestFail; + + b += INFO_BLOB_SIZE; + } + + /* De-serialize a control info list and re-validate it. */ + V4L2ControlInfoMap newInfoMap; + newInfoMap.deserialize(blob->data(), blob->size()); + for (auto it : newInfoMap) { + unsigned int id = it.first; + V4L2ControlInfo &info = it.second; + + if (!validateInfoValue(id, info)) + return TestFail; + } + + return TestPass; + } +}; + +TEST_REGISTER(V4L2ControlInfoListSerializeTest) From patchwork Tue Sep 24 17:24:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2015 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9A10762378 for ; Tue, 24 Sep 2019 19:23:38 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 42B0560006 for ; Tue, 24 Sep 2019 17:23:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:58 +0200 Message-Id: <20190924172503.30864-17-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 16/21] ipa: Remove IPAInterface::init() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:39 -0000 From: Niklas Söderlund The function performs no useful task and will not be needed when we extend the IPA interface to process parameter and statistic buffers. Reviewed-by: Jacopo Mondi Signed-off-by: Niklas Söderlund [jacopo: Remove init() method in ipa_proxy_linux.cpp] Signed-off-by: Jacopo Mondi --- include/ipa/ipa_interface.h | 2 -- src/ipa/ipa_dummy.cpp | 10 ---------- src/libcamera/ipa_interface.cpp | 5 ----- src/libcamera/pipeline/vimc.cpp | 2 -- src/libcamera/proxy/ipa_proxy_linux.cpp | 9 --------- 5 files changed, 28 deletions(-) diff --git a/include/ipa/ipa_interface.h b/include/ipa/ipa_interface.h index 2c5eb1fd5243..9bbc4cf58ec6 100644 --- a/include/ipa/ipa_interface.h +++ b/include/ipa/ipa_interface.h @@ -13,8 +13,6 @@ class IPAInterface { public: virtual ~IPAInterface() {} - - virtual int init() = 0; }; } /* namespace libcamera */ diff --git a/src/ipa/ipa_dummy.cpp b/src/ipa/ipa_dummy.cpp index 9d0cbdc8b1ad..c833e5fb0b2d 100644 --- a/src/ipa/ipa_dummy.cpp +++ b/src/ipa/ipa_dummy.cpp @@ -5,8 +5,6 @@ * ipa_dummy.cpp - Dummy Image Processing Algorithm module */ -#include - #include #include @@ -14,16 +12,8 @@ namespace libcamera { class IPADummy : public IPAInterface { -public: - int init(); }; -int IPADummy::init() -{ - std::cout << "initializing dummy IPA!" << std::endl; - return 0; -} - /* * External IPA module interface */ diff --git a/src/libcamera/ipa_interface.cpp b/src/libcamera/ipa_interface.cpp index d7d8ca8881ef..f70d91ded1ab 100644 --- a/src/libcamera/ipa_interface.cpp +++ b/src/libcamera/ipa_interface.cpp @@ -19,9 +19,4 @@ namespace libcamera { * \brief Interface for IPA implementation */ -/** - * \fn IPAInterface::init() - * \brief Initialise the IPAInterface - */ - } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 80a71f7cd5fd..499ce59181c5 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -364,8 +364,6 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) ipa_ = IPAManager::instance()->createIPA(this, 0, 0); if (ipa_ == nullptr) LOG(VIMC, Warning) << "no matching IPA found"; - else - ipa_->init(); std::unique_ptr data = utils::make_unique(this); diff --git a/src/libcamera/proxy/ipa_proxy_linux.cpp b/src/libcamera/proxy/ipa_proxy_linux.cpp index 62fcb529e1c7..c9eaedff0224 100644 --- a/src/libcamera/proxy/ipa_proxy_linux.cpp +++ b/src/libcamera/proxy/ipa_proxy_linux.cpp @@ -26,8 +26,6 @@ public: IPAProxyLinux(IPAModule *ipam); ~IPAProxyLinux(); - int init(); - private: void readyRead(IPCUnixSocket *ipc); @@ -36,13 +34,6 @@ private: IPCUnixSocket *socket_; }; -int IPAProxyLinux::init() -{ - LOG(IPAProxy, Debug) << "initializing IPA via dummy proxy!"; - - return 0; -} - IPAProxyLinux::IPAProxyLinux(IPAModule *ipam) : proc_(nullptr), socket_(nullptr) { From patchwork Tue Sep 24 17:24:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2016 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EEAAF62391 for ; Tue, 24 Sep 2019 19:23:39 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id C6E8160005 for ; Tue, 24 Sep 2019 17:23:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:24:59 +0200 Message-Id: <20190924172503.30864-18-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 17/21] ipa: Convert the IPA API to plain C X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:40 -0000 The C++ objects that are expected to convey data through the IPA API will have associated methods that would require IPAs to link to libcamera. Even though the libcamera license allows this, suppliers of closed-source IPAs may have a different interpretation. To ease their mind and clearly separate vendor code and libcamera code, turn the IPA API to plain C. The corresponding C objects will be stored in plain C structures or have their binary format documented, removing the need for linking to libcamera code on the IPA side. This is implemented by adding two new C structures, ipa_context and ipa_operations. The ipa_operations contains function pointers for all the IPA API operations. The ipa_context represents a context of operation for the IPA, and is passed to the IPA oparations. The IPAInterface class is retained as it is easier to use than a plain C API for pipeline handlers, with a new IPAWrapper class that wraps the ipa_context and ipa_operations into and IPAInterface. On the IPA module side usage of IPAInterface may be desired for IPAs implemented in C++ that want to link to libcamera. For those IPAs, a new IPAWrapperContext helper class is introduce to wrap the IPAInterface implemented internally by the IPA module into an ipa_context and ipa_operations. Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Documentation/Doxyfile.in | 1 + Documentation/meson.build | 2 + include/ipa/ipa_interface.h | 16 ++++ src/ipa/ipa_dummy.cpp | 6 +- src/ipa/libipa/ipa_interface_wrapper.cpp | 74 ++++++++++++++++++ src/ipa/libipa/ipa_interface_wrapper.h | 29 +++++++ src/ipa/libipa/meson.build | 10 +++ src/ipa/meson.build | 3 + src/libcamera/include/ipa_context_wrapper.h | 26 +++++++ src/libcamera/include/ipa_module.h | 5 +- src/libcamera/include/meson.build | 1 + src/libcamera/ipa_context_wrapper.cpp | 52 +++++++++++++ src/libcamera/ipa_interface.cpp | 77 ++++++++++++++++++- src/libcamera/ipa_manager.cpp | 67 +++++++++++++++- src/libcamera/ipa_module.cpp | 23 +++--- src/libcamera/meson.build | 1 + src/libcamera/pipeline/vimc.cpp | 2 +- .../proxy/worker/ipa_proxy_linux_worker.cpp | 8 +- 18 files changed, 381 insertions(+), 22 deletions(-) create mode 100644 src/ipa/libipa/ipa_interface_wrapper.cpp create mode 100644 src/ipa/libipa/ipa_interface_wrapper.h create mode 100644 src/ipa/libipa/meson.build create mode 100644 src/libcamera/include/ipa_context_wrapper.h create mode 100644 src/libcamera/ipa_context_wrapper.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index 28a9c2da1ad4..fb822998a374 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -793,6 +793,7 @@ WARN_LOGFILE = INPUT = "@TOP_SRCDIR@/include/ipa" \ "@TOP_SRCDIR@/include/libcamera" \ + "@TOP_SRCDIR@/src/ipa/libipa" \ "@TOP_SRCDIR@/src/libcamera" # This tag can be used to specify the character encoding of the source files diff --git a/Documentation/meson.build b/Documentation/meson.build index 4ff3fbeb0674..9136506f5d9c 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -24,6 +24,8 @@ if doxygen.found() libcamera_ipa_api, libcamera_headers, libcamera_sources, + libipa_headers, + libipa_sources, ], output : 'api-html', command : [doxygen, doxyfile], diff --git a/include/ipa/ipa_interface.h b/include/ipa/ipa_interface.h index 9bbc4cf58ec6..f1ebac20f151 100644 --- a/include/ipa/ipa_interface.h +++ b/include/ipa/ipa_interface.h @@ -7,6 +7,21 @@ #ifndef __LIBCAMERA_IPA_INTERFACE_H__ #define __LIBCAMERA_IPA_INTERFACE_H__ +#ifdef __cplusplus +extern "C" { +#endif + +struct ipa_context { + const struct ipa_operations *ops; +}; + +struct ipa_operations { + void (*destroy)(struct ipa_context *ctx); +}; + +#ifdef __cplusplus +} + namespace libcamera { class IPAInterface @@ -16,5 +31,6 @@ public: }; } /* namespace libcamera */ +#endif #endif /* __LIBCAMERA_IPA_INTERFACE_H__ */ diff --git a/src/ipa/ipa_dummy.cpp b/src/ipa/ipa_dummy.cpp index c833e5fb0b2d..6dc9448a3f56 100644 --- a/src/ipa/ipa_dummy.cpp +++ b/src/ipa/ipa_dummy.cpp @@ -8,6 +8,8 @@ #include #include +#include "libipa/ipa_interface_wrapper.h" + namespace libcamera { class IPADummy : public IPAInterface @@ -27,9 +29,9 @@ const struct IPAModuleInfo ipaModuleInfo = { LICENSE, }; -IPAInterface *ipaCreate() +struct ipa_context *ipaCreate() { - return new IPADummy(); + return new IPAInterfaceWrapper(new IPADummy()); } }; diff --git a/src/ipa/libipa/ipa_interface_wrapper.cpp b/src/ipa/libipa/ipa_interface_wrapper.cpp new file mode 100644 index 000000000000..aacd189851c3 --- /dev/null +++ b/src/ipa/libipa/ipa_interface_wrapper.cpp @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_interface_wrapper.cpp - Image Processing Algorithm interface wrapper + */ + +#include "ipa_interface_wrapper.h" + +#include + +/** + * \file ipa_interface_wrapper.h + * \brief Image Processing Algorithm interface wrapper + */ + +namespace libcamera { + +/** + * \class IPAInterfaceWrapper + * \brief Wrap an IPAInterface and expose it as an ipa_context + * + * This class implements the ipa_context API based on a provided IPAInterface. + * It helps IPAs that implement the IPAInterface API to provide the external + * ipa_context API. + * + * To use the wrapper, an IPA module simple creates a new instance of its + * IPAInterface implementation, and passes it to the constructor of the + * IPAInterfaceWrapper. As IPAInterfaceWrapper inherits from ipa_context, the + * constructed wrapper can then be directly returned from the IPA module's + * ipaCreate() function. + * + * \code{.cpp} + * class MyIPA : public IPAInterface + * { + * ... + * }; + * + * struct ipa_context *ipaCreate() + * { + * return new IPAInterfaceWrapper(new MyIPA()); + * } + * \endcode + */ + +/** + * \brief Construct an IPAInterfaceWrapper wrapping \a interface + * \param[in] interface The interface to wrap + */ +IPAInterfaceWrapper::IPAInterfaceWrapper(IPAInterface *interface) + : ipa(interface) +{ + ops = &operations; +} + +void IPAInterfaceWrapper::destroy(struct ipa_context *_ctx) +{ + IPAInterfaceWrapper *ctx = static_cast(_ctx); + + delete ctx->ipa; + delete ctx; +} + +#ifndef __DOXYGEN__ +/* + * This construct confuses Doygen and makes it believe that all members of the + * operations is a member of IPAInterfaceWrapper. It must thus be hidden. + */ +const struct ipa_operations IPAInterfaceWrapper::operations = { + .destroy = &IPAInterfaceWrapper::destroy, +}; +#endif + +}; /* namespace libcamera */ diff --git a/src/ipa/libipa/ipa_interface_wrapper.h b/src/ipa/libipa/ipa_interface_wrapper.h new file mode 100644 index 000000000000..d2ab46f50d3c --- /dev/null +++ b/src/ipa/libipa/ipa_interface_wrapper.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_interface_wrapper.h - Image Processing Algorithm interface wrapper + */ +#ifndef __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__ +#define __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__ + +#include + +namespace libcamera { + +class IPAInterfaceWrapper : public ipa_context +{ +public: + IPAInterfaceWrapper(IPAInterface *interface); + +private: + static void destroy(struct ipa_context *ctx); + + static const struct ipa_operations operations; + + IPAInterface *ipa; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__ */ diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build new file mode 100644 index 000000000000..455bac977029 --- /dev/null +++ b/src/ipa/libipa/meson.build @@ -0,0 +1,10 @@ +libipa_headers = files([ + 'ipa_interface_wrapper.h', +]) + +libipa_sources = files([ + 'ipa_interface_wrapper.cpp', +]) + +libipa = static_library('ipa', libipa_sources, + dependencies : libcamera_dep) diff --git a/src/ipa/meson.build b/src/ipa/meson.build index f09915bc1388..6483ea66a478 100644 --- a/src/ipa/meson.build +++ b/src/ipa/meson.build @@ -1,3 +1,5 @@ +subdir('libipa') + ipa_dummy_sources = [ ['ipa_dummy', 'LGPL-2.1-or-later'], ['ipa_dummy_isolate', 'Proprietary'], @@ -9,6 +11,7 @@ foreach t : ipa_dummy_sources ipa = shared_module(t[0], 'ipa_dummy.cpp', name_prefix : '', include_directories : libcamera_includes, + link_with : libipa, install : true, install_dir : ipa_install_dir, cpp_args : '-DLICENSE="' + t[1] + '"') diff --git a/src/libcamera/include/ipa_context_wrapper.h b/src/libcamera/include/ipa_context_wrapper.h new file mode 100644 index 000000000000..12894ac6885e --- /dev/null +++ b/src/libcamera/include/ipa_context_wrapper.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_context_wrapper.h - Image Processing Algorithm context wrapper + */ +#ifndef __LIBCAMERA_IPA_CONTEXT_WRAPPER_H__ +#define __LIBCAMERA_IPA_CONTEXT_WRAPPER_H__ + +#include + +namespace libcamera { + +class IPAContextWrapper final : public IPAInterface +{ +public: + IPAContextWrapper(struct ipa_context *context); + ~IPAContextWrapper(); + +private: + struct ipa_context *ctx_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_CONTEXT_WRAPPER_H__ */ diff --git a/src/libcamera/include/ipa_module.h b/src/libcamera/include/ipa_module.h index 97737587ab3a..2028b76a1913 100644 --- a/src/libcamera/include/ipa_module.h +++ b/src/libcamera/include/ipa_module.h @@ -7,7 +7,6 @@ #ifndef __LIBCAMERA_IPA_MODULE_H__ #define __LIBCAMERA_IPA_MODULE_H__ -#include #include #include @@ -30,7 +29,7 @@ public: bool load(); - std::unique_ptr createInstance(); + struct ipa_context *createContext(); bool match(PipelineHandler *pipe, uint32_t minVersion, uint32_t maxVersion) const; @@ -45,7 +44,7 @@ private: bool loaded_; void *dlHandle_; - typedef IPAInterface *(*IPAIntfFactory)(void); + typedef struct ipa_context *(*IPAIntfFactory)(void); IPAIntfFactory ipaCreate_; int loadIPAModuleInfo(); diff --git a/src/libcamera/include/meson.build b/src/libcamera/include/meson.build index 3bec594c3b3d..1e1445a9ab2f 100644 --- a/src/libcamera/include/meson.build +++ b/src/libcamera/include/meson.build @@ -5,6 +5,7 @@ libcamera_headers = files([ 'device_enumerator_udev.h', 'event_dispatcher_poll.h', 'formats.h', + 'ipa_context_wrapper.h', 'ipa_manager.h', 'ipa_module.h', 'ipa_proxy.h', diff --git a/src/libcamera/ipa_context_wrapper.cpp b/src/libcamera/ipa_context_wrapper.cpp new file mode 100644 index 000000000000..87ff98d45c99 --- /dev/null +++ b/src/libcamera/ipa_context_wrapper.cpp @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_context_wrapper.cpp - Image Processing Algorithm context wrapper + */ + +#include "ipa_context_wrapper.h" + +#include + +/** + * \file ipa_context_wrapper.h + * \brief Image Processing Algorithm context wrapper + */ + +namespace libcamera { + +/** + * \class IPAContextWrapper + * \brief Wrap an ipa_context and expose it as an IPAInterface + * + * The IPAContextWrapper class wraps an ipa_context, provided by an IPA module, and + * exposes an IPAInterface. This mechanism is used for IPAs that are not + * isolated in a separate process to allow direct calls from pipeline handler + * using the IPAInterface API instead of the lower-level ipa_context API. + * + * The IPAInterface methods are converted to the ipa_context API by serialising + * all C++ arguments into plain C structures or byte arrays that contain no + * pointer, as required by the ipa_context API. + */ + +/** + * \brief Construct an IPAContextWrapper instance that wraps the \a context + * \param[in] context The IPA module context + * + * Ownership of the \a context is passed to the IPAContextWrapper. The context remains + * valid for the whole lifetime of the wrapper and is destroyed automatically + * with it. + */ +IPAContextWrapper::IPAContextWrapper(struct ipa_context *context) + : ctx_(context) +{ +} + +IPAContextWrapper::~IPAContextWrapper() +{ + if (ctx_) + ctx_->ops->destroy(ctx_); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/ipa_interface.cpp b/src/libcamera/ipa_interface.cpp index f70d91ded1ab..6e83aab0fb73 100644 --- a/src/libcamera/ipa_interface.cpp +++ b/src/libcamera/ipa_interface.cpp @@ -10,13 +10,88 @@ /** * \file ipa_interface.h * \brief Image Processing Algorithm interface + * + * libcamera interfaces with IPA modules through a plain C interface. IPA + * modules shall expose a public function name ipaCreate() with the following + * prototype. + * + * \code{.c} + * struct ipa_context *ipaCreate(); + * \endcode + * + * The ipaCreate() function creates an instance of an IPA context, which models + * a context of execution for the IPA. IPA modules shall support creating one + * or multiple contexts, as required by their associated pipeline handler. + * + * The IPA module operations are defined in the struct ipa_operations. An IPA + * module stores a pointer to the operations corresponding to its context in + * the ipa_context::ops field. That pointer is immutable for the lifetime of + * the context, and may be different for multiple contexts created by the same + * IPA module. + * + * All argument to ipa_operations members are Plain Old Data and are documented + * either in the form of C data types, or as a textual description for byte + * arrays that can't be expressed using C data types (such as variable-length + * arrays). IPA modules can thus use the C API without calling into libcamera + * to access the data passed to the IPA operations. + * + * The IPAInterface class is a C++ representation of the ipa_operations, using + * C++ data classes provided by libcamera. This is the API exposed to pipeline + * handlers to communicate with IPA modules. IPA modules may use the + * IPAInterface API internally if they want to benefit from the data and helper + * classes offered by libcamera. + */ + +/** + * \struct ipa_context + * \brief IPA module context of execution + * + * This structure models a context of execution for an IPA module. It is + * instantiated by the IPA module ipaCreate() function. IPA modules allocate + * context instances in an implementation-defined way, contexts shall thus be + * destroyed using the ipa_operation::destroy operation only. + * + * The ipa_context structure provides a pointer to the IPA operations. It shall + * otherwise be treated as a constant black-box cookie and passed unmodified to + * the operations defined in struct ipa_operations. + * + * IPA modules are expected to extend struct ipa_context by inheriting from it, + * either through structure embedding to model inheritance in plain C, or + * through C++ class inheritance. A simple example of the latter is available + * in the IPAContextWrapper class implementation. + * + * \var ipa_context::ops + * \brief The IPA context operations + */ + +/** + * \struct ipa_operations + * \brief IPA context operations as a set of function pointers + * + * To allow for isolation of IPA modules in separate processes, the functions + * defined in the ipa_operations structure return only data related to the + * libcamera side of the operations. In particular, error related to the + * libcamera side of the IPC may be returned. Data returned by the IPA, + * including status information, shall be provided through callbacks from the + * IPA to libcamera. + * + * \var ipa_operations::destroy + * \brief Destroy the ipa_context created by the module's ipaCreate() function */ namespace libcamera { /** * \class IPAInterface - * \brief Interface for IPA implementation + * \brief IPA module interface + * + * This pure virtual class defines a C++ API corresponding to the ipa_context + * and ipa_operations API. It is used by pipeline handlers to interact with IPA + * modules, and may be used internally in IPA modules if desired to benefit + * from the data and helper classes provided by libcamera. + * + * As for the operations defined in struct ipa_operations, the methods defined + * by this class shall not return data from the IPA. */ } /* namespace libcamera */ diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 708233e8a9c7..53c2c7859e79 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -11,6 +11,7 @@ #include #include +#include "ipa_context_wrapper.h" #include "ipa_module.h" #include "ipa_proxy.h" #include "log.h" @@ -29,6 +30,66 @@ LOG_DEFINE_CATEGORY(IPAManager) /** * \class IPAManager * \brief Manager for IPA modules + * + * The IPA module manager discovers IPA modules from disk, queries and loads + * them, and creates IPA contexts. It supports isolation of the modules in a + * separate process with IPC communication and offers a unified IPAInterface + * view of the IPA contexts to pipeline handlers regardless of whether the + * modules are isolated or loaded in the same process. + * + * Module isolation is based on the module licence. Open-source modules are + * loaded without isolation, while closed-source module are forcefully isolated. + * The isolation mechanism ensures that no code from a closed-source module is + * ever run in the libcamera process. + * + * To create an IPA context, pipeline handlers call the IPAManager::ipaCreate() + * method. For a directly loaded module, the manager calls the module's + * ipaCreate() function directly and wraps the returned context in an + * IPAContextWrapper that exposes an IPAInterface. + * + * ~~~~ + * +---------------+ + * | Pipeline | + * | Handler | + * +---------------+ + * | + * v + * +---------------+ +---------------+ + * | IPA | | Open Source | + * | Interface | | IPA Module | + * | - - - - - - - | | - - - - - - - | + * | IPA Context | ipa_operations | ipa_context | + * | Wrapper | ----------------> | | + * +---------------+ +---------------+ + * ~~~~ + * + * For an isolated module, the manager instantiates an IPAProxy which spawns a + * new process for an IPA proxy worker. The worker loads the IPA module and + * creates the IPA context. The IPAProxy alse exposes an IPAInterface. + * + * ~~~~ + * +---------------+ +---------------+ + * | Pipeline | | Closed Source | + * | Handler | | IPA Module | + * +---------------+ | - - - - - - - | + * | | ipa_context | + * v | | + * +---------------+ +---------------+ + * | IPA | ipa_operations ^ + * | Interface | | + * | - - - - - - - | +---------------+ + * | IPA Proxy | operations | IPA Proxy | + * | | ----------------> | Worker | + * +---------------+ over IPC +---------------+ + * ~~~~ + * + * The IPAInterface implemented by the IPAContextWrapper or IPAProxy is + * returned to the pipeline handler, and all interactions with the IPA context + * go the same interface regarless of process isolation. + * + * In all cases the data passed to the IPAInterface methods is serialised to + * Plain Old Data, either for the purpose of passing it to the IPA context + * plain C API, or to transmit the data to the isolated process through IPC. */ IPAManager::IPAManager() @@ -189,7 +250,11 @@ std::unique_ptr IPAManager::createIPA(PipelineHandler *pipe, if (!m->load()) return nullptr; - return m->createInstance(); + struct ipa_context *ctx = m->createContext(); + if (!ctx) + return nullptr; + + return utils::make_unique(ctx); } } /* namespace libcamera */ diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index 99d308efd47b..9f5a01418f73 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -385,13 +385,13 @@ const std::string &IPAModule::path() const /** * \brief Load the IPA implementation factory from the shared object * - * The IPA module shared object implements an IPAInterface class to be used + * The IPA module shared object implements an ipa_context object to be used * by pipeline handlers. This method loads the factory function from the - * shared object. Later, createInstance() can be called to instantiate the - * IPAInterface. + * shared object. Later, createContext() can be called to instantiate the + * ipa_context. * * This method only needs to be called successfully once, after which - * createInstance() can be called as many times as IPAInterface instances are + * createContext() can be called as many times as ipa_context instances are * needed. * * Calling this function on an invalid module (as returned by isValid()) is @@ -433,24 +433,25 @@ bool IPAModule::load() } /** - * \brief Instantiate an IPAInterface + * \brief Instantiate an IPA context * - * After loading the IPA module with load(), this method creates an - * instance of the IPA module interface. + * After loading the IPA module with load(), this method creates an instance of + * the IPA module context. Ownership of the context is passed to the caller, and + * the context shall be destroyed by calling the \ref ipa_operations::destroy + * "ipa_context::ops::destroy()" operation. * * Calling this function on a module that has not yet been loaded, or an * invalid module (as returned by load() and isValid(), respectively) is * an error. * - * \return The IPA implementation as a new IPAInterface instance on success, - * or nullptr on error + * \return The IPA context on success, or nullptr on error */ -std::unique_ptr IPAModule::createInstance() +struct ipa_context *IPAModule::createContext() { if (!valid_ || !loaded_) return nullptr; - return std::unique_ptr(ipaCreate_()); + return ipaCreate_(); } /** diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 0f6f97305e4f..3c7f890b3359 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -13,6 +13,7 @@ libcamera_sources = files([ 'event_notifier.cpp', 'formats.cpp', 'geometry.cpp', + 'ipa_context_wrapper.cpp', 'ipa_interface.cpp', 'ipa_manager.cpp', 'ipa_module.cpp', diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 499ce59181c5..9ba620a7562a 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -362,7 +362,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) return false; ipa_ = IPAManager::instance()->createIPA(this, 0, 0); - if (ipa_ == nullptr) + if (!ipa_) LOG(VIMC, Warning) << "no matching IPA found"; std::unique_ptr data = utils::make_unique(this); diff --git a/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp b/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp index a10761e52b32..07380c16e2d5 100644 --- a/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp +++ b/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp @@ -72,9 +72,9 @@ int main(int argc, char **argv) } socket.readyRead.connect(&readyRead); - std::unique_ptr ipa = ipam->createInstance(); - if (!ipa) { - LOG(IPAProxyLinuxWorker, Error) << "Failed to create IPA interface"; + struct ipa_context *ipac = ipam->createContext(); + if (!ipac) { + LOG(IPAProxyLinuxWorker, Error) << "Failed to create IPA context"; return EXIT_FAILURE; } @@ -85,5 +85,7 @@ int main(int argc, char **argv) while (1) dispatcher->processEvents(); + ipac->ops->destroy(ipac); + return 0; } From patchwork Tue Sep 24 17:25:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2017 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9A34462381 for ; Tue, 24 Sep 2019 19:23:40 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 245C960005 for ; Tue, 24 Sep 2019 17:23:39 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:25:00 +0200 Message-Id: <20190924172503.30864-19-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 18/21] POC: Add control related operation to IPA X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:40 -0000 Implement operations plumbing in the IPA interface for the init_controls() operation and queue_request() one. Signed-off-by: Jacopo Mondi --- include/ipa/ipa_interface.h | 11 +++++++++++ src/ipa/ipa_dummy.cpp | 10 ++++++++++ src/ipa/libipa/ipa_interface_wrapper.cpp | 21 +++++++++++++++++++++ src/ipa/libipa/ipa_interface_wrapper.h | 6 ++++++ src/libcamera/include/ipa_context_wrapper.h | 7 +++++++ src/libcamera/ipa_context_wrapper.cpp | 19 +++++++++++++++++++ src/libcamera/proxy/ipa_proxy_linux.cpp | 10 ++++++++++ 7 files changed, 84 insertions(+) diff --git a/include/ipa/ipa_interface.h b/include/ipa/ipa_interface.h index f1ebac20f151..d50ec41ba55e 100644 --- a/include/ipa/ipa_interface.h +++ b/include/ipa/ipa_interface.h @@ -8,6 +8,10 @@ #define __LIBCAMERA_IPA_INTERFACE_H__ #ifdef __cplusplus +#include + +#include "libcamera/controls.h" + extern "C" { #endif @@ -16,6 +20,10 @@ struct ipa_context { }; struct ipa_operations { + int (*init_controls)(struct ipa_context *ctx, uint8_t *controlInfo, + std::size_t len); + int (*queue_request)(struct ipa_context *ctx, uint8_t *controls, + std::size_t len); void (*destroy)(struct ipa_context *ctx); }; @@ -28,6 +36,9 @@ class IPAInterface { public: virtual ~IPAInterface() {} + + virtual int initControls(ControlInfoMap &controlInfo) = 0; + virtual int queueRequest(ControlList &controls) = 0; }; } /* namespace libcamera */ diff --git a/src/ipa/ipa_dummy.cpp b/src/ipa/ipa_dummy.cpp index 6dc9448a3f56..ec79ba83ce58 100644 --- a/src/ipa/ipa_dummy.cpp +++ b/src/ipa/ipa_dummy.cpp @@ -14,6 +14,16 @@ namespace libcamera { class IPADummy : public IPAInterface { +public: + int initControls(ControlInfoMap &controlInfo) override + { + return 0; + } + + int queueRequest(ControlList &controls) override + { + return 0; + } }; /* diff --git a/src/ipa/libipa/ipa_interface_wrapper.cpp b/src/ipa/libipa/ipa_interface_wrapper.cpp index aacd189851c3..bc2fb3b78ea2 100644 --- a/src/ipa/libipa/ipa_interface_wrapper.cpp +++ b/src/ipa/libipa/ipa_interface_wrapper.cpp @@ -61,12 +61,33 @@ void IPAInterfaceWrapper::destroy(struct ipa_context *_ctx) delete ctx; } +int IPAInterfaceWrapper::initControls(struct ipa_context *_ctx, + uint8_t *data, std::size_t len) +{ + IPAInterfaceWrapper *ctx = static_cast(_ctx); + + return ctx->controlInfoMap_.deserialize(data, len); +} + +int IPAInterfaceWrapper::queueRequest(struct ipa_context *_ctx, + uint8_t *data, std::size_t len) +{ + IPAInterfaceWrapper *ctx = static_cast(_ctx); + + ControlList controls(ctx->controlInfoMap_); + controls.deserialize(data, len); + + return ctx->ipa->queueRequest(controls); +} + #ifndef __DOXYGEN__ /* * This construct confuses Doygen and makes it believe that all members of the * operations is a member of IPAInterfaceWrapper. It must thus be hidden. */ const struct ipa_operations IPAInterfaceWrapper::operations = { + .init_controls = &IPAInterfaceWrapper::initControls, + .queue_request = &IPAInterfaceWrapper::queueRequest, .destroy = &IPAInterfaceWrapper::destroy, }; #endif diff --git a/src/ipa/libipa/ipa_interface_wrapper.h b/src/ipa/libipa/ipa_interface_wrapper.h index d2ab46f50d3c..ec528f624494 100644 --- a/src/ipa/libipa/ipa_interface_wrapper.h +++ b/src/ipa/libipa/ipa_interface_wrapper.h @@ -15,6 +15,10 @@ class IPAInterfaceWrapper : public ipa_context { public: IPAInterfaceWrapper(IPAInterface *interface); + static int initControls(struct ipa_context *_ctx, + uint8_t *controlInfo, std::size_t len); + static int queueRequest(struct ipa_context *_ctx, + uint8_t *controls, std::size_t len); private: static void destroy(struct ipa_context *ctx); @@ -22,6 +26,8 @@ private: static const struct ipa_operations operations; IPAInterface *ipa; + + ControlInfoMap controlInfoMap_; }; } /* namespace libcamera */ diff --git a/src/libcamera/include/ipa_context_wrapper.h b/src/libcamera/include/ipa_context_wrapper.h index 12894ac6885e..c7820290c56a 100644 --- a/src/libcamera/include/ipa_context_wrapper.h +++ b/src/libcamera/include/ipa_context_wrapper.h @@ -9,14 +9,21 @@ #include +#include + namespace libcamera { +class ControlInfoMap; +class ControlList; class IPAContextWrapper final : public IPAInterface { public: IPAContextWrapper(struct ipa_context *context); ~IPAContextWrapper(); + int initControls(ControlInfoMap &controlInfo) override; + int queueRequest(ControlList &controls) override; + private: struct ipa_context *ctx_; }; diff --git a/src/libcamera/ipa_context_wrapper.cpp b/src/libcamera/ipa_context_wrapper.cpp index 87ff98d45c99..fbb9eb1df6eb 100644 --- a/src/libcamera/ipa_context_wrapper.cpp +++ b/src/libcamera/ipa_context_wrapper.cpp @@ -8,6 +8,7 @@ #include "ipa_context_wrapper.h" #include +#include /** * \file ipa_context_wrapper.h @@ -49,4 +50,22 @@ IPAContextWrapper::~IPAContextWrapper() ctx_->ops->destroy(ctx_); } +int IPAContextWrapper::initControls(ControlInfoMap &controlInfo) +{ + std::unique_ptr blob = controlInfo.serialize(); + if (!blob->valid()) + return -EINVAL; + + return ctx_->ops->init_controls(ctx_, blob->data(), blob->size()); +} + +int IPAContextWrapper::queueRequest(ControlList &controls) +{ + std::unique_ptr blob = controls.serialize(); + if (!blob->valid()) + return -EINVAL; + + return ctx_->ops->queue_request(ctx_, blob->data(), blob->size()); +} + } /* namespace libcamera */ diff --git a/src/libcamera/proxy/ipa_proxy_linux.cpp b/src/libcamera/proxy/ipa_proxy_linux.cpp index c9eaedff0224..052f6c00afad 100644 --- a/src/libcamera/proxy/ipa_proxy_linux.cpp +++ b/src/libcamera/proxy/ipa_proxy_linux.cpp @@ -26,6 +26,16 @@ public: IPAProxyLinux(IPAModule *ipam); ~IPAProxyLinux(); + int initControls(ControlInfoMap &controlInfo) override + { + return 0; + } + + int queueRequest(ControlList &controls) override + { + return 0; + } + private: void readyRead(IPCUnixSocket *ipc); From patchwork Tue Sep 24 17:25:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2018 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1FFD262379 for ; Tue, 24 Sep 2019 19:23:41 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id C87CC60005 for ; Tue, 24 Sep 2019 17:23:40 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:25:01 +0200 Message-Id: <20190924172503.30864-20-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 19/21] POC: dummy_ipa: printout deserialize control value X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:41 -0000 Verify the content of the received controls in the dummy request queue operation. Signed-off-by: Jacopo Mondi --- src/ipa/ipa_dummy.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ipa/ipa_dummy.cpp b/src/ipa/ipa_dummy.cpp index ec79ba83ce58..e26ec16e33a1 100644 --- a/src/ipa/ipa_dummy.cpp +++ b/src/ipa/ipa_dummy.cpp @@ -5,6 +5,8 @@ * ipa_dummy.cpp - Dummy Image Processing Algorithm module */ +#include + #include #include @@ -22,6 +24,16 @@ public: int queueRequest(ControlList &controls) override { + std::cout << "Request queued to IPA!" << std::endl; + for (auto it : controls) { + const ControlInfo *info = it.first; + ControlValue &control = it.second; + + std::cout << "Deserialized control:" + << info->name() << ":" + << control.getInt() << std::endl; + } + return 0; } }; From patchwork Tue Sep 24 17:25:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2019 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9F5146239A for ; Tue, 24 Sep 2019 19:23:41 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 5476E60005 for ; Tue, 24 Sep 2019 17:23:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:25:02 +0200 Message-Id: <20190924172503.30864-21-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 20/21] POC: vimc: Initialize and set controls from request X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:42 -0000 Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/vimc.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 9ba620a7562a..d24a7304b216 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -330,6 +330,9 @@ int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request) return -ENOENT; } + if (ipa_) + ipa_->queueRequest(request->controls()); + int ret = processControls(data, request); if (ret < 0) return ret; @@ -371,6 +374,9 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) if (data->init(media)) return false; + if (ipa_) + ipa_->initControls(data->controlInfo_); + /* Create and register the camera. */ std::set streams{ &data->stream_ }; std::shared_ptr camera = Camera::create(this, "VIMC Sensor B", From patchwork Tue Sep 24 17:25:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2020 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1FA026238B for ; Tue, 24 Sep 2019 19:23:42 +0200 (CEST) X-Originating-IP: 213.45.248.89 Received: from uno.homenet.telecomitalia.it (host89-248-dynamic.45-213-r.retail.telecomitalia.it [213.45.248.89]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id C97AC60005 for ; Tue, 24 Sep 2019 17:23:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 24 Sep 2019 19:25:03 +0200 Message-Id: <20190924172503.30864-22-jacopo@jmondi.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190924172503.30864-1-jacopo@jmondi.org> References: <20190924172503.30864-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 21/21] POC: cam: Set random controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Sep 2019 17:23:42 -0000 Set random values for 3 controls supporte by the VIMC camera. Signed-off-by: Jacopo Mondi --- src/cam/capture.cpp | 12 ++++++++++++ src/cam/capture.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp index 8a939c622703..ce655c683a78 100644 --- a/src/cam/capture.cpp +++ b/src/cam/capture.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -114,6 +115,7 @@ int Capture::capture(EventLoop *loop) } for (Request *request : requests) { + setControls(request); ret = camera_->queueRequest(request); if (ret < 0) { std::cerr << "Can't queue request" << std::endl; @@ -188,5 +190,15 @@ void Capture::requestComplete(Request *request, const std::mapaddBuffer(std::move(newBuffer)); } + setControls(request); camera_->queueRequest(request); } + +void Capture::setControls(libcamera::Request *request) +{ + ControlList &controls = request->controls(); + + controls[Brightness] = rand() % 255; + controls[Saturation] = rand() % 500; + controls[Contrast] = rand() % 128; +} diff --git a/src/cam/capture.h b/src/cam/capture.h index ee0dc4211111..b98cd37eff87 100644 --- a/src/cam/capture.h +++ b/src/cam/capture.h @@ -31,6 +31,8 @@ private: void requestComplete(libcamera::Request *request, const std::map &buffers); + void setControls(libcamera::Request *request); + libcamera::Camera *camera_; libcamera::CameraConfiguration *config_;