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__ */
|
Loading…
Add table
Add a link
Reference in a new issue