Regarding (de)serialization in isolated IPA calls, we have four layers: - struct - byte vector + fd vector - IPCMessage - IPC payload The proxy handles the upper three layers (with help from the IPADataSerializer), and passes an IPCMessage to the IPC mechanism (implemented as an IPCPipe), which sends an IPC payload to its worker counterpart. When a FileDescriptor is involved, previously it was only a FileDescriptor in the first layer; in the lower three it was an int. To reduce the risk of potential fd leaks in the future, keep the FileDescriptor as-is throughout the upper three layers. Only the IPC mechanism will deal with ints, if it so wishes, when it does the actual IPC. IPCPipeUnixSocket does deal with ints for sending fds, so the conversion between IPCMessage and IPCUnixSocket::Payload converts between FileDescriptor and int. Additionally, change the data portion of the serialized form of FileDescriptor to a 32-bit unsigned integer, for alightnment purposes and in preparation for conversion to an index into the fd array. Also update the deserializer of FrameBuffer::Plane accordingly. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Tested-by: Umang Jain <umang.jain@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
309 lines
8.8 KiB
C++
309 lines
8.8 KiB
C++
/* 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/base/log.h>
|
|
|
|
#include <libcamera/control_ids.h>
|
|
#include <libcamera/framebuffer.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"
|
|
|
|
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<FileDescriptor>>
|
|
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<FileDescriptor> &fds,
|
|
ControlSerializer *cs = nullptr);
|
|
static T deserialize(std::vector<uint8_t>::const_iterator dataBegin,
|
|
std::vector<uint8_t>::const_iterator dataEnd,
|
|
std::vector<FileDescriptor>::const_iterator fdsBegin,
|
|
std::vector<FileDescriptor>::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<FileDescriptor>>
|
|
serialize(const std::vector<V> &data, ControlSerializer *cs = nullptr)
|
|
{
|
|
std::vector<uint8_t> dataVec;
|
|
std::vector<FileDescriptor> 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<FileDescriptor> 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<FileDescriptor> fds;
|
|
return deserialize(dataBegin, dataEnd, fds.cbegin(), fds.end(), cs);
|
|
}
|
|
|
|
static std::vector<V> deserialize(std::vector<uint8_t> &data, std::vector<FileDescriptor> &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<FileDescriptor>::const_iterator fdsBegin,
|
|
[[maybe_unused]] std::vector<FileDescriptor>::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<FileDescriptor>::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<FileDescriptor>>
|
|
serialize(const std::map<K, V> &data, ControlSerializer *cs = nullptr)
|
|
{
|
|
std::vector<uint8_t> dataVec;
|
|
std::vector<FileDescriptor> 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<FileDescriptor> 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<FileDescriptor> fds;
|
|
return deserialize(dataBegin, dataEnd, fds.cbegin(), fds.end(), cs);
|
|
}
|
|
|
|
static std::map<K, V> deserialize(std::vector<uint8_t> &data, std::vector<FileDescriptor> &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<FileDescriptor>::const_iterator fdsBegin,
|
|
[[maybe_unused]] std::vector<FileDescriptor>::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<FileDescriptor>::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__ */
|