From patchwork Tue Sep 22 13:35:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 9717 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 6B5EFBF01C for ; Tue, 22 Sep 2020 13:37:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3872762FD8; Tue, 22 Sep 2020 15:37:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="pfW9Denm"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 513AB60576 for ; Tue, 22 Sep 2020 15:37:24 +0200 (CEST) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 36ED32D7; Tue, 22 Sep 2020 15:37:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1600781839; bh=hmtcYdfePNftsI7XTR24w4+Mj0YCEquS7pyPJMp1KrM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pfW9Denm0JZxpouSmQJMK4xDqvwbS0O+8nshBnean9Hu4C3SbrAPITXmqo8UKu+hI pOrm2ofS85c0LIHCjLQlfoYOdPvWMLGANiw4/HWVwHFi3j1+zGD3uYIq7OK96rcpGF aaOiLWLX4kwbTBt64Uc/DHmXp6OCn8f0yp6JvEx8= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 22 Sep 2020 22:35:12 +0900 Message-Id: <20200922133537.258098-14-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200922133537.258098-1-paul.elder@ideasonboard.com> References: <20200922133537.258098-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 13/38] libcamera: Add IPADataSerializer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add an IPADataSerializer which implments de/serialization of built-in 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 --- 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 | 1220 +++++++++++++++++ src/libcamera/ipa_data_serializer.cpp | 154 +++ src/libcamera/meson.build | 1 + 3 files changed, 1375 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..accd4dce --- /dev/null +++ b/include/libcamera/internal/ipa_data_serializer.h @@ -0,0 +1,1220 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include + +#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 +void appendUInt(std::vector &vec, T val) +{ + size_t byteWidth = sizeof(val); + for (size_t i = 0; i < byteWidth; i++) + vec.push_back(static_cast((val >> 8*i) & 0xff)); +} + +template +T readUInt(std::vector &vec, size_t pos) +{ + T ret = 0; + size_t byteWidth = sizeof(ret); + if (pos + byteWidth > vec.size()) + return ret; + + for (size_t i = 0; i < byteWidth; i++) + ret |= vec[pos + i] << 8*i; + return ret; +} + +template +T readUInt(std::vector::iterator it) +{ + T ret = 0; + size_t byteWidth = sizeof(ret); + for (size_t i = 0; i < byteWidth; i++) + ret |= *(it + i) << 8*i; + return ret; +} + +template +class IPADataSerializer +{ +#ifdef __DOXYGEN__ +public: + static std::tuple, std::vector> + serialize(T data, ControlSerializer *cs); + + static T deserialize(std::vector &data, + ControlSerializer *cs); + static T deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs); + + static T deserialize(std::vector &data, + std::vector &fds, + ControlSerializer *cs); + static T deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + std::vector::iterator fds_it1, + std::vector::iterator fds_it2, + ControlSerializer *cs); +#endif /* __DOXYGEN__ */ +}; + +#ifndef __DOXYGEN__ + +template +class IPADataSerializer> +{ +public: + static std::tuple, std::vector> + serialize(const std::vector &data, ControlSerializer *cs = nullptr) + { + std::vector data_vec; + std::vector fds_vec; + + // serialize the length + uint32_t vec_len = data.size(); + appendUInt(data_vec, vec_len); + + // serialize the members + for (auto it = data.begin(); it != data.end(); ++it) { + std::vector dvec; + std::vector fvec; + + std::tie(dvec, fvec) = + IPADataSerializer::serialize(*it, cs); + + appendUInt(data_vec, dvec.size()); + appendUInt(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 deserialize(std::vector &data, ControlSerializer *cs = nullptr) + { + return IPADataSerializer>::deserialize(data.begin(), data.end(), cs); + } + + static std::vector deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs = nullptr) + { + std::vector fds; + return IPADataSerializer>::deserialize(it1, it2, + fds.begin(), fds.end(), + cs); + } + + static std::vector deserialize(std::vector &data, std::vector &fds, + ControlSerializer *cs = nullptr) + { + return IPADataSerializer>::deserialize(data.begin(), data.end(), + fds.begin(), fds.end(), + cs); + } + + static std::vector deserialize(std::vector::iterator data_it1, + [[maybe_unused]] std::vector::iterator data_it2, + std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + ControlSerializer *cs = nullptr) + { + uint32_t vec_len = readUInt(data_it1); + std::vector ret(vec_len); + + std::vector::iterator data_it = data_it1 + 4; + std::vector::iterator fd_it = fds_it1; + for (uint32_t i = 0; i < vec_len; i++) { + uint32_t sizeof_data = readUInt(data_it); + uint32_t sizeof_fds = readUInt(data_it + 4); + + ret[i] = IPADataSerializer::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 +class IPADataSerializer> +{ +public: + static std::tuple, std::vector> + serialize(const std::map &data, ControlSerializer *cs = nullptr) + { + std::vector data_vec; + std::vector fds_vec; + + // serialize the length + uint32_t map_len = data.size(); + appendUInt(data_vec, map_len); + + // serialize the members + for (auto it = data.begin(); it != data.end(); ++it) { + std::vector dvec; + std::vector fvec; + + std::tie(dvec, fvec) = + IPADataSerializer::serialize(it->first, cs); + + appendUInt(data_vec, dvec.size()); + appendUInt(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::serialize(it->second, cs); + + appendUInt(data_vec, dvec.size()); + appendUInt(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 deserialize(std::vector &data, ControlSerializer *cs = nullptr) + { + return IPADataSerializer>::deserialize(data.begin(), data.end(), cs); + } + + static std::map deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs = nullptr) + { + std::vector fds; + return IPADataSerializer>::deserialize(it1, it2, + fds.begin(), fds.end(), + cs); + } + + static std::map deserialize(std::vector &data, std::vector &fds, + ControlSerializer *cs = nullptr) + { + return IPADataSerializer>::deserialize(data.begin(), data.end(), + fds.begin(), fds.end(), + cs); + } + + static std::map deserialize(std::vector::iterator data_it1, + [[maybe_unused]] std::vector::iterator data_it2, + std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + ControlSerializer *cs = nullptr) + { + std::map ret; + + uint32_t map_len = readUInt(data_it1); + + std::vector::iterator data_it = data_it1 + 4; + std::vector::iterator fd_it = fds_it1; + for (uint32_t i = 0; i < map_len; i++) { + uint32_t sizeof_data = readUInt(data_it); + uint32_t sizeof_fds = readUInt(data_it + 4); + + K key = IPADataSerializer::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(data_it); + sizeof_fds = readUInt(data_it + 4); + + const V value = IPADataSerializer::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_INTEGRAL_SERIALIZER(type) \ +template<> \ +class IPADataSerializer \ +{ \ +public: \ + static std::tuple, std::vector> \ + serialize(const type data, \ + [[maybe_unused]] ControlSerializer *cs = nullptr) \ + { \ + std::vector data_vec; \ + appendUInt(data_vec, data); \ + \ + return {data_vec, {}}; \ + } \ + \ + static type deserialize(std::vector &data, \ + [[maybe_unused]] ControlSerializer *cs = nullptr)\ + { \ + return IPADataSerializer::deserialize(data.begin(),\ + data.end());\ + } \ + \ + static type deserialize(std::vector::iterator it1, \ + [[maybe_unused]] std::vector::iterator it2,\ + [[maybe_unused]] ControlSerializer *cs = nullptr)\ + { \ + return readUInt(it1); \ + } \ + \ + static type deserialize(std::vector &data, \ + [[maybe_unused]] std::vector &fds,\ + [[maybe_unused]] ControlSerializer *cs = nullptr)\ + { \ + return IPADataSerializer::deserialize(data.begin(),\ + data.end());\ + } \ + \ + static type deserialize(std::vector::iterator data_it1,\ + std::vector::iterator data_it2,\ + [[maybe_unused]] std::vector::iterator fds_it1,\ + [[maybe_unused]] std::vector::iterator fds_it2,\ + [[maybe_unused]] ControlSerializer *cs = nullptr)\ + { \ + return IPADataSerializer::deserialize(data_it1, \ + data_it2); \ + } \ +}; + +DECLARE_INTEGRAL_SERIALIZER(uint8_t) +DECLARE_INTEGRAL_SERIALIZER(uint16_t) +DECLARE_INTEGRAL_SERIALIZER(uint32_t) +DECLARE_INTEGRAL_SERIALIZER(uint64_t) +DECLARE_INTEGRAL_SERIALIZER(int8_t) +DECLARE_INTEGRAL_SERIALIZER(int16_t) +DECLARE_INTEGRAL_SERIALIZER(int32_t) + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const int64_t data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec; + appendUInt(data_vec, data); + + return {data_vec, {}}; + } + + static int64_t deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), + data.end()); + } + + static int64_t deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + if (std::distance(it1, it2) < 8) { + LOG(IPADataSerializer, Info) + << "Not enough bytes to deserialize int64_t, returning 0"; + return 0; + } + + uint32_t lower = readUInt(it1); + uint32_t upper = readUInt(it1 + 4); + + return lower + (uint64_t(upper) << 32); + } + + static int64_t deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), + data.end()); + } + + static int64_t deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const bool data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec; + appendUInt(data_vec, data); + + return {data_vec, {}}; + } + + static bool deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), + data.end()); + } + + static bool deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return readUInt(it1); + } + + static bool deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), + data.end()); + } + + static bool deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const float data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + uint8_t arr[4]; + memcpy(arr, &data, sizeof(arr)); + + std::vector data_vec(arr, arr + 4); + + return {data_vec, {}}; + } + + static float deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static float deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + if (std::distance(it1, it2) < 4) { + LOG(IPADataSerializer, Info) + << "Not enough bytes to deserialize float, returning 0"; + return 0; + } + + std::vector data(it1, it2); + float ret; + memcpy(&ret, data.data(), sizeof(ret)); + + return ret; + } + + static float deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static float deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const double data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + uint8_t arr[8]; + memcpy(arr, &data, sizeof(arr)); + + std::vector data_vec(arr, arr + 8); + + return {data_vec, {}}; + } + + static double deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static double deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + if (std::distance(it1, it2) < 8) { + LOG(IPADataSerializer, Info) + << "Not enough bytes to deserialize double, returning 0"; + return 0; + } + + std::vector data(it1, it2); + double ret; + memcpy(&ret, data.data(), sizeof(ret)); + + return ret; + } + + static double deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static double deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const std::string &data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec(data.begin(), data.end()); + + return {data_vec, {}}; + } + + static std::string deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static std::string deserialize(std::vector::iterator it1, + std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::string str(it1, it2); + + return str; + } + + static std::string deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static std::string deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const FileDescriptor &data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec = { data.isValid() }; + std::vector fd_vec; + if (data.isValid()) + fd_vec.push_back(data.fd()); + + return {data_vec, fd_vec}; + } + + static FileDescriptor deserialize(std::vector &data, std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), + fds.begin(), fds.end()); + } + + static FileDescriptor deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + std::vector::iterator fds_it1, + std::vector::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 +{ +public: + static std::tuple, std::vector> + serialize(const IPASettings &data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::serialize(data.configurationFile); + } + + static IPASettings deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static IPASettings deserialize(std::vector::iterator it1, + std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + IPASettings ret; + ret.configurationFile = IPADataSerializer::deserialize(it1, it2); + + return ret; + } + + static IPASettings deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static IPASettings deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const CameraSensorInfo &data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec; + + uint32_t str_len = data.model.size(); + appendUInt(data_vec, str_len); + + data_vec.insert(data_vec.end(), data.model.begin(), data.model.end()); + + appendUInt(data_vec, data.bitsPerPixel); + + appendUInt(data_vec, data.activeAreaSize.width); + appendUInt(data_vec, data.activeAreaSize.height); + + appendUInt(data_vec, static_cast(data.analogCrop.x)); + appendUInt(data_vec, static_cast(data.analogCrop.y)); + appendUInt(data_vec, data.analogCrop.width); + appendUInt(data_vec, data.analogCrop.height); + + appendUInt(data_vec, data.outputSize.width); + appendUInt(data_vec, data.outputSize.height); + + appendUInt(data_vec, data.pixelRate); + + appendUInt(data_vec, data.lineLength); + + return {data_vec, {}}; + } + + static CameraSensorInfo deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static CameraSensorInfo deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + CameraSensorInfo ret; + + uint32_t str_len = readUInt(it1); + std::string str(it1 + 4, it1 + 4 + str_len); + ret.model = str; + + std::vector::iterator it = it1 + 4 + str_len; + + ret.bitsPerPixel = readUInt(it); + + ret.activeAreaSize.width = readUInt(it + 4); + ret.activeAreaSize.height = readUInt(it + 8); + + ret.analogCrop.x = static_cast(readUInt(it + 12)); + ret.analogCrop.y = static_cast(readUInt(it + 16)); + ret.analogCrop.width = readUInt(it + 20); + ret.analogCrop.height = readUInt(it + 24); + + ret.outputSize.width = readUInt(it + 28); + ret.outputSize.height = readUInt(it + 32); + + ret.pixelRate = readUInt(it + 36); + + ret.lineLength = readUInt(it + 44); + + return ret; + } + + static CameraSensorInfo deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static CameraSensorInfo deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const IPAStream &data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec; + + appendUInt(data_vec, data.pixelFormat); + + appendUInt(data_vec, data.size.width); + appendUInt(data_vec, data.size.height); + + return {data_vec, {}}; + } + + static IPAStream deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static IPAStream deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + IPAStream ret; + + ret.pixelFormat = readUInt(it1); + + ret.size.width = readUInt(it1 + 4); + ret.size.height = readUInt(it1 + 8); + + return ret; + } + + static IPAStream deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static IPAStream deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data_it1, data_it2); + } +}; + +template<> +class IPADataSerializer +{ +public: + // map arg will be generated, since it's per-pipeline anyway + static std::tuple, std::vector> + 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 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 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 data_vec; + appendUInt(data_vec, infoData.size()); + appendUInt(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 &data, ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), cs); + } + + static const ControlList deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + ControlSerializer *cs) + { + if (!cs) + LOG(IPADataSerializer, Fatal) + << "ControlSerializer not provided for deserialization of ControlList"; + + uint32_t infoDataSize = readUInt(it1); + uint32_t listDataSize = readUInt(it1 + 4); + + std::vector::iterator it = it1 + 8; + + std::vector infoData(it, it + infoDataSize); + std::vector listData(it + infoDataSize, it + infoDataSize + listDataSize); + + ByteStreamBuffer buffer(const_cast(infoData.data()), infoData.size()); + ControlInfoMap map = cs->deserialize(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(listData.data()), listData.size()); + ControlList list = cs->deserialize(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 &data, + [[maybe_unused]] std::vector &fds, + ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), cs); + } + + static const ControlList deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data_it1, data_it2, cs); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const ControlList &data, const ControlInfoMap &map, + ControlSerializer *cs) + { + const ControlList &list_const = const_cast(data); + + std::vector data_vec; + std::tie(data_vec, std::ignore) = + IPADataSerializer::serialize(list_const, map, cs); + + return {data_vec, {}}; + } + + static ControlList deserialize(std::vector &data, + ControlSerializer *cs) + { + ControlList ret; + const ControlList &list = ret; + const_cast(list) = + IPADataSerializer::deserialize(data, cs); + + return ret; + } + + static ControlList deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + ControlSerializer *cs) + { + ControlList ret; + const ControlList &list = ret; + const_cast(list) = + IPADataSerializer::deserialize(it1, it2, cs); + + return ret; + } + + static ControlList deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + ControlSerializer *cs) + { + ControlList ret; + const ControlList &list = ret; + const_cast(list) = + IPADataSerializer::deserialize(data, fds, cs); + + return ret; + } + + static ControlList deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + ControlSerializer *cs) + { + ControlList ret; + const ControlList &list = ret; + const_cast(list) = + IPADataSerializer::deserialize(data_it1, data_it2, + fds_it1, fds_it2, cs); + + return ret; + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + 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 infoData(size); + ByteStreamBuffer buffer(infoData.data(), infoData.size()); + int ret = cs->serialize(map, buffer); + + if (ret < 0 || buffer.overflow()) + return {{}, {}}; + + std::vector data_vec; + appendUInt(data_vec, infoData.size()); + data_vec.insert(data_vec.end(), infoData.begin(), infoData.end()); + + return {data_vec, {}}; + } + + static const ControlInfoMap deserialize(std::vector &data, + ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), cs); + } + + static const ControlInfoMap deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + ControlSerializer *cs) + { + if (!cs) + LOG(IPADataSerializer, Fatal) + << "ControlSerializer not provided for deserialization of ControlInfoMap"; + + uint32_t infoDataSize = readUInt(it1); + + std::vector::iterator it = it1 + 4; + + std::vector infoData(it, it + infoDataSize); + + ByteStreamBuffer buffer(const_cast(infoData.data()), infoData.size()); + const ControlInfoMap map = cs->deserialize(buffer); + + return map; + } + + static const ControlInfoMap deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), cs); + } + + static const ControlInfoMap deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data_it1, data_it2, cs); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const ControlInfoMap &map, [[maybe_unused]] ControlSerializer *cs) + { + const ControlInfoMap &map_const = const_cast(map); + + std::vector data_vec; + std::tie(data_vec, std::ignore) = + IPADataSerializer::serialize(map_const, cs); + + return {data_vec, {}}; + } + + static ControlInfoMap deserialize(std::vector &data, + ControlSerializer *cs) + { + ControlInfoMap ret; + const ControlInfoMap &map = ret; + const_cast(map) = + IPADataSerializer::deserialize(data, cs); + + return ret; + } + + static ControlInfoMap deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + ControlSerializer *cs) + { + ControlInfoMap ret; + const ControlInfoMap &map = ret; + const_cast(map) = + IPADataSerializer::deserialize(it1, it2, cs); + + return ret; + } + + static ControlInfoMap deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + ControlSerializer *cs) + { + ControlInfoMap ret; + const ControlInfoMap &map = ret; + const_cast(map) = + IPADataSerializer::deserialize(data, fds, cs); + + return ret; + } + + static ControlInfoMap deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + [[maybe_unused]] std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + ControlSerializer *cs) + { + ControlInfoMap ret; + const ControlInfoMap &map = ret; + const_cast(map) = + IPADataSerializer::deserialize(data_it1, data_it2, + fds_it1, fds_it2, cs); + + return ret; + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const FrameBuffer::Plane &data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec; + std::vector fds_vec; + + // fd + std::vector fdBuf; + std::vector fdFds; + std::tie(fdBuf, fdFds) = + IPADataSerializer::serialize(data.fd); + data_vec.insert(data_vec.end(), fdBuf.begin(), fdBuf.end()); + fds_vec.insert(fds_vec.end(), fdFds.begin(), fdFds.end()); + + // length + appendUInt(data_vec, data.length); + + return {data_vec, fds_vec}; + } + + static FrameBuffer::Plane deserialize(std::vector &data, + std::vector &fds, + ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), + fds.begin(), fds.end(), + cs); + } + + static FrameBuffer::Plane deserialize(std::vector::iterator data_it1, + [[maybe_unused]] std::vector::iterator data_it2, + std::vector::iterator fds_it1, + [[maybe_unused]] std::vector::iterator fds_it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + FrameBuffer::Plane ret; + + ret.fd = IPADataSerializer::deserialize(data_it1, data_it1 + 1, + fds_it1, fds_it1 + 1); + ret.length = readUInt(data_it1 + 1); + + return ret; + } +}; + + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const IPABuffer &data, ControlSerializer *cs = nullptr) + { + std::vector data_vec; + + appendUInt(data_vec, data.id); + + std::vector planes_data_vec; + std::vector planes_fds_vec; + std::tie(planes_data_vec, planes_fds_vec) = + IPADataSerializer>::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 &data, + std::vector &fds, + ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), + fds.begin(), fds.end(), cs); + } + + static IPABuffer deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + std::vector::iterator fds_it1, + std::vector::iterator fds_it2, + ControlSerializer *cs = nullptr) + { + IPABuffer ret; + + ret.id = readUInt(data_it1); + + ret.planes = + IPADataSerializer>::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 void appendUInt(std::vector &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 T readUInt(std::vector &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 T readUInt(std::vector::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 IPADataSerializer::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 IPADataSerializer::deserialize( + * std::vector &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 IPADataSerializer::deserialize( + * std::vector::iterator it1, + * std::vector::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 IPADataSerializer::deserialize( + * std::vector &data, + * std::vector &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 IPADataSerializer::deserialize( + * std::vector::iterator data_it1, + * std::vector::iterator data_it2, + * std::vector::iterator fds_it1, + * std::vector::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 9d7442fa..61aad08e 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -23,6 +23,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',