[libcamera-devel] [PATCH 13/38] libcamera: Add IPADataSerializer
Jacopo Mondi
jacopo at jmondi.org
Wed Sep 23 17:32:18 CEST 2020
Hi Paul,
On Tue, Sep 22, 2020 at 10:35:12PM +0900, Paul Elder wrote:
> Add an IPADataSerializer which implments de/serialization of built-in
With built-in do you mean STL defined data types ?
> and libcamera data structures. This is intended to be used by the proxy
> and the proxy worker in the IPC layer.
>
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
>
> ---
> Changes in v2:
> - added serializers for all integer types, bool, and string
> - use string serializer for IPASettings serializer
> - add documentation
> - add serializer for const ControlList
> ---
> .../libcamera/internal/ipa_data_serializer.h | 1220 +++++++++++++++++
> src/libcamera/ipa_data_serializer.cpp | 154 +++
> src/libcamera/meson.build | 1 +
> 3 files changed, 1375 insertions(+)
> create mode 100644 include/libcamera/internal/ipa_data_serializer.h
> create mode 100644 src/libcamera/ipa_data_serializer.cpp
>
> diff --git a/include/libcamera/internal/ipa_data_serializer.h b/include/libcamera/internal/ipa_data_serializer.h
> new file mode 100644
> index 00000000..accd4dce
> --- /dev/null
> +++ b/include/libcamera/internal/ipa_data_serializer.h
> @@ -0,0 +1,1220 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * ipa_data_serializer.h - Image Processing Algorithm data serializer
> + */
> +#ifndef __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_H__
> +#define __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_H__
> +
> +#include <deque>
> +#include <iostream>
> +#include <tuple>
> +#include <vector>
> +
> +#include <libcamera/buffer.h>
> +#include <libcamera/control_ids.h>
> +#include <libcamera/geometry.h>
> +#include <libcamera/ipa/ipa_interface.h>
> +
> +#include "libcamera/internal/byte_stream_buffer.h"
> +#include "libcamera/internal/camera_sensor.h"
> +#include "libcamera/internal/control_serializer.h"
> +#include "libcamera/internal/log.h"
> +
> +namespace libcamera {
> +
> +LOG_DECLARE_CATEGORY(IPADataSerializer)
> +
> +template<typename T>
> +void appendUInt(std::vector<uint8_t> &vec, T val)
> +{
> + size_t byteWidth = sizeof(val);
> + for (size_t i = 0; i < byteWidth; i++)
> + vec.push_back(static_cast<uint8_t>((val >> 8*i) & 0xff));
I see in several places missing spaces around the '*' operator
I think you can also drop the & 0xff as it's implied in the cast to
uint8_t?
> +}
> +
> +template<typename T>
> +T readUInt(std::vector<uint8_t> &vec, size_t pos)
> +{
> + T ret = 0;
> + size_t byteWidth = sizeof(ret);
> + if (pos + byteWidth > vec.size())
> + return ret;
> +
> + for (size_t i = 0; i < byteWidth; i++)
> + ret |= vec[pos + i] << 8*i;
You could iterate the vector and call the below defined overload. Not
a big deal, it would be probably more confusing.
> + return ret;
> +}
> +
> +template<typename T>
> +T readUInt(std::vector<uint8_t>::iterator it)
> +{
> + T ret = 0;
> + size_t byteWidth = sizeof(ret);
> + for (size_t i = 0; i < byteWidth; i++)
> + ret |= *(it + i) << 8*i;
> + return ret;
> +}
> +
> +template<typename T>
> +class IPADataSerializer
> +{
> +#ifdef __DOXYGEN__
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(T data, ControlSerializer *cs);
> +
> + static T deserialize(std::vector<uint8_t> &data,
> + ControlSerializer *cs);
That *cs parameter is unused in all specializations but ControlList
one. We already had to face a similar issue when we implemented
ControlValue. You could define two versions of these functions one for
the ControlList case which has *cs in its signature, the other for all
the other types, without cs. The construct to do so is not nice at a
first look but effective:
https://en.cppreference.com/w/cpp/types/enable_if
I think it could be applied here, maybe on top ?
> + static T deserialize(std::vector<uint8_t>::iterator it1,
> + std::vector<uint8_t>::iterator it2,
> + ControlSerializer *cs);
> +
> + static T deserialize(std::vector<uint8_t> &data,
> + std::vector<int32_t> &fds,
> + ControlSerializer *cs);
> + static T deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + std::vector<int32_t>::iterator fds_it1,
> + std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs);
Where can I see this used ? As I wonder why this always take one
> +#endif /* __DOXYGEN__ */
> +};
> +
> +#ifndef __DOXYGEN__
> +
> +template<typename V>
> +class IPADataSerializer<std::vector<V>>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const std::vector<V> &data, ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> + std::vector<int32_t> fds_vec;
> +
> + // serialize the length
// ?
> + uint32_t vec_len = data.size();
> + appendUInt<uint32_t>(data_vec, vec_len);
> +
> + // serialize the members
> + for (auto it = data.begin(); it != data.end(); ++it) {
> + std::vector<uint8_t> dvec;
> + std::vector<int32_t> fvec;
> +
> + std::tie(dvec, fvec) =
> + IPADataSerializer<V>::serialize(*it, cs);
> +
> + appendUInt<uint32_t>(data_vec, dvec.size());
> + appendUInt<uint32_t>(data_vec, fvec.size());
> +
> + data_vec.insert(data_vec.end(), dvec.begin(), dvec.end());
> + fds_vec.insert(fds_vec.end(), fvec.begin(), fvec.end());
> + }
> +
> + return {data_vec, fds_vec};
> + }
> +
> + static std::vector<V> deserialize(std::vector<uint8_t> &data, ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::vector<V>>::deserialize(data.begin(), data.end(), cs);
> + }
> +
> + static std::vector<V> deserialize(std::vector<uint8_t>::iterator it1,
> + std::vector<uint8_t>::iterator it2,
> + ControlSerializer *cs = nullptr)
> + {
> + std::vector<int32_t> fds;
> + return IPADataSerializer<std::vector<V>>::deserialize(it1, it2,
> + fds.begin(), fds.end(),
> + cs);
> + }
> +
> + static std::vector<V> deserialize(std::vector<uint8_t> &data, std::vector<int32_t> &fds,
> + ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::vector<V>>::deserialize(data.begin(), data.end(),
> + fds.begin(), fds.end(),
> + cs);
> + }
> +
> + static std::vector<V> deserialize(std::vector<uint8_t>::iterator data_it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator data_it2,
> + std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs = nullptr)
> + {
> + uint32_t vec_len = readUInt<uint32_t>(data_it1);
> + std::vector<V> ret(vec_len);
> +
> + std::vector<uint8_t>::iterator data_it = data_it1 + 4;
> + std::vector<int32_t>::iterator fd_it = fds_it1;
> + for (uint32_t i = 0; i < vec_len; i++) {
> + uint32_t sizeof_data = readUInt<uint32_t>(data_it);
> + uint32_t sizeof_fds = readUInt<uint32_t>(data_it + 4);
> +
> + ret[i] = IPADataSerializer<V>::deserialize(data_it + 8,
> + data_it + 8 + sizeof_data,
> + fd_it,
> + fd_it + sizeof_fds,
> + cs);
> +
> + data_it += 8 + sizeof_data;
> + fd_it += sizeof_fds;
> + }
> +
> + return ret;
> + }
> +};
> +
> +template<typename K, typename V>
> +class IPADataSerializer<std::map<K, V>>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const std::map<K, V> &data, ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> + std::vector<int32_t> fds_vec;
> +
> + // serialize the length
> + uint32_t map_len = data.size();
> + appendUInt<uint32_t>(data_vec, map_len);
> +
> + // serialize the members
> + for (auto it = data.begin(); it != data.end(); ++it) {
> + std::vector<uint8_t> dvec;
> + std::vector<int32_t> fvec;
> +
> + std::tie(dvec, fvec) =
> + IPADataSerializer<K>::serialize(it->first, cs);
> +
> + appendUInt<uint32_t>(data_vec, dvec.size());
> + appendUInt<uint32_t>(data_vec, fvec.size());
> +
> + data_vec.insert(data_vec.end(), dvec.begin(), dvec.end());
> + fds_vec.insert(fds_vec.end(), fvec.begin(), fvec.end());
> +
> + std::tie(dvec, fvec) =
> + IPADataSerializer<V>::serialize(it->second, cs);
> +
> + appendUInt<uint32_t>(data_vec, dvec.size());
> + appendUInt<uint32_t>(data_vec, fvec.size());
> +
> + data_vec.insert(data_vec.end(), dvec.begin(), dvec.end());
> + fds_vec.insert(fds_vec.end(), fvec.begin(), fvec.end());
> + }
> +
> + return {data_vec, fds_vec};
> + }
> +
> + static std::map<K, V> deserialize(std::vector<uint8_t> &data, ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::map<K, V>>::deserialize(data.begin(), data.end(), cs);
> + }
> +
> + static std::map<K, V> deserialize(std::vector<uint8_t>::iterator it1,
> + std::vector<uint8_t>::iterator it2,
> + ControlSerializer *cs = nullptr)
> + {
> + std::vector<int32_t> fds;
> + return IPADataSerializer<std::map<K, V>>::deserialize(it1, it2,
> + fds.begin(), fds.end(),
> + cs);
> + }
> +
> + static std::map<K, V> deserialize(std::vector<uint8_t> &data, std::vector<int32_t> &fds,
> + ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::map<K, V>>::deserialize(data.begin(), data.end(),
> + fds.begin(), fds.end(),
> + cs);
> + }
> +
> + static std::map<K, V> deserialize(std::vector<uint8_t>::iterator data_it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator data_it2,
> + std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs = nullptr)
> + {
> + std::map<K, V> ret;
> +
> + uint32_t map_len = readUInt<uint32_t>(data_it1);
> +
> + std::vector<uint8_t>::iterator data_it = data_it1 + 4;
> + std::vector<int32_t>::iterator fd_it = fds_it1;
> + for (uint32_t i = 0; i < map_len; i++) {
> + uint32_t sizeof_data = readUInt<uint32_t>(data_it);
> + uint32_t sizeof_fds = readUInt<uint32_t>(data_it + 4);
> +
> + K key = IPADataSerializer<K>::deserialize(data_it + 8,
> + data_it + 8 + sizeof_data,
> + fd_it,
> + fd_it + sizeof_fds,
> + cs);
> +
> + data_it += 8 + sizeof_data;
> + fd_it += sizeof_fds;
> + sizeof_data = readUInt<uint32_t>(data_it);
> + sizeof_fds = readUInt<uint32_t>(data_it + 4);
> +
> + const V value = IPADataSerializer<V>::deserialize(data_it + 8,
> + data_it + 8 + sizeof_data,
> + fd_it,
> + fd_it + sizeof_fds,
> + cs);
> + ret.insert({key, value});
> +
> + data_it += 8 + sizeof_data;
> + fd_it += sizeof_fds;
> + }
> +
> + return ret;
> + }
> +};
> +
> +#define DECLARE_INTEGRAL_SERIALIZER(type) \
> +template<> \
> +class IPADataSerializer<type> \
> +{ \
> +public: \
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>> \
> + serialize(const type data, \
> + [[maybe_unused]] ControlSerializer *cs = nullptr) \
> + { \
> + std::vector<uint8_t> data_vec; \
> + appendUInt<type>(data_vec, data); \
> + \
> + return {data_vec, {}}; \
> + } \
> + \
> + static type deserialize(std::vector<uint8_t> &data, \
> + [[maybe_unused]] ControlSerializer *cs = nullptr)\
> + { \
> + return IPADataSerializer<type>::deserialize(data.begin(),\
> + data.end());\
> + } \
> + \
> + static type deserialize(std::vector<uint8_t>::iterator it1, \
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,\
> + [[maybe_unused]] ControlSerializer *cs = nullptr)\
> + { \
> + return readUInt<type>(it1); \
> + } \
> + \
> + static type deserialize(std::vector<uint8_t> &data, \
> + [[maybe_unused]] std::vector<int32_t> &fds,\
> + [[maybe_unused]] ControlSerializer *cs = nullptr)\
> + { \
> + return IPADataSerializer<type>::deserialize(data.begin(),\
> + data.end());\
> + } \
> + \
> + static type deserialize(std::vector<uint8_t>::iterator data_it1,\
> + std::vector<uint8_t>::iterator data_it2,\
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,\
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,\
> + [[maybe_unused]] ControlSerializer *cs = nullptr)\
> + { \
> + return IPADataSerializer<type>::deserialize(data_it1, \
> + data_it2); \
> + } \
> +};
> +
> +DECLARE_INTEGRAL_SERIALIZER(uint8_t)
> +DECLARE_INTEGRAL_SERIALIZER(uint16_t)
> +DECLARE_INTEGRAL_SERIALIZER(uint32_t)
> +DECLARE_INTEGRAL_SERIALIZER(uint64_t)
> +DECLARE_INTEGRAL_SERIALIZER(int8_t)
> +DECLARE_INTEGRAL_SERIALIZER(int16_t)
> +DECLARE_INTEGRAL_SERIALIZER(int32_t)
> +
> +template<>
> +class IPADataSerializer<int64_t>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const int64_t data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> + appendUInt<uint64_t>(data_vec, data);
> +
> + return {data_vec, {}};
> + }
> +
> + static int64_t deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<int64_t>::deserialize(data.begin(),
> + data.end());
> + }
> +
> + static int64_t deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + if (std::distance(it1, it2) < 8) {
> + LOG(IPADataSerializer, Info)
> + << "Not enough bytes to deserialize int64_t, returning 0";
> + return 0;
> + }
> +
> + uint32_t lower = readUInt<uint32_t>(it1);
> + uint32_t upper = readUInt<uint32_t>(it1 + 4);
> +
> + return lower + (uint64_t(upper) << 32);
> + }
> +
> + static int64_t deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<int64_t>::deserialize(data.begin(),
> + data.end());
> + }
> +
> + static int64_t deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<int64_t>::deserialize(data_it1, data_it2);
> + }
> +};
In what is the int64_t specialization different that the other ones
defined through DECLARE_INTEGRAL_SERIALIZER ? It's only because you
don't have a readUInt<int64_t> ?
> +
> +template<>
> +class IPADataSerializer<bool>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const bool data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> + appendUInt<uint8_t>(data_vec, data);
> +
> + return {data_vec, {}};
> + }
> +
> + static bool deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<bool>::deserialize(data.begin(),
> + data.end());
> + }
> +
> + static bool deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return readUInt<uint8_t>(it1);
The sizeof(bool) seems to be a bit an issue actually... Can you solve
it by declarting a
template<> bool readUInt(std::vector<uint8_t>::iterator it)
?
Actually it seems to me the current implementation might work with
bool too...
> + }
> +
> + static bool deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<bool>::deserialize(data.begin(),
> + data.end());
> + }
> +
> + static bool deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<bool>::deserialize(data_it1, data_it2);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<float>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const float data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + uint8_t arr[4];
> + memcpy(arr, &data, sizeof(arr));
I wonder if we should no be using memcpy in the readUInt() function
too. Would this help you with floats ?
> +
> + std::vector<uint8_t> data_vec(arr, arr + 4);
> +
> + return {data_vec, {}};
> + }
> +
> + static float deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<float>::deserialize(data.begin(), data.end());
> + }
> +
> + static float deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + if (std::distance(it1, it2) < 4) {
> + LOG(IPADataSerializer, Info)
> + << "Not enough bytes to deserialize float, returning 0";
> + return 0;
> + }
> +
> + std::vector data(it1, it2);
> + float ret;
> + memcpy(&ret, data.data(), sizeof(ret));
> +
> + return ret;
> + }
> +
> + static float deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<float>::deserialize(data.begin(), data.end());
> + }
> +
> + static float deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<float>::deserialize(data_it1, data_it2);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<double>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const double data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + uint8_t arr[8];
> + memcpy(arr, &data, sizeof(arr));
> +
> + std::vector<uint8_t> data_vec(arr, arr + 8);
> +
> + return {data_vec, {}};
> + }
> +
> + static double deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<double>::deserialize(data.begin(), data.end());
> + }
> +
> + static double deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + if (std::distance(it1, it2) < 8) {
> + LOG(IPADataSerializer, Info)
> + << "Not enough bytes to deserialize double, returning 0";
> + return 0;
> + }
> +
> + std::vector data(it1, it2);
> + double ret;
> + memcpy(&ret, data.data(), sizeof(ret));
> +
> + return ret;
> + }
> +
> + static double deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<double>::deserialize(data.begin(), data.end());
> + }
> +
> + static double deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<double>::deserialize(data_it1, data_it2);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<std::string>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const std::string &data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec(data.begin(), data.end());
> +
> + return {data_vec, {}};
> + }
> +
> + static std::string deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::string>::deserialize(data.begin(), data.end());
> + }
> +
> + static std::string deserialize(std::vector<uint8_t>::iterator it1,
> + std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::string str(it1, it2);
> +
> + return str;
> + }
> +
> + static std::string deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::string>::deserialize(data.begin(), data.end());
> + }
> +
> + static std::string deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::string>::deserialize(data_it1, data_it2);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<FileDescriptor>
Ah, that's why you have the fds parameter in deserializer and the
std::vector<int32_t> in the serializer return parameter.
I think this would be cleaner if we could use enable_if and define an
ad-hoc function signature for FileDescriptor and ControlList. It would
remove the fds and cs parameters from all other types (the ones I've
see so far at least).
I think I'll stop here, there's enough to discuss on
Thanks
j
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const FileDescriptor &data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec = { data.isValid() };
> + std::vector<int32_t> fd_vec;
> + if (data.isValid())
> + fd_vec.push_back(data.fd());
> +
> + return {data_vec, fd_vec};
> + }
> +
> + static FileDescriptor deserialize(std::vector<uint8_t> &data, std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<FileDescriptor>::deserialize(data.begin(), data.end(),
> + fds.begin(), fds.end());
> + }
> +
> + static FileDescriptor deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + std::vector<int32_t>::iterator fds_it1,
> + std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + if (std::distance(data_it1, data_it2) < 1)
> + LOG(IPADataSerializer, Fatal)
> + << "Invalid data to deserialize FileDescriptor";
> +
> + bool valid = *data_it1;
> +
> + if (valid && std::distance(fds_it1, fds_it2) < 1)
> + LOG(IPADataSerializer, Fatal)
> + << "Invalid fds to deserialize FileDescriptor";
> +
> + return valid ? FileDescriptor(*fds_it1) : FileDescriptor();
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<IPASettings>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const IPASettings &data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<std::string>::serialize(data.configurationFile);
> + }
> +
> + static IPASettings deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<IPASettings>::deserialize(data.begin(), data.end());
> + }
> +
> + static IPASettings deserialize(std::vector<uint8_t>::iterator it1,
> + std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + IPASettings ret;
> + ret.configurationFile = IPADataSerializer<std::string>::deserialize(it1, it2);
> +
> + return ret;
> + }
> +
> + static IPASettings deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<IPASettings>::deserialize(data.begin(), data.end());
> + }
> +
> + static IPASettings deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<IPASettings>::deserialize(data_it1, data_it2);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<CameraSensorInfo>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const CameraSensorInfo &data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> +
> + uint32_t str_len = data.model.size();
> + appendUInt<uint32_t>(data_vec, str_len);
> +
> + data_vec.insert(data_vec.end(), data.model.begin(), data.model.end());
> +
> + appendUInt<uint32_t>(data_vec, data.bitsPerPixel);
> +
> + appendUInt<uint32_t>(data_vec, data.activeAreaSize.width);
> + appendUInt<uint32_t>(data_vec, data.activeAreaSize.height);
> +
> + appendUInt<uint32_t>(data_vec, static_cast<uint32_t>(data.analogCrop.x));
> + appendUInt<uint32_t>(data_vec, static_cast<uint32_t>(data.analogCrop.y));
> + appendUInt<uint32_t>(data_vec, data.analogCrop.width);
> + appendUInt<uint32_t>(data_vec, data.analogCrop.height);
> +
> + appendUInt<uint32_t>(data_vec, data.outputSize.width);
> + appendUInt<uint32_t>(data_vec, data.outputSize.height);
> +
> + appendUInt<uint64_t>(data_vec, data.pixelRate);
> +
> + appendUInt<uint32_t>(data_vec, data.lineLength);
> +
> + return {data_vec, {}};
> + }
> +
> + static CameraSensorInfo deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<CameraSensorInfo>::deserialize(data.begin(), data.end());
> + }
> +
> + static CameraSensorInfo deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + CameraSensorInfo ret;
> +
> + uint32_t str_len = readUInt<uint32_t>(it1);
> + std::string str(it1 + 4, it1 + 4 + str_len);
> + ret.model = str;
> +
> + std::vector<uint8_t>::iterator it = it1 + 4 + str_len;
> +
> + ret.bitsPerPixel = readUInt<uint32_t>(it);
> +
> + ret.activeAreaSize.width = readUInt<uint32_t>(it + 4);
> + ret.activeAreaSize.height = readUInt<uint32_t>(it + 8);
> +
> + ret.analogCrop.x = static_cast<int32_t>(readUInt<uint32_t>(it + 12));
> + ret.analogCrop.y = static_cast<int32_t>(readUInt<uint32_t>(it + 16));
> + ret.analogCrop.width = readUInt<uint32_t>(it + 20);
> + ret.analogCrop.height = readUInt<uint32_t>(it + 24);
> +
> + ret.outputSize.width = readUInt<uint32_t>(it + 28);
> + ret.outputSize.height = readUInt<uint32_t>(it + 32);
> +
> + ret.pixelRate = readUInt<uint64_t>(it + 36);
> +
> + ret.lineLength = readUInt<uint64_t>(it + 44);
> +
> + return ret;
> + }
> +
> + static CameraSensorInfo deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<CameraSensorInfo>::deserialize(data.begin(), data.end());
> + }
> +
> + static CameraSensorInfo deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<CameraSensorInfo>::deserialize(data_it1, data_it2);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<IPAStream>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const IPAStream &data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> +
> + appendUInt<uint32_t>(data_vec, data.pixelFormat);
> +
> + appendUInt<uint32_t>(data_vec, data.size.width);
> + appendUInt<uint32_t>(data_vec, data.size.height);
> +
> + return {data_vec, {}};
> + }
> +
> + static IPAStream deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<IPAStream>::deserialize(data.begin(), data.end());
> + }
> +
> + static IPAStream deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + IPAStream ret;
> +
> + ret.pixelFormat = readUInt<uint32_t>(it1);
> +
> + ret.size.width = readUInt<uint32_t>(it1 + 4);
> + ret.size.height = readUInt<uint32_t>(it1 + 8);
> +
> + return ret;
> + }
> +
> + static IPAStream deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<IPAStream>::deserialize(data.begin(), data.end());
> + }
> +
> + static IPAStream deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<IPAStream>::deserialize(data_it1, data_it2);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<const ControlList>
> +{
> +public:
> + // map arg will be generated, since it's per-pipeline anyway
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const ControlList &data, const ControlInfoMap &map,
> + ControlSerializer *cs)
> + {
> + if (!cs)
> + LOG(IPADataSerializer, Fatal)
> + << "ControlSerializer not provided for serialization of ControlList";
> +
> + size_t size = cs->binarySize(map);
> + std::vector<uint8_t> infoData(size);
> + ByteStreamBuffer buffer(infoData.data(), infoData.size());
> + int ret = cs->serialize(map, buffer);
> +
> + if (ret < 0 || buffer.overflow()) {
> + LOG(IPADataSerializer, Error) << "Failed to serialize ControlList's ControlInfoMap";
> + return {{}, {}};
> + }
> +
> + size = cs->binarySize(data);
> + std::vector<uint8_t> listData(size);
> + buffer = ByteStreamBuffer(listData.data(), listData.size());
> + ret = cs->serialize(data, buffer);
> +
> + if (ret < 0 || buffer.overflow()) {
> + LOG(IPADataSerializer, Error) << "Failed to serialize ControlList";
> + return {{}, {}};
> + }
> +
> + std::vector<uint8_t> data_vec;
> + appendUInt<uint32_t>(data_vec, infoData.size());
> + appendUInt<uint32_t>(data_vec, listData.size());
> + data_vec.insert(data_vec.end(), infoData.begin(), infoData.end());
> + data_vec.insert(data_vec.end(), listData.begin(), listData.end());
> +
> + return {data_vec, {}};
> + }
> +
> + static const ControlList deserialize(std::vector<uint8_t> &data, ControlSerializer *cs)
> + {
> + return IPADataSerializer<const ControlList>::deserialize(data.begin(), data.end(), cs);
> + }
> +
> + static const ControlList deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + ControlSerializer *cs)
> + {
> + if (!cs)
> + LOG(IPADataSerializer, Fatal)
> + << "ControlSerializer not provided for deserialization of ControlList";
> +
> + uint32_t infoDataSize = readUInt<uint32_t>(it1);
> + uint32_t listDataSize = readUInt<uint32_t>(it1 + 4);
> +
> + std::vector<uint8_t>::iterator it = it1 + 8;
> +
> + std::vector<uint8_t> infoData(it, it + infoDataSize);
> + std::vector<uint8_t> listData(it + infoDataSize, it + infoDataSize + listDataSize);
> +
> + ByteStreamBuffer buffer(const_cast<const uint8_t *>(infoData.data()), infoData.size());
> + ControlInfoMap map = cs->deserialize<ControlInfoMap>(buffer);
> + /* It's fine if map is empty. */
> + if (buffer.overflow()) {
> + LOG(IPADataSerializer, Error)
> + << "Failed to deserialize ControlLists's ControlInfoMap: buffer overflow";
> + return ControlList();
> + }
> +
> + buffer = ByteStreamBuffer(const_cast<const uint8_t *>(listData.data()), listData.size());
> + ControlList list = cs->deserialize<ControlList>(buffer);
> + if (buffer.overflow())
> + LOG(IPADataSerializer, Error) << "Failed to deserialize ControlList: buffer overflow";
> + if (list.empty())
> + LOG(IPADataSerializer, Error) << "Failed to deserialize ControlList: empty list";
> +
> + return list;
> + }
> +
> + static const ControlList deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + ControlSerializer *cs)
> + {
> + return IPADataSerializer<const ControlList>::deserialize(data.begin(), data.end(), cs);
> + }
> +
> + static const ControlList deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs)
> + {
> + return IPADataSerializer<const ControlList>::deserialize(data_it1, data_it2, cs);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<ControlList>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const ControlList &data, const ControlInfoMap &map,
> + ControlSerializer *cs)
> + {
> + const ControlList &list_const = const_cast<const ControlList &>(data);
> +
> + std::vector<uint8_t> data_vec;
> + std::tie(data_vec, std::ignore) =
> + IPADataSerializer<const ControlList>::serialize(list_const, map, cs);
> +
> + return {data_vec, {}};
> + }
> +
> + static ControlList deserialize(std::vector<uint8_t> &data,
> + ControlSerializer *cs)
> + {
> + ControlList ret;
> + const ControlList &list = ret;
> + const_cast<ControlList &>(list) =
> + IPADataSerializer<const ControlList>::deserialize(data, cs);
> +
> + return ret;
> + }
> +
> + static ControlList deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + ControlSerializer *cs)
> + {
> + ControlList ret;
> + const ControlList &list = ret;
> + const_cast<ControlList &>(list) =
> + IPADataSerializer<const ControlList>::deserialize(it1, it2, cs);
> +
> + return ret;
> + }
> +
> + static ControlList deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + ControlSerializer *cs)
> + {
> + ControlList ret;
> + const ControlList &list = ret;
> + const_cast<ControlList &>(list) =
> + IPADataSerializer<const ControlList>::deserialize(data, fds, cs);
> +
> + return ret;
> + }
> +
> + static ControlList deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs)
> + {
> + ControlList ret;
> + const ControlList &list = ret;
> + const_cast<ControlList &>(list) =
> + IPADataSerializer<const ControlList>::deserialize(data_it1, data_it2,
> + fds_it1, fds_it2, cs);
> +
> + return ret;
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<const ControlInfoMap>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const ControlInfoMap &map, ControlSerializer *cs)
> + {
> + if (!cs)
> + LOG(IPADataSerializer, Fatal)
> + << "ControlSerializer not provided for serialization of ControlInfoMap";
> +
> + size_t size = cs->binarySize(map);
> + std::vector<uint8_t> infoData(size);
> + ByteStreamBuffer buffer(infoData.data(), infoData.size());
> + int ret = cs->serialize(map, buffer);
> +
> + if (ret < 0 || buffer.overflow())
> + return {{}, {}};
> +
> + std::vector<uint8_t> data_vec;
> + appendUInt<uint32_t>(data_vec, infoData.size());
> + data_vec.insert(data_vec.end(), infoData.begin(), infoData.end());
> +
> + return {data_vec, {}};
> + }
> +
> + static const ControlInfoMap deserialize(std::vector<uint8_t> &data,
> + ControlSerializer *cs)
> + {
> + return IPADataSerializer<const ControlInfoMap>::deserialize(data.begin(), data.end(), cs);
> + }
> +
> + static const ControlInfoMap deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + ControlSerializer *cs)
> + {
> + if (!cs)
> + LOG(IPADataSerializer, Fatal)
> + << "ControlSerializer not provided for deserialization of ControlInfoMap";
> +
> + uint32_t infoDataSize = readUInt<uint32_t>(it1);
> +
> + std::vector<uint8_t>::iterator it = it1 + 4;
> +
> + std::vector<uint8_t> infoData(it, it + infoDataSize);
> +
> + ByteStreamBuffer buffer(const_cast<const uint8_t *>(infoData.data()), infoData.size());
> + const ControlInfoMap map = cs->deserialize<ControlInfoMap>(buffer);
> +
> + return map;
> + }
> +
> + static const ControlInfoMap deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + ControlSerializer *cs)
> + {
> + return IPADataSerializer<const ControlInfoMap>::deserialize(data.begin(), data.end(), cs);
> + }
> +
> + static const ControlInfoMap deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs)
> + {
> + return IPADataSerializer<const ControlInfoMap>::deserialize(data_it1, data_it2, cs);
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<ControlInfoMap>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const ControlInfoMap &map, [[maybe_unused]] ControlSerializer *cs)
> + {
> + const ControlInfoMap &map_const = const_cast<const ControlInfoMap &>(map);
> +
> + std::vector<uint8_t> data_vec;
> + std::tie(data_vec, std::ignore) =
> + IPADataSerializer<const ControlInfoMap>::serialize(map_const, cs);
> +
> + return {data_vec, {}};
> + }
> +
> + static ControlInfoMap deserialize(std::vector<uint8_t> &data,
> + ControlSerializer *cs)
> + {
> + ControlInfoMap ret;
> + const ControlInfoMap &map = ret;
> + const_cast<ControlInfoMap &>(map) =
> + IPADataSerializer<const ControlInfoMap>::deserialize(data, cs);
> +
> + return ret;
> + }
> +
> + static ControlInfoMap deserialize(std::vector<uint8_t>::iterator it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator it2,
> + ControlSerializer *cs)
> + {
> + ControlInfoMap ret;
> + const ControlInfoMap &map = ret;
> + const_cast<ControlInfoMap &>(map) =
> + IPADataSerializer<const ControlInfoMap>::deserialize(it1, it2, cs);
> +
> + return ret;
> + }
> +
> + static ControlInfoMap deserialize(std::vector<uint8_t> &data,
> + [[maybe_unused]] std::vector<int32_t> &fds,
> + ControlSerializer *cs)
> + {
> + ControlInfoMap ret;
> + const ControlInfoMap &map = ret;
> + const_cast<ControlInfoMap &>(map) =
> + IPADataSerializer<const ControlInfoMap>::deserialize(data, fds, cs);
> +
> + return ret;
> + }
> +
> + static ControlInfoMap deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs)
> + {
> + ControlInfoMap ret;
> + const ControlInfoMap &map = ret;
> + const_cast<ControlInfoMap &>(map) =
> + IPADataSerializer<const ControlInfoMap>::deserialize(data_it1, data_it2,
> + fds_it1, fds_it2, cs);
> +
> + return ret;
> + }
> +};
> +
> +template<>
> +class IPADataSerializer<FrameBuffer::Plane>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const FrameBuffer::Plane &data, [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> + std::vector<int32_t> fds_vec;
> +
> + // fd
> + std::vector<uint8_t> fdBuf;
> + std::vector<int32_t> fdFds;
> + std::tie(fdBuf, fdFds) =
> + IPADataSerializer<FileDescriptor>::serialize(data.fd);
> + data_vec.insert(data_vec.end(), fdBuf.begin(), fdBuf.end());
> + fds_vec.insert(fds_vec.end(), fdFds.begin(), fdFds.end());
> +
> + // length
> + appendUInt<uint32_t>(data_vec, data.length);
> +
> + return {data_vec, fds_vec};
> + }
> +
> + static FrameBuffer::Plane deserialize(std::vector<uint8_t> &data,
> + std::vector<int32_t> &fds,
> + ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<FrameBuffer::Plane>::deserialize(data.begin(), data.end(),
> + fds.begin(), fds.end(),
> + cs);
> + }
> +
> + static FrameBuffer::Plane deserialize(std::vector<uint8_t>::iterator data_it1,
> + [[maybe_unused]] std::vector<uint8_t>::iterator data_it2,
> + std::vector<int32_t>::iterator fds_it1,
> + [[maybe_unused]] std::vector<int32_t>::iterator fds_it2,
> + [[maybe_unused]] ControlSerializer *cs = nullptr)
> + {
> + FrameBuffer::Plane ret;
> +
> + ret.fd = IPADataSerializer<FileDescriptor>::deserialize(data_it1, data_it1 + 1,
> + fds_it1, fds_it1 + 1);
> + ret.length = readUInt<uint32_t>(data_it1 + 1);
> +
> + return ret;
> + }
> +};
> +
> +
> +template<>
> +class IPADataSerializer<IPABuffer>
> +{
> +public:
> + static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
> + serialize(const IPABuffer &data, ControlSerializer *cs = nullptr)
> + {
> + std::vector<uint8_t> data_vec;
> +
> + appendUInt<uint32_t>(data_vec, data.id);
> +
> + std::vector<uint8_t> planes_data_vec;
> + std::vector<int32_t> planes_fds_vec;
> + std::tie(planes_data_vec, planes_fds_vec) =
> + IPADataSerializer<std::vector<FrameBuffer::Plane>>::serialize(data.planes, cs);
> +
> + data_vec.insert(data_vec.end(), planes_data_vec.begin(), planes_data_vec.end());
> +
> + return {data_vec, planes_fds_vec};
> + }
> +
> + static IPABuffer deserialize(std::vector<uint8_t> &data,
> + std::vector<int32_t> &fds,
> + ControlSerializer *cs = nullptr)
> + {
> + return IPADataSerializer<IPABuffer>::deserialize(data.begin(), data.end(),
> + fds.begin(), fds.end(), cs);
> + }
> +
> + static IPABuffer deserialize(std::vector<uint8_t>::iterator data_it1,
> + std::vector<uint8_t>::iterator data_it2,
> + std::vector<int32_t>::iterator fds_it1,
> + std::vector<int32_t>::iterator fds_it2,
> + ControlSerializer *cs = nullptr)
> + {
> + IPABuffer ret;
> +
> + ret.id = readUInt<uint32_t>(data_it1);
> +
> + ret.planes =
> + IPADataSerializer<std::vector<FrameBuffer::Plane>>::deserialize(
> + data_it1 + 4, data_it2, fds_it1, fds_it2, cs);
> +
> + return ret;
> + }
> +};
> +
> +#endif /* __DOXYGEN__ */
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_H__ */
> diff --git a/src/libcamera/ipa_data_serializer.cpp b/src/libcamera/ipa_data_serializer.cpp
> new file mode 100644
> index 00000000..5029cdf6
> --- /dev/null
> +++ b/src/libcamera/ipa_data_serializer.cpp
> @@ -0,0 +1,154 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * ipa_data_serializer.cpp - Image Processing Algorithm data serializer
> + */
> +
> +#include "libcamera/internal/ipa_data_serializer.h"
> +
> +#include "libcamera/internal/log.h"
> +
> +/**
> + * \file ipa_data_serializer.h
> + * \brief IPA Data Serializer
> + */
> +
> +namespace libcamera {
> +
> +LOG_DEFINE_CATEGORY(IPADataSerializer)
> +
> +/**
> + * \class IPADataSerializer
> + * \brief IPA Data Serializer
> + *
> + * Static template class that provides functions for serializing and
> + * deserializing IPA data.
> + */
> +
> +/**
> + * \fn template<typename T> void appendUInt(std::vector<uint8_t> &vec, T val)
> + * \brief Append uint to end of byte vector, in little-endian order
> + * \tparam T Type of uint to append
> + * \param[in] vec Byte vector to append to
> + * \param[in] val Value of uint to append
> + */
> +
> +/**
> + * \fn template<typename T> T readUInt(std::vector<uint8_t> &vec, size_t pos)
> + * \brief Read uint from byte vector, in little-endian order
> + * \tparam T Type of uint to read
> + * \param[in] vec Byte vector to read from
> + * \param[in] pos Index in vec to start reading from
> + *
> + * \return The uint read from \a vec, or 0 if reading goes past end of \a vec
> + */
> +
> +/**
> + * \fn template<typename T> T readUInt(std::vector<uint8_t>::iterator it)
> + * \brief Read uint from byte vector, in little-endian order
> + * \tparam T Type of uint to read
> + * \param[in] it Iterator of byte vector to read from
> + *
> + * \return The uint read from \a vec
> + */
> +
> +/**
> + * \fn template<typename T> IPADataSerializer<T>::serialize(
> + * T data,
> + * ControlSerializer *cs = nullptr)
> + * \brief Serialize an object into byte vector and fd vector
> + * \tparam T Type of object to serialize
> + * \param[in] data Object to serialize
> + * \param[in] cs ControlSerializer
> + *
> + * \a cs is only necessary if the object type \a T or its members contain
> + * ControlList or ControlInfoMap.
> + *
> + * \return Tuple of byte vector and fd vector, that is the serialized form
> + * of \a data
> + */
> +
> +/**
> + * \fn template<typename T> IPADataSerializer<T>::deserialize(
> + * std::vector<uint8_t> &data,
> + * ControlSerializer *cs = nullptr)
> + * \brief Deserialize byte vector into an object
> + * \tparam T Type of object to deserialize to
> + * \param[in] data Byte vector to deserialize from
> + * \param[in] cs ControlSerializer
> + *
> + * This version of deserialize() can be used if the object type \a T and its
> + * members don't have any FileDescriptor.
> + *
> + * \a cs is only necessary if the object type \a T or its members contain
> + * ControlList or ControlInfoMap.
> + *
> + * \return The deserialized object
> + */
> +
> +/**
> + * \fn template<typename T> IPADataSerializer<T>::deserialize(
> + * std::vector<uint8_t>::iterator it1,
> + * std::vector<uint8_t>::iterator it2,
> + * ControlSerializer *cs = nullptr)
> + * \brief Deserialize byte vector into an object
> + * \tparam T Type of object to deserialize to
> + * \param[in] it1 Begin iterator of byte vector to deserialize from
> + * \param[in] it2 End iterator of byte vector to deserialize from
> + * \param[in] cs ControlSerializer
> + *
> + * This version of deserialize() can be used if the object type \a T and its
> + * members don't have any FileDescriptor.
> + *
> + * \a cs is only necessary if the object type \a T or its members contain
> + * ControlList or ControlInfoMap.
> + *
> + * \return The deserialized object
> + */
> +
> +/**
> + * \fn template<typename T> IPADataSerializer<T>::deserialize(
> + * std::vector<uint8_t> &data,
> + * std::vector<int32_t> &fds,
> + * ControlSerializer *cs = nullptr)
> + * \brief Deserialize byte vector and fd vector into an object
> + * \tparam T Type of object to deserialize to
> + * \param[in] data Byte vector to deserialize from
> + * \param[in] fds Fd vector to deserialize from
> + * \param[in] cs ControlSerializer
> + *
> + * This version of deserialize() (or the iterator version) must be used if
> + * the object type \a T or its members contain FileDescriptor.
> + *
> + * \a cs is only necessary if the object type \a T or its members contain
> + * ControlList or ControlInfoMap.
> + *
> + * \return The deserialized object
> + */
> +
> +/**
> + * \fn template<typename T> IPADataSerializer::deserialize(
> + * std::vector<uint8_t>::iterator data_it1,
> + * std::vector<uint8_t>::iterator data_it2,
> + * std::vector<int32_t>::iterator fds_it1,
> + * std::vector<int32_t>::iterator fds_it2,
> + * ControlSerializer *cs = nullptr)
> + * \brief Deserialize byte vector and fd vector into an object
> + * \tparam T Type of object to deserialize to
> + * \param[in] data_it1 Begin iterator of byte vector to deserialize from
> + * \param[in] data_it2 End iterator of byte vector to deserialize from
> + * \param[in] fds_it1 Begin iterator of fd vector to deserialize from
> + * \param[in] fds_it2 End iterator of fd vector to deserialize from
> + * \param[in] cs ControlSerializer
> + *
> + * This version of deserialize() (or the vector version) must be used if
> + * the object type \a T or its members contain FileDescriptor.
> + *
> + * \a cs is only necessary if the object type \a T or its members contain
> + * ControlList or ControlInfoMap.
> + *
> + * \return The deserialized object
> + */
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 9d7442fa..61aad08e 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -23,6 +23,7 @@ libcamera_sources = files([
> 'geometry.cpp',
> 'ipa_context_wrapper.cpp',
> 'ipa_controls.cpp',
> + 'ipa_data_serializer.cpp',
> 'ipa_interface.cpp',
> 'ipa_manager.cpp',
> 'ipa_module.cpp',
> --
> 2.27.0
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
More information about the libcamera-devel
mailing list