libcamera: Add IPADataSerializer
Add an IPADataSerializer which implements (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@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
c6d4303b0b
commit
13f7d58569
3 changed files with 923 additions and 0 deletions
307
include/libcamera/internal/ipa_data_serializer.h
Normal file
307
include/libcamera/internal/ipa_data_serializer.h
Normal file
|
@ -0,0 +1,307 @@
|
|||
/* 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 <type_traits>
|
||||
#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)
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
|
||||
void appendPOD(std::vector<uint8_t> &vec, T val)
|
||||
{
|
||||
constexpr size_t byteWidth = sizeof(val);
|
||||
vec.resize(vec.size() + byteWidth);
|
||||
memcpy(&*(vec.end() - byteWidth), &val, byteWidth);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
|
||||
T readPOD(std::vector<uint8_t>::const_iterator it, size_t pos,
|
||||
std::vector<uint8_t>::const_iterator end)
|
||||
{
|
||||
ASSERT(pos + it < end);
|
||||
|
||||
T ret = 0;
|
||||
memcpy(&ret, &(*(it + pos)), sizeof(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
|
||||
T readPOD(std::vector<uint8_t> &vec, size_t pos)
|
||||
{
|
||||
return readPOD<T>(vec.cbegin(), pos, vec.end());
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
template<typename T>
|
||||
class IPADataSerializer
|
||||
{
|
||||
public:
|
||||
static std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
|
||||
serialize(const T &data, ControlSerializer *cs = nullptr);
|
||||
|
||||
static T deserialize(const std::vector<uint8_t> &data,
|
||||
ControlSerializer *cs = nullptr);
|
||||
static T deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
ControlSerializer *cs = nullptr);
|
||||
|
||||
static T deserialize(const std::vector<uint8_t> &data,
|
||||
const std::vector<int32_t> &fds,
|
||||
ControlSerializer *cs = nullptr);
|
||||
static T deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
std::vector<int32_t>::const_iterator fdsBegin,
|
||||
std::vector<int32_t>::const_iterator fdsEnd,
|
||||
ControlSerializer *cs = nullptr);
|
||||
};
|
||||
|
||||
#ifndef __DOXYGEN__
|
||||
|
||||
/*
|
||||
* Serialization format for vector of type V:
|
||||
*
|
||||
* 4 bytes - uint32_t Length of vector, in number of elements
|
||||
*
|
||||
* For every element in the vector:
|
||||
*
|
||||
* 4 bytes - uint32_t Size of element, in bytes
|
||||
* 4 bytes - uint32_t Number of fds for the element
|
||||
* X bytes - Serialized element
|
||||
*
|
||||
* \todo Support elements that are references
|
||||
*/
|
||||
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> dataVec;
|
||||
std::vector<int32_t> fdsVec;
|
||||
|
||||
/* Serialize the length. */
|
||||
uint32_t vecLen = data.size();
|
||||
appendPOD<uint32_t>(dataVec, vecLen);
|
||||
|
||||
/* Serialize the members. */
|
||||
for (auto const &it : data) {
|
||||
std::vector<uint8_t> dvec;
|
||||
std::vector<int32_t> fvec;
|
||||
|
||||
std::tie(dvec, fvec) =
|
||||
IPADataSerializer<V>::serialize(it, cs);
|
||||
|
||||
appendPOD<uint32_t>(dataVec, dvec.size());
|
||||
appendPOD<uint32_t>(dataVec, fvec.size());
|
||||
|
||||
dataVec.insert(dataVec.end(), dvec.begin(), dvec.end());
|
||||
fdsVec.insert(fdsVec.end(), fvec.begin(), fvec.end());
|
||||
}
|
||||
|
||||
return { dataVec, fdsVec };
|
||||
}
|
||||
|
||||
static std::vector<V> deserialize(std::vector<uint8_t> &data, ControlSerializer *cs = nullptr)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), cs);
|
||||
}
|
||||
|
||||
static std::vector<V> deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
ControlSerializer *cs = nullptr)
|
||||
{
|
||||
std::vector<int32_t> fds;
|
||||
return deserialize(dataBegin, dataEnd, fds.cbegin(), fds.end(), cs);
|
||||
}
|
||||
|
||||
static std::vector<V> deserialize(std::vector<uint8_t> &data, std::vector<int32_t> &fds,
|
||||
ControlSerializer *cs = nullptr)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs);
|
||||
}
|
||||
|
||||
static std::vector<V> deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
std::vector<int32_t>::const_iterator fdsBegin,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsEnd,
|
||||
ControlSerializer *cs = nullptr)
|
||||
{
|
||||
uint32_t vecLen = readPOD<uint32_t>(dataBegin, 0, dataEnd);
|
||||
std::vector<V> ret(vecLen);
|
||||
|
||||
std::vector<uint8_t>::const_iterator dataIter = dataBegin + 4;
|
||||
std::vector<int32_t>::const_iterator fdIter = fdsBegin;
|
||||
for (uint32_t i = 0; i < vecLen; i++) {
|
||||
uint32_t sizeofData = readPOD<uint32_t>(dataIter, 0, dataEnd);
|
||||
uint32_t sizeofFds = readPOD<uint32_t>(dataIter, 4, dataEnd);
|
||||
dataIter += 8;
|
||||
|
||||
ret[i] = IPADataSerializer<V>::deserialize(dataIter,
|
||||
dataIter + sizeofData,
|
||||
fdIter,
|
||||
fdIter + sizeofFds,
|
||||
cs);
|
||||
|
||||
dataIter += sizeofData;
|
||||
fdIter += sizeofFds;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Serialization format for map of key type K and value type V:
|
||||
*
|
||||
* 4 bytes - uint32_t Length of map, in number of pairs
|
||||
*
|
||||
* For every pair in the map:
|
||||
*
|
||||
* 4 bytes - uint32_t Size of key, in bytes
|
||||
* 4 bytes - uint32_t Number of fds for the key
|
||||
* X bytes - Serialized key
|
||||
* 4 bytes - uint32_t Size of value, in bytes
|
||||
* 4 bytes - uint32_t Number of fds for the value
|
||||
* X bytes - Serialized value
|
||||
*
|
||||
* \todo Support keys or values that are references
|
||||
*/
|
||||
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> dataVec;
|
||||
std::vector<int32_t> fdsVec;
|
||||
|
||||
/* Serialize the length. */
|
||||
uint32_t mapLen = data.size();
|
||||
appendPOD<uint32_t>(dataVec, mapLen);
|
||||
|
||||
/* Serialize the members. */
|
||||
for (auto const &it : data) {
|
||||
std::vector<uint8_t> dvec;
|
||||
std::vector<int32_t> fvec;
|
||||
|
||||
std::tie(dvec, fvec) =
|
||||
IPADataSerializer<K>::serialize(it.first, cs);
|
||||
|
||||
appendPOD<uint32_t>(dataVec, dvec.size());
|
||||
appendPOD<uint32_t>(dataVec, fvec.size());
|
||||
|
||||
dataVec.insert(dataVec.end(), dvec.begin(), dvec.end());
|
||||
fdsVec.insert(fdsVec.end(), fvec.begin(), fvec.end());
|
||||
|
||||
std::tie(dvec, fvec) =
|
||||
IPADataSerializer<V>::serialize(it.second, cs);
|
||||
|
||||
appendPOD<uint32_t>(dataVec, dvec.size());
|
||||
appendPOD<uint32_t>(dataVec, fvec.size());
|
||||
|
||||
dataVec.insert(dataVec.end(), dvec.begin(), dvec.end());
|
||||
fdsVec.insert(fdsVec.end(), fvec.begin(), fvec.end());
|
||||
}
|
||||
|
||||
return { dataVec, fdsVec };
|
||||
}
|
||||
|
||||
static std::map<K, V> deserialize(std::vector<uint8_t> &data, ControlSerializer *cs = nullptr)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), cs);
|
||||
}
|
||||
|
||||
static std::map<K, V> deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
ControlSerializer *cs = nullptr)
|
||||
{
|
||||
std::vector<int32_t> fds;
|
||||
return deserialize(dataBegin, dataEnd, fds.cbegin(), fds.end(), cs);
|
||||
}
|
||||
|
||||
static std::map<K, V> deserialize(std::vector<uint8_t> &data, std::vector<int32_t> &fds,
|
||||
ControlSerializer *cs = nullptr)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs);
|
||||
}
|
||||
|
||||
static std::map<K, V> deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
std::vector<int32_t>::const_iterator fdsBegin,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsEnd,
|
||||
ControlSerializer *cs = nullptr)
|
||||
{
|
||||
std::map<K, V> ret;
|
||||
|
||||
uint32_t mapLen = readPOD<uint32_t>(dataBegin, 0, dataEnd);
|
||||
|
||||
std::vector<uint8_t>::const_iterator dataIter = dataBegin + 4;
|
||||
std::vector<int32_t>::const_iterator fdIter = fdsBegin;
|
||||
for (uint32_t i = 0; i < mapLen; i++) {
|
||||
uint32_t sizeofData = readPOD<uint32_t>(dataIter, 0, dataEnd);
|
||||
uint32_t sizeofFds = readPOD<uint32_t>(dataIter, 4, dataEnd);
|
||||
dataIter += 8;
|
||||
|
||||
K key = IPADataSerializer<K>::deserialize(dataIter,
|
||||
dataIter + sizeofData,
|
||||
fdIter,
|
||||
fdIter + sizeofFds,
|
||||
cs);
|
||||
|
||||
dataIter += sizeofData;
|
||||
fdIter += sizeofFds;
|
||||
sizeofData = readPOD<uint32_t>(dataIter, 0, dataEnd);
|
||||
sizeofFds = readPOD<uint32_t>(dataIter, 4, dataEnd);
|
||||
dataIter += 8;
|
||||
|
||||
const V value = IPADataSerializer<V>::deserialize(dataIter,
|
||||
dataIter + sizeofData,
|
||||
fdIter,
|
||||
fdIter + sizeofFds,
|
||||
cs);
|
||||
ret.insert({ key, value });
|
||||
|
||||
dataIter += sizeofData;
|
||||
fdIter += sizeofFds;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __DOXYGEN__ */
|
||||
|
||||
} /* namespace libcamera */
|
||||
|
||||
#endif /* __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_H__ */
|
615
src/libcamera/ipa_data_serializer.cpp
Normal file
615
src/libcamera/ipa_data_serializer.cpp
Normal file
|
@ -0,0 +1,615 @@
|
|||
/* 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.
|
||||
*
|
||||
* \todo Switch to Span instead of byte and fd vector
|
||||
*
|
||||
* \todo Harden the vector and map deserializer
|
||||
*
|
||||
* \todo For FileDescriptors, instead of storing a validity flag, store an
|
||||
* index into the fd array. This will allow us to use views instead of copying.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* \fn template<typename T> void appendPOD(std::vector<uint8_t> &vec, T val)
|
||||
* \brief Append POD to end of byte vector, in little-endian order
|
||||
* \tparam T Type of POD to append
|
||||
* \param[in] vec Byte vector to append to
|
||||
* \param[in] val Value to append
|
||||
*
|
||||
* This function is meant to be used by the IPA data serializer, and the
|
||||
* generated IPA proxies.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn template<typename T> T readPOD(std::vector<uint8_t>::iterator it, size_t pos,
|
||||
* std::vector<uint8_t>::iterator end)
|
||||
* \brief Read POD from byte vector, in little-endian order
|
||||
* \tparam T Type of POD to read
|
||||
* \param[in] it Iterator of byte vector to read from
|
||||
* \param[in] pos Index in byte vector to read from
|
||||
* \param[in] end Iterator marking end of byte vector
|
||||
*
|
||||
* This function is meant to be used by the IPA data serializer, and the
|
||||
* generated IPA proxies.
|
||||
*
|
||||
* If the \a pos plus the byte-width of the desired POD is past \a end, it is
|
||||
* a fata error will occur, as it means there is insufficient data for
|
||||
* deserialization, which should never happen.
|
||||
*
|
||||
* \return The POD read from \a it at index \a pos
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn template<typename T> T readPOD(std::vector<uint8_t> &vec, size_t pos)
|
||||
* \brief Read POD from byte vector, in little-endian order
|
||||
* \tparam T Type of POD to read
|
||||
* \param[in] vec Byte vector to read from
|
||||
* \param[in] pos Index in vec to start reading from
|
||||
*
|
||||
* This function is meant to be used by the IPA data serializer, and the
|
||||
* generated IPA proxies.
|
||||
*
|
||||
* If the \a pos plus the byte-width of the desired POD is past the end of
|
||||
* \a vec, a fatal error will occur, as it means there is insufficient data
|
||||
* for deserialization, which should never happen.
|
||||
*
|
||||
* \return The POD read from \a vec at index \a pos
|
||||
*/
|
||||
|
||||
} /* namespace */
|
||||
|
||||
/**
|
||||
* \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(
|
||||
* const 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>::const_iterator dataBegin,
|
||||
* std::vector<uint8_t>::const_iterator dataEnd,
|
||||
* ControlSerializer *cs = nullptr)
|
||||
* \brief Deserialize byte vector into an object
|
||||
* \tparam T Type of object to deserialize to
|
||||
* \param[in] dataBegin Begin iterator of byte vector to deserialize from
|
||||
* \param[in] dataEnd 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(
|
||||
* const std::vector<uint8_t> &data,
|
||||
* const 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>::const_iterator dataBegin,
|
||||
* std::vector<uint8_t>::const_iterator dataEnd,
|
||||
* std::vector<int32_t>::const_iterator fdsBegin,
|
||||
* std::vector<int32_t>::const_iterator fdsEnd,
|
||||
* ControlSerializer *cs = nullptr)
|
||||
* \brief Deserialize byte vector and fd vector into an object
|
||||
* \tparam T Type of object to deserialize to
|
||||
* \param[in] dataBegin Begin iterator of byte vector to deserialize from
|
||||
* \param[in] dataEnd End iterator of byte vector to deserialize from
|
||||
* \param[in] fdsBegin Begin iterator of fd vector to deserialize from
|
||||
* \param[in] fdsEnd 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
|
||||
*/
|
||||
|
||||
#ifndef __DOXYGEN__
|
||||
|
||||
#define DEFINE_POD_SERIALIZER(type) \
|
||||
\
|
||||
template<> \
|
||||
std::tuple<std::vector<uint8_t>, std::vector<int32_t>> \
|
||||
IPADataSerializer<type>::serialize(const type &data, \
|
||||
[[maybe_unused]] ControlSerializer *cs) \
|
||||
{ \
|
||||
std::vector<uint8_t> dataVec; \
|
||||
dataVec.reserve(sizeof(type)); \
|
||||
appendPOD<type>(dataVec, data); \
|
||||
\
|
||||
return { dataVec, {} }; \
|
||||
} \
|
||||
\
|
||||
template<> \
|
||||
type IPADataSerializer<type>::deserialize(std::vector<uint8_t>::const_iterator dataBegin, \
|
||||
std::vector<uint8_t>::const_iterator dataEnd, \
|
||||
[[maybe_unused]] ControlSerializer *cs) \
|
||||
{ \
|
||||
return readPOD<type>(dataBegin, 0, dataEnd); \
|
||||
} \
|
||||
\
|
||||
template<> \
|
||||
type IPADataSerializer<type>::deserialize(const std::vector<uint8_t> &data, \
|
||||
ControlSerializer *cs) \
|
||||
{ \
|
||||
return deserialize(data.cbegin(), data.end(), cs); \
|
||||
} \
|
||||
\
|
||||
template<> \
|
||||
type IPADataSerializer<type>::deserialize(const std::vector<uint8_t> &data, \
|
||||
[[maybe_unused]] const std::vector<int32_t> &fds, \
|
||||
ControlSerializer *cs) \
|
||||
{ \
|
||||
return deserialize(data.cbegin(), data.end(), cs); \
|
||||
} \
|
||||
\
|
||||
template<> \
|
||||
type IPADataSerializer<type>::deserialize(std::vector<uint8_t>::const_iterator dataBegin, \
|
||||
std::vector<uint8_t>::const_iterator dataEnd, \
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsBegin, \
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsEnd, \
|
||||
ControlSerializer *cs) \
|
||||
{ \
|
||||
return deserialize(dataBegin, dataEnd, cs); \
|
||||
}
|
||||
|
||||
DEFINE_POD_SERIALIZER(bool)
|
||||
DEFINE_POD_SERIALIZER(uint8_t)
|
||||
DEFINE_POD_SERIALIZER(uint16_t)
|
||||
DEFINE_POD_SERIALIZER(uint32_t)
|
||||
DEFINE_POD_SERIALIZER(uint64_t)
|
||||
DEFINE_POD_SERIALIZER(int8_t)
|
||||
DEFINE_POD_SERIALIZER(int16_t)
|
||||
DEFINE_POD_SERIALIZER(int32_t)
|
||||
DEFINE_POD_SERIALIZER(int64_t)
|
||||
DEFINE_POD_SERIALIZER(float)
|
||||
DEFINE_POD_SERIALIZER(double)
|
||||
|
||||
/*
|
||||
* Strings are serialized simply by converting by {string.cbegin(), string.end()}.
|
||||
* The size of the string is recorded by the container (struct, vector, map, or
|
||||
* function parameter serdes).
|
||||
*/
|
||||
template<>
|
||||
std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
|
||||
IPADataSerializer<std::string>::serialize(const std::string &data,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
return { { data.cbegin(), data.end() }, {} };
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
IPADataSerializer<std::string>::deserialize(const std::vector<uint8_t> &data,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
return { data.cbegin(), data.cend() };
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
IPADataSerializer<std::string>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
return { dataBegin, dataEnd };
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
IPADataSerializer<std::string>::deserialize(const std::vector<uint8_t> &data,
|
||||
[[maybe_unused]] const std::vector<int32_t> &fds,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
return { data.cbegin(), data.cend() };
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
IPADataSerializer<std::string>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsBegin,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsEnd,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
return { dataBegin, dataEnd };
|
||||
}
|
||||
|
||||
/*
|
||||
* ControlList is serialized as:
|
||||
*
|
||||
* 4 bytes - uint32_t Size of serialized ControlInfoMap, in bytes
|
||||
* 4 bytes - uint32_t Size of serialized ControlList, in bytes
|
||||
* X bytes - Serialized ControlInfoMap (using ControlSerializer)
|
||||
* X bytes - Serialized ControlList (using ControlSerializer)
|
||||
*
|
||||
* If data.infoMap() is nullptr, then the default controls::controls will
|
||||
* be used. The serialized ControlInfoMap will have zero length.
|
||||
*/
|
||||
template<>
|
||||
std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
|
||||
IPADataSerializer<ControlList>::serialize(const ControlList &data, ControlSerializer *cs)
|
||||
{
|
||||
if (!cs)
|
||||
LOG(IPADataSerializer, Fatal)
|
||||
<< "ControlSerializer not provided for serialization of ControlList";
|
||||
|
||||
size_t size;
|
||||
std::vector<uint8_t> infoData;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* \todo Revisit this opportunistic serialization of the
|
||||
* ControlInfoMap, as it could be fragile
|
||||
*/
|
||||
if (data.infoMap() && !cs->isCached(*data.infoMap())) {
|
||||
size = cs->binarySize(*data.infoMap());
|
||||
infoData.resize(size);
|
||||
ByteStreamBuffer buffer(infoData.data(), infoData.size());
|
||||
ret = cs->serialize(*data.infoMap(), 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);
|
||||
ByteStreamBuffer buffer(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> dataVec;
|
||||
dataVec.reserve(8 + infoData.size() + listData.size());
|
||||
appendPOD<uint32_t>(dataVec, infoData.size());
|
||||
appendPOD<uint32_t>(dataVec, listData.size());
|
||||
dataVec.insert(dataVec.end(), infoData.begin(), infoData.end());
|
||||
dataVec.insert(dataVec.end(), listData.begin(), listData.end());
|
||||
|
||||
return { dataVec, {} };
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlList
|
||||
IPADataSerializer<ControlList>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
if (!cs)
|
||||
LOG(IPADataSerializer, Fatal)
|
||||
<< "ControlSerializer not provided for deserialization of ControlList";
|
||||
|
||||
if (std::distance(dataBegin, dataEnd) < 8)
|
||||
return {};
|
||||
|
||||
uint32_t infoDataSize = readPOD<uint32_t>(dataBegin, 0, dataEnd);
|
||||
uint32_t listDataSize = readPOD<uint32_t>(dataBegin, 4, dataEnd);
|
||||
|
||||
std::vector<uint8_t>::const_iterator it = dataBegin + 8;
|
||||
|
||||
if (infoDataSize + listDataSize < infoDataSize ||
|
||||
static_cast<uint32_t>(std::distance(it, dataEnd)) < infoDataSize + listDataSize)
|
||||
return {};
|
||||
|
||||
if (infoDataSize > 0) {
|
||||
ByteStreamBuffer buffer(&*it, infoDataSize);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
it += infoDataSize;
|
||||
ByteStreamBuffer buffer(&*it, listDataSize);
|
||||
ControlList list = cs->deserialize<ControlList>(buffer);
|
||||
if (buffer.overflow())
|
||||
LOG(IPADataSerializer, Error) << "Failed to deserialize ControlList: buffer overflow";
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlList
|
||||
IPADataSerializer<ControlList>::deserialize(const std::vector<uint8_t> &data,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), cs);
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlList
|
||||
IPADataSerializer<ControlList>::deserialize(const std::vector<uint8_t> &data,
|
||||
[[maybe_unused]] const std::vector<int32_t> &fds,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), cs);
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlList
|
||||
IPADataSerializer<ControlList>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsBegin,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsEnd,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(dataBegin, dataEnd, cs);
|
||||
}
|
||||
|
||||
/*
|
||||
* const ControlInfoMap is serialized as:
|
||||
*
|
||||
* 4 bytes - uint32_t Size of serialized ControlInfoMap, in bytes
|
||||
* X bytes - Serialized ControlInfoMap (using ControlSerializer)
|
||||
*/
|
||||
template<>
|
||||
std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
|
||||
IPADataSerializer<ControlInfoMap>::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()) {
|
||||
LOG(IPADataSerializer, Error) << "Failed to serialize ControlInfoMap";
|
||||
return { {}, {} };
|
||||
}
|
||||
|
||||
std::vector<uint8_t> dataVec;
|
||||
appendPOD<uint32_t>(dataVec, infoData.size());
|
||||
dataVec.insert(dataVec.end(), infoData.begin(), infoData.end());
|
||||
|
||||
return { dataVec, {} };
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlInfoMap
|
||||
IPADataSerializer<ControlInfoMap>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
if (!cs)
|
||||
LOG(IPADataSerializer, Fatal)
|
||||
<< "ControlSerializer not provided for deserialization of ControlInfoMap";
|
||||
|
||||
if (std::distance(dataBegin, dataEnd) < 4)
|
||||
return {};
|
||||
|
||||
uint32_t infoDataSize = readPOD<uint32_t>(dataBegin, 0, dataEnd);
|
||||
|
||||
std::vector<uint8_t>::const_iterator it = dataBegin + 4;
|
||||
|
||||
if (static_cast<uint32_t>(std::distance(it, dataEnd)) < infoDataSize)
|
||||
return {};
|
||||
|
||||
ByteStreamBuffer buffer(&*it, infoDataSize);
|
||||
ControlInfoMap map = cs->deserialize<ControlInfoMap>(buffer);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlInfoMap
|
||||
IPADataSerializer<ControlInfoMap>::deserialize(const std::vector<uint8_t> &data,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), cs);
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlInfoMap
|
||||
IPADataSerializer<ControlInfoMap>::deserialize(const std::vector<uint8_t> &data,
|
||||
[[maybe_unused]] const std::vector<int32_t> &fds,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), cs);
|
||||
}
|
||||
|
||||
template<>
|
||||
ControlInfoMap
|
||||
IPADataSerializer<ControlInfoMap>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsBegin,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsEnd,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(dataBegin, dataEnd, cs);
|
||||
}
|
||||
|
||||
/*
|
||||
* FileDescriptors are serialized into a single byte that tells if the
|
||||
* FileDescriptor is valid or not. If it is valid, then for serialization
|
||||
* the fd will be written to the fd vector, or for deserialization the
|
||||
* fd vector const_iterator will be valid.
|
||||
*
|
||||
* This validity is necessary so that we don't send -1 fd over sendmsg(). It
|
||||
* also allows us to simply send the entire fd vector into the deserializer
|
||||
* and it will be recursively consumed as necessary.
|
||||
*
|
||||
* \todo Consider serializing the FileDescriptor in 4 bytes to ensure
|
||||
* 32-bit alignment of all serialized data
|
||||
*/
|
||||
template<>
|
||||
std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
|
||||
IPADataSerializer<FileDescriptor>::serialize(const FileDescriptor &data,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
std::vector<uint8_t> dataVec = { data.isValid() };
|
||||
std::vector<int32_t> fdVec;
|
||||
if (data.isValid())
|
||||
fdVec.push_back(data.fd());
|
||||
|
||||
return { dataVec, fdVec };
|
||||
}
|
||||
|
||||
template<>
|
||||
FileDescriptor IPADataSerializer<FileDescriptor>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
std::vector<int32_t>::const_iterator fdsBegin,
|
||||
std::vector<int32_t>::const_iterator fdsEnd,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
ASSERT(std::distance(dataBegin, dataEnd) >= 1);
|
||||
|
||||
bool valid = !!(*dataBegin);
|
||||
|
||||
ASSERT(!(valid && std::distance(fdsBegin, fdsEnd) < 1));
|
||||
|
||||
return valid ? FileDescriptor(*fdsBegin) : FileDescriptor();
|
||||
}
|
||||
|
||||
template<>
|
||||
FileDescriptor IPADataSerializer<FileDescriptor>::deserialize(const std::vector<uint8_t> &data,
|
||||
const std::vector<int32_t> &fds,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end());
|
||||
}
|
||||
|
||||
/*
|
||||
* FrameBuffer::Plane is serialized as:
|
||||
*
|
||||
* 1 byte - FileDescriptor
|
||||
* 4 bytes - uint32_t Length
|
||||
*/
|
||||
template<>
|
||||
std::tuple<std::vector<uint8_t>, std::vector<int32_t>>
|
||||
IPADataSerializer<FrameBuffer::Plane>::serialize(const FrameBuffer::Plane &data,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
std::vector<uint8_t> dataVec;
|
||||
std::vector<int32_t> fdsVec;
|
||||
|
||||
std::vector<uint8_t> fdBuf;
|
||||
std::vector<int32_t> fdFds;
|
||||
std::tie(fdBuf, fdFds) =
|
||||
IPADataSerializer<FileDescriptor>::serialize(data.fd);
|
||||
dataVec.insert(dataVec.end(), fdBuf.begin(), fdBuf.end());
|
||||
fdsVec.insert(fdsVec.end(), fdFds.begin(), fdFds.end());
|
||||
|
||||
appendPOD<uint32_t>(dataVec, data.length);
|
||||
|
||||
return { dataVec, fdsVec };
|
||||
}
|
||||
|
||||
template<>
|
||||
FrameBuffer::Plane
|
||||
IPADataSerializer<FrameBuffer::Plane>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
||||
std::vector<uint8_t>::const_iterator dataEnd,
|
||||
std::vector<int32_t>::const_iterator fdsBegin,
|
||||
[[maybe_unused]] std::vector<int32_t>::const_iterator fdsEnd,
|
||||
[[maybe_unused]] ControlSerializer *cs)
|
||||
{
|
||||
FrameBuffer::Plane ret;
|
||||
|
||||
ret.fd = IPADataSerializer<FileDescriptor>::deserialize(dataBegin, dataBegin + 1,
|
||||
fdsBegin, fdsBegin + 1);
|
||||
ret.length = readPOD<uint32_t>(dataBegin, 1, dataEnd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<>
|
||||
FrameBuffer::Plane
|
||||
IPADataSerializer<FrameBuffer::Plane>::deserialize(const std::vector<uint8_t> &data,
|
||||
const std::vector<int32_t> &fds,
|
||||
ControlSerializer *cs)
|
||||
{
|
||||
return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs);
|
||||
}
|
||||
|
||||
#endif /* __DOXYGEN__ */
|
||||
|
||||
} /* namespace libcamera */
|
|
@ -26,6 +26,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',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue