Now that we have a UniqueFD class, the name FileDescriptor is ambiguous. Rename it to SharedFD. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Hirokazu Honda <hiroh@chromium.org> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
626 lines
19 KiB
C++
626 lines
19 KiB
C++
/* 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 <unistd.h>
|
|
|
|
#include <libcamera/base/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 SharedFDs, 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 SharedFD.
|
|
*
|
|
* \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 SharedFD.
|
|
*
|
|
* \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<SharedFD> &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 SharedFD.
|
|
*
|
|
* \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<SharedFD>::const_iterator fdsBegin,
|
|
* std::vector<SharedFD>::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 SharedFD.
|
|
*
|
|
* \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<SharedFD>> \
|
|
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<SharedFD> &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<SharedFD>::const_iterator fdsBegin, \
|
|
[[maybe_unused]] std::vector<SharedFD>::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<SharedFD>>
|
|
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<SharedFD> &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<SharedFD>::const_iterator fdsBegin,
|
|
[[maybe_unused]] std::vector<SharedFD>::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<SharedFD>>
|
|
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<SharedFD> &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<SharedFD>::const_iterator fdsBegin,
|
|
[[maybe_unused]] std::vector<SharedFD>::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<SharedFD>>
|
|
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<SharedFD> &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<SharedFD>::const_iterator fdsBegin,
|
|
[[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
|
|
ControlSerializer *cs)
|
|
{
|
|
return deserialize(dataBegin, dataEnd, cs);
|
|
}
|
|
|
|
/*
|
|
* SharedFD instances are serialized into four bytes that tells if the SharedFD
|
|
* 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.
|
|
*/
|
|
template<>
|
|
std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
|
|
IPADataSerializer<SharedFD>::serialize(const SharedFD &data,
|
|
[[maybe_unused]] ControlSerializer *cs)
|
|
{
|
|
std::vector<uint8_t> dataVec;
|
|
std::vector<SharedFD> fdVec;
|
|
|
|
/*
|
|
* Store as uint32_t to prepare for conversion from validity flag
|
|
* to index, and for alignment.
|
|
*/
|
|
appendPOD<uint32_t>(dataVec, data.isValid());
|
|
|
|
if (data.isValid())
|
|
fdVec.push_back(data);
|
|
|
|
|
|
return { dataVec, fdVec };
|
|
}
|
|
|
|
template<>
|
|
SharedFD IPADataSerializer<SharedFD>::deserialize([[maybe_unused]] std::vector<uint8_t>::const_iterator dataBegin,
|
|
[[maybe_unused]] std::vector<uint8_t>::const_iterator dataEnd,
|
|
std::vector<SharedFD>::const_iterator fdsBegin,
|
|
std::vector<SharedFD>::const_iterator fdsEnd,
|
|
[[maybe_unused]] ControlSerializer *cs)
|
|
{
|
|
ASSERT(std::distance(dataBegin, dataEnd) >= 4);
|
|
|
|
uint32_t valid = readPOD<uint32_t>(dataBegin, 0, dataEnd);
|
|
|
|
ASSERT(!(valid && std::distance(fdsBegin, fdsEnd) < 1));
|
|
|
|
return valid ? *fdsBegin : SharedFD();
|
|
}
|
|
|
|
template<>
|
|
SharedFD IPADataSerializer<SharedFD>::deserialize(const std::vector<uint8_t> &data,
|
|
const std::vector<SharedFD> &fds,
|
|
[[maybe_unused]] ControlSerializer *cs)
|
|
{
|
|
return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end());
|
|
}
|
|
|
|
/*
|
|
* FrameBuffer::Plane is serialized as:
|
|
*
|
|
* 4 byte - SharedFD
|
|
* 4 bytes - uint32_t Offset
|
|
* 4 bytes - uint32_t Length
|
|
*/
|
|
template<>
|
|
std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
|
|
IPADataSerializer<FrameBuffer::Plane>::serialize(const FrameBuffer::Plane &data,
|
|
[[maybe_unused]] ControlSerializer *cs)
|
|
{
|
|
std::vector<uint8_t> dataVec;
|
|
std::vector<SharedFD> fdsVec;
|
|
|
|
std::vector<uint8_t> fdBuf;
|
|
std::vector<SharedFD> fdFds;
|
|
std::tie(fdBuf, fdFds) =
|
|
IPADataSerializer<SharedFD>::serialize(data.fd);
|
|
dataVec.insert(dataVec.end(), fdBuf.begin(), fdBuf.end());
|
|
fdsVec.insert(fdsVec.end(), fdFds.begin(), fdFds.end());
|
|
|
|
appendPOD<uint32_t>(dataVec, data.offset);
|
|
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<SharedFD>::const_iterator fdsBegin,
|
|
[[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
|
|
[[maybe_unused]] ControlSerializer *cs)
|
|
{
|
|
FrameBuffer::Plane ret;
|
|
|
|
ret.fd = IPADataSerializer<SharedFD>::deserialize(dataBegin, dataBegin + 4,
|
|
fdsBegin, fdsBegin + 1);
|
|
ret.offset = readPOD<uint32_t>(dataBegin, 4, dataEnd);
|
|
ret.length = readPOD<uint32_t>(dataBegin, 8, dataEnd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
template<>
|
|
FrameBuffer::Plane
|
|
IPADataSerializer<FrameBuffer::Plane>::deserialize(const std::vector<uint8_t> &data,
|
|
const std::vector<SharedFD> &fds,
|
|
ControlSerializer *cs)
|
|
{
|
|
return deserialize(data.cbegin(), data.end(), fds.cbegin(), fds.end(), cs);
|
|
}
|
|
|
|
#endif /* __DOXYGEN__ */
|
|
|
|
} /* namespace libcamera */
|