[libcamera-devel] [PATCH v3 10/38] libcamera: Add IPADataSerializer
Paul Elder
paul.elder at ideasonboard.com
Fri Oct 2 16:31:26 CEST 2020
Add an IPADataSerializer which implments de/serialization of built-in
(PODs, vector, map, string) 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 v3:
- reimplement append/readUInt with memcpy (intead of bit shifting)
- change DECLARE_INTEGRAL_SERIALIZER with DECLARE_POD_SERIALIZER
- use this for int64_t, bool, float, and double
- fix comment style
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 | 1014 +++++++++++++++++
src/libcamera/ipa_data_serializer.cpp | 154 +++
src/libcamera/meson.build | 1 +
3 files changed, 1169 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..9cd35c4c
--- /dev/null
+++ b/include/libcamera/internal/ipa_data_serializer.h
@@ -0,0 +1,1014 @@
+/* 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 <string.h>
+#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);
+ std::vector<uint8_t> v(byteWidth);
+ memcpy(&v[0], &val, byteWidth);
+
+ vec.insert(vec.end(), v.begin(), v.end());
+}
+
+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;
+
+ memcpy(&ret, &vec.data()[pos], byteWidth);
+ return ret;
+}
+
+template<typename T>
+T readUInt(std::vector<uint8_t>::iterator it)
+{
+ T ret = 0;
+ size_t byteWidth = sizeof(ret);
+
+ std::vector<uint8_t> v(it, it + byteWidth);
+ memcpy(&ret, v.data(), byteWidth);
+ 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);
+ 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);
+#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_POD_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_POD_SERIALIZER(bool)
+DECLARE_POD_SERIALIZER(uint8_t)
+DECLARE_POD_SERIALIZER(uint16_t)
+DECLARE_POD_SERIALIZER(uint32_t)
+DECLARE_POD_SERIALIZER(uint64_t)
+DECLARE_POD_SERIALIZER(int8_t)
+DECLARE_POD_SERIALIZER(int16_t)
+DECLARE_POD_SERIALIZER(int32_t)
+DECLARE_POD_SERIALIZER(int64_t)
+DECLARE_POD_SERIALIZER(float)
+DECLARE_POD_SERIALIZER(double)
+
+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>
+{
+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;
+
+ 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());
+
+ 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 07711b5f..190d7490 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -24,6 +24,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
More information about the libcamera-devel
mailing list