From patchwork Wed Aug 26 11:09:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 9388 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 AC099BD87E for ; Wed, 26 Aug 2020 11:09:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 76FEA628F9; Wed, 26 Aug 2020 13:09:59 +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="DuvBpjE1"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8DD2C6037B for ; Wed, 26 Aug 2020 13:09:58 +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 2000B53C; Wed, 26 Aug 2020 13:09:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1598440198; bh=3I8Uvtq2XBRUqzTBotDWXcSdqJubJfUIb63/4k3Coo4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DuvBpjE1JlFfuHAAHw0ayeUuqsw1p8u1VkAuBnlnLkfZ7olTJ6go49DR3GAyC0U3C lOrOUF/e/wIOdJ+W86Pol9VylPs+dRUmgCEzmO8RZDxTkj39p2lBtGWdZ1mm82oEWz sd+ZFMQ8Hngn6ddQF+pSIMDdIQBwe5udEGp4Gv7U= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 26 Aug 2020 20:09:13 +0900 Message-Id: <20200826110926.67192-5-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200826110926.67192-1-paul.elder@ideasonboard.com> References: <20200826110926.67192-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 04/17] IPA: IPC: 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" This patch adds IPADataSerializer. It is a template class that implements de/serialization. ipa_data_serializer.h implements de/serialization for libcamera classes and primitives. This is handwritten, and if there is any demand for any more stuctures to be added, they must be added by hand. There was some debate as to whether this should use some well-known wire format, such as mojo or flatbuffers. As for a pre-made de/serializer, such as flatbuffers that I used in the last RFC, we noticed that I had to wrap the serialization anyway, so I decided I might as well just do the whole thing and throw flatbuffers out the window. To my knowledge, there is no serdes framework that can actually use generate serdes code for a pre-defined class, except mojo, which we can't use :) So since I had to implement manual serialization anyway, I could've followed a pre-existing standard. I didn't, but this can be changed. To get this RFC out I just did a simple wire format. I also think that the only merit to following a standard format is for performance, since we're going to be wrapping both sides of the IPC pipe in IPAProxy and IPAProxyWorker, so it's not like the world is going to see the wire format. raspberrypi_serializer.h will be generated based on the mojo file seen in the last patch. Other than that, it is conceptually the same as ipa_data_serializer.h. This header will be included by the generated IPA proxy and proxy worker so that they can de/serialize the data when then call into IPC. Signed-off-by: Paul Elder --- .../libcamera/internal/ipa_data_serializer.h | 816 ++++++++++++++++++ .../libcamera/ipa/raspberrypi_serializer.h | 487 +++++++++++ src/libcamera/ipa_data_serializer.cpp | 29 + 3 files changed, 1332 insertions(+) create mode 100644 include/libcamera/internal/ipa_data_serializer.h create mode 100644 include/libcamera/ipa/raspberrypi_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..368a398b --- /dev/null +++ b/include/libcamera/internal/ipa_data_serializer.h @@ -0,0 +1,816 @@ +/* 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" + +#include + +template std::ostream &operator<<(std::ostream &stream, const std::vector &vec) +{ + stream << "{ "; + for (const T &v : vec) + stream << std::hex << std::setfill('0') << std::setw(2) << static_cast(v) << ", "; + + stream << " }"; + return stream; +} + +namespace libcamera { + +LOG_DECLARE_CATEGORY(IPADataSerializer) + +static void appendUint32(std::vector &vec, uint32_t val) +{ + for (int i = 0; i < 4; i++) + vec.push_back(static_cast((val >> 8*i) & 0xff)); +} + +static void appendUint64(std::vector &vec, uint64_t val) +{ + for (int i = 0; i < 8; i++) + vec.push_back(static_cast((val >> 8*i) & 0xff)); +} + +static uint32_t extractUint32(std::vector::iterator it) +{ + uint32_t ret = 0; + for (int i = 0; i < 4; i++) + ret |= *(it + i) << 8*i; + return ret; +} + +static uint64_t extractUint64(std::vector::iterator it) +{ + uint32_t ret = 0; + for (int i = 0; i < 8; i++) + ret |= *(it + i) << 8*i; + return ret; +} + +template +class IPADataSerializer +{ +}; + +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(); + appendUint32(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); + + appendUint32(data_vec, dvec.size()); + appendUint32(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 = extractUint32(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 = extractUint32(data_it); + uint32_t sizeof_fds = extractUint32(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(); + appendUint32(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); + + appendUint32(data_vec, dvec.size()); + appendUint32(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); + + appendUint32(data_vec, dvec.size()); + appendUint32(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 = extractUint32(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 = extractUint32(data_it); + uint32_t sizeof_fds = extractUint32(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 = extractUint32(data_it); + sizeof_fds = extractUint32(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; + } +}; + +// TODO implement this for all primitives +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const unsigned int data, [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector data_vec; + appendUint32(data_vec, data); + + return {data_vec, {}}; + } + + static unsigned int deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static unsigned int deserialize(std::vector::iterator it1, + [[maybe_unused]] std::vector::iterator it2, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return extractUint32(it1); + } + + static unsigned int deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + return IPADataSerializer::deserialize(data.begin(), data.end()); + } + + static unsigned int 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) + { + std::vector data_vec(data.configurationFile.begin(), + data.configurationFile.end()); + + return {data_vec, {}}; + } + + 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) + { + std::string str(it1, it2); + + IPASettings ret; + ret.configurationFile = str; + + 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(); + appendUint32(data_vec, str_len); + + data_vec.insert(data_vec.end(), data.model.begin(), data.model.end()); + + appendUint32(data_vec, data.bitsPerPixel); + + appendUint32(data_vec, data.activeAreaSize.width); + appendUint32(data_vec, data.activeAreaSize.height); + + appendUint32(data_vec, static_cast(data.analogCrop.x)); + appendUint32(data_vec, static_cast(data.analogCrop.y)); + appendUint32(data_vec, data.analogCrop.width); + appendUint32(data_vec, data.analogCrop.height); + + appendUint32(data_vec, data.outputSize.width); + appendUint32(data_vec, data.outputSize.height); + + appendUint64(data_vec, data.pixelRate); + + appendUint32(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 = extractUint32(it1); + std::string str(it1 + 4, it1 + 4 + str_len); + ret.model = str; + + std::vector::iterator it = it1 + 4 + str_len; + + ret.bitsPerPixel = extractUint32(it); + + ret.activeAreaSize.width = extractUint32(it + 4); + ret.activeAreaSize.height = extractUint32(it + 8); + + ret.analogCrop.x = static_cast(extractUint32(it + 12)); + ret.analogCrop.y = static_cast(extractUint32(it + 16)); + ret.analogCrop.width = extractUint32(it + 20); + ret.analogCrop.height = extractUint32(it + 24); + + ret.outputSize.width = extractUint32(it + 28); + ret.outputSize.height = extractUint32(it + 32); + + ret.pixelRate = extractUint64(it + 36); + + ret.lineLength = extractUint64(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; + + appendUint32(data_vec, data.pixelFormat); + + appendUint32(data_vec, data.size.width); + appendUint32(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 = extractUint32(it1); + + ret.size.width = extractUint32(it1 + 4); + ret.size.height = extractUint32(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()) { + std::cerr << "Failed to serialize ControlList's ControlInfoMap" << std::endl; + 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()) { + std::cerr << "Failed to serialize ControlList" << std::endl; + return {{}, {}}; + } + + std::vector data_vec; + appendUint32(data_vec, infoData.size()); + appendUint32(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 ControlList deserialize(std::vector &data, ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), cs); + } + + static 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 = extractUint32(it1); + uint32_t listDataSize = extractUint32(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); + if (map.empty() || buffer.overflow()) { + std::cerr << "Failed to deserialize ControlLists's ControlInfoMap" << std::endl; + return ControlList(); + } + + buffer = ByteStreamBuffer(const_cast(listData.data()), listData.size()); + ControlList list = cs->deserialize(buffer); + if (buffer.overflow()) + std::cerr << "Failed to deserialize ControlList: buffer overflow" << std::endl; + if (list.empty()) + std::cerr << "Failed to deserialize ControlList: empty list" << std::endl; + + return list; + } + + static ControlList deserialize(std::vector &data, + [[maybe_unused]] std::vector &fds, + ControlSerializer *cs) + { + return IPADataSerializer::deserialize(data.begin(), data.end(), cs); + } + + 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) + { + return IPADataSerializer::deserialize(data_it1, data_it2, cs); + } +}; + +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; + appendUint32(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 = extractUint32(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); + + /* + ControlInfoMap::Map ctrls; + for (auto pair : map) + ctrls.emplace(controls::controls.at(pair.first->id()), + pair.second); + + ControlInfoMap ret = std::move(ctrls); + return ret; + */ + + 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 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 + appendUint32(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 = extractUint32(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; + + appendUint32(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 = extractUint32(data_it1); + + ret.planes = + IPADataSerializer>::deserialize( + data_it1 + 4, data_it2, fds_it1, fds_it2, cs); + + return ret; + } +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_H__ */ diff --git a/include/libcamera/ipa/raspberrypi_serializer.h b/include/libcamera/ipa/raspberrypi_serializer.h new file mode 100644 index 00000000..01d69986 --- /dev/null +++ b/include/libcamera/ipa/raspberrypi_serializer.h @@ -0,0 +1,487 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * raspberrypi_serializer.h - Image Processing Algorithm data serializer for raspberry pi + */ + +// automatically generated by custom compiler + +#include +#include + +#include "libcamera/internal/ipa_data_serializer.h" + +#ifndef __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_RASPBERRYPI_H__ +#define __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_RASPBERRYPI_H__ + +namespace libcamera { + +LOG_DECLARE_CATEGORY(IPADataSerializer) + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const RPiStaggeredWritePayload data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector ret_data; + + // scalar gainDelay_ + appendUint32(ret_data, data.gainDelay_); + + // scalar exposureDelay_ + appendUint32(ret_data, data.exposureDelay_); + + // scalar sensorMetadata_ + appendUint32(ret_data, data.sensorMetadata_); + + return {ret_data, {}}; + } + + static RPiStaggeredWritePayload deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + RPiStaggeredWritePayload ret; + std::vector::iterator m = data.begin(); + + // scalar gainDelay_ + ret.gainDelay_ = extractUint32(m); + m += 4; + + // scalar exposureDelay_ + ret.exposureDelay_ = extractUint32(m); + m += 4; + + // scalar sensorMetadata_ + ret.sensorMetadata_ = extractUint32(m); + + return ret; + } + + static RPiStaggeredWritePayload deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs = nullptr) + { + std::vector data(it1, it2); + return IPADataSerializer::deserialize(data, cs); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const RPiIspPreparePayload data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + std::vector ret_data; + + // scalar embeddedbufferId_ + appendUint32(ret_data, data.embeddedbufferId_); + + // scalar bayerbufferId_ + appendUint32(ret_data, data.bayerbufferId_); + + return {ret_data, {}}; + } + + static RPiIspPreparePayload deserialize(std::vector &data, + [[maybe_unused]] ControlSerializer *cs = nullptr) + { + RPiIspPreparePayload ret; + std::vector::iterator m = data.begin(); + + // scalar embeddedbufferId_ + ret.embeddedbufferId_ = extractUint32(m); + m += 4; + + // scalar bayerbufferId_ + ret.bayerbufferId_ = extractUint32(m); + + return ret; + } + + static RPiIspPreparePayload deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs = nullptr) + { + std::vector data(it1, it2); + return IPADataSerializer::deserialize(data, cs); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const RPiStatsCompletePayload data, + ControlSerializer *cs) + { + std::vector ret_data; + + // scalar bufferId_ + appendUint32(ret_data, data.bufferId_); + + // ControlList controls_ + if (data.controls_.size() > 0) { + std::vector controls; + std::tie(controls, std::ignore) = + IPADataSerializer::serialize(data.controls_, + data.controls_.infoMap() ? *data.controls_.infoMap() : RPiControls, + cs); + appendUint32(ret_data, controls.size()); + ret_data.insert(ret_data.end(), controls.begin(), controls.end()); + } else { + appendUint32(ret_data, 0); + } + + + return {ret_data, {}}; + } + + static RPiStatsCompletePayload deserialize(std::vector &data, + ControlSerializer *cs) + { + RPiStatsCompletePayload ret; + std::vector::iterator m = data.begin(); + + // scalar bufferId_ + ret.bufferId_ = extractUint32(m); + m += 4; + + // ControlList controls_ + size_t controlsSize = extractUint32(m); + if (controlsSize > 0) + ret.controls_ = + IPADataSerializer::deserialize(m + 4, m + 4 + controlsSize, cs); + + return ret; + } + + static RPiStatsCompletePayload deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs) + { + std::vector data(it1, it2); + return IPADataSerializer::deserialize(data, cs); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const RPiConfigurePayload data, + ControlSerializer *cs) + { + std::vector ret_data; + std::vector ret_fds; + + // scalar op_ + appendUint32(ret_data, data.op_); + + // fd lsTableHandle_ + std::vector lsTableHandle; + std::vector lsTableHandleFds; + std::tie(lsTableHandle, lsTableHandleFds) = + IPADataSerializer::serialize(data.lsTableHandle_); + ret_data.insert(ret_data.end(), lsTableHandle.begin(), lsTableHandle.end()); + ret_fds.insert(ret_fds.end(), lsTableHandleFds.begin(), lsTableHandleFds.end()); + + // scalar lsTableHandleStatic_ + appendUint32(ret_data, static_cast(data.lsTableHandleStatic_)); + + // struct staggeredWriteResult_ + std::vector staggeredWriteResult; + std::tie(staggeredWriteResult, std::ignore) = + IPADataSerializer::serialize(data.staggeredWriteResult_, cs); + appendUint32(ret_data, staggeredWriteResult.size()); + ret_data.insert(ret_data.end(), staggeredWriteResult.begin(), staggeredWriteResult.end()); + + // ControlList controls_ + if (data.controls_.size() > 0) { + std::vector controls; + std::tie(controls, std::ignore) = + IPADataSerializer::serialize(data.controls_, + data.controls_.infoMap() ? *data.controls_.infoMap() : RPiControls, + cs); + appendUint32(ret_data, controls.size()); + ret_data.insert(ret_data.end(), controls.begin(), controls.end()); + } else { + appendUint32(ret_data, 0); + } + + // scalar bufferFd_ + appendUint32(ret_data, static_cast(data.bufferFd_)); + + return {ret_data, ret_fds}; + } + + static RPiConfigurePayload deserialize(std::vector &data, + std::vector &fds, + ControlSerializer *cs) + { + RPiConfigurePayload ret; + std::vector::iterator m = data.begin(); + std::vector::iterator n = fds.begin(); + + // scalar op_ + ret.op_ = static_cast(extractUint32(m)); + m += 4; + + // fd lsTableHandle_ + ret.lsTableHandle_ = IPADataSerializer::deserialize(m, m + 1, n, n + 1); + m += 1; + n += ret.lsTableHandle_.isValid() ? 1 : 0; + + // scalar lsTableHandleStatic_ + ret.lsTableHandleStatic_ = static_cast(extractUint32(m)); + m += 4; + + // struct staggeredWriteResult_ + size_t staggeredWriteResultSize = extractUint32(m); + ret.staggeredWriteResult_ = + IPADataSerializer::deserialize(m + 4, m + 4 + staggeredWriteResultSize, cs); + m += 4 + staggeredWriteResultSize; + + // ControlList controls_ + size_t controlsSize = extractUint32(m); + if (controlsSize > 0) + ret.controls_ = + IPADataSerializer::deserialize(m + 4, m + 4 + controlsSize, cs); + m += 4 + controlsSize; + + // scalar bufferFd_ + ret.bufferFd_ = static_cast(extractUint32(m)); + + return ret; + } + + static RPiConfigurePayload deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + std::vector::iterator fds_it1, + std::vector::iterator fds_it2, + ControlSerializer *cs) + { + std::vector data(data_it1, data_it2); + std::vector fds(fds_it1, fds_it2); + return IPADataSerializer::deserialize(data, fds, cs); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const RPiConfigureParams data, + ControlSerializer *cs) + { + std::vector ret_data; + std::vector ret_fds; + + // vector payload_ + // only member, so don't need size + std::tie(ret_data, ret_fds) = + IPADataSerializer>::serialize(data.payload_, cs); + + return {ret_data, ret_fds}; + } + + static RPiConfigureParams deserialize(std::vector &data, + std::vector &fds, + ControlSerializer *cs) + { + RPiConfigureParams ret; + + // vector payload_ + ret.payload_ = + IPADataSerializer>::deserialize(data, fds, cs); + + return ret; + } + + static RPiConfigureParams deserialize(std::vector::iterator data_it1, + std::vector::iterator data_it2, + std::vector::iterator fds_it1, + std::vector::iterator fds_it2, + ControlSerializer *cs) + { + std::vector data(data_it1, data_it2); + std::vector fds(fds_it1, fds_it2); + return IPADataSerializer::deserialize(data, fds, cs); + } +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const RPiEventParams data, + ControlSerializer *cs) + { + std::vector ret_data; + + // scalar ev_ + appendUint32(ret_data, data.ev_); + + // scalar bufferId_ + appendUint32(ret_data, data.bufferId_); + + // struct ispPrepare_ + std::vector ispPrepare; + std::tie(ispPrepare, std::ignore) = + IPADataSerializer::serialize(data.ispPrepare_, cs); + appendUint32(ret_data, ispPrepare.size()); + ret_data.insert(ret_data.end(), ispPrepare.begin(), ispPrepare.end()); + + // ControlList controls_ + if (data.controls_.size() > 0) { + std::vector controls; + std::tie(controls, std::ignore) = + IPADataSerializer::serialize(data.controls_, + data.controls_.infoMap() ? *data.controls_.infoMap() : RPiControls, + cs); + appendUint32(ret_data, controls.size()); + ret_data.insert(ret_data.end(), controls.begin(), controls.end()); + } else { + appendUint32(ret_data, 0); + } + + // scalar bufferFd_ + appendUint32(ret_data, static_cast(data.bufferFd_)); + + return {ret_data, {}}; + } + + static RPiEventParams deserialize(std::vector &data, + ControlSerializer *cs) + { + RPiEventParams ret; + std::vector::iterator m = data.begin(); + + // scalar ev_ + ret.ev_ = static_cast(extractUint32(m)); + m += 4; + + // scalar bufferId_ + ret.bufferId_ = extractUint32(m); + m += 4; + + // struct ispPrepare_ + size_t ispPrepareSize = extractUint32(m); + ret.ispPrepare_ = + IPADataSerializer::deserialize(m + 4, m + 4 + ispPrepareSize, cs); + m += 4 + ispPrepareSize; + + // ControlList controls_ + size_t controlsSize = extractUint32(m); + if (controlsSize > 0) + ret.controls_ = + IPADataSerializer::deserialize(m + 4, m + 4 + controlsSize, cs); + m += 4 + controlsSize; + + // scalar bufferFd_ + ret.bufferFd_ = static_cast(extractUint32(m)); + + return ret; + } + + static RPiEventParams deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs) + { + std::vector data(it1, it2); + return IPADataSerializer::deserialize(data, cs); + } + +}; + +template<> +class IPADataSerializer +{ +public: + static std::tuple, std::vector> + serialize(const RPiActionParams data, + ControlSerializer *cs) + { + std::vector ret_data; + + // scalar op_ + appendUint32(ret_data, data.op_); + + // scalar bufferId_ + appendUint32(ret_data, data.bufferId_); + + // struct statsComplete_ + std::vector statsComplete; + std::tie(statsComplete, std::ignore) = + IPADataSerializer::serialize(data.statsComplete_, cs); + appendUint32(ret_data, statsComplete.size()); + ret_data.insert(ret_data.end(), statsComplete.begin(), statsComplete.end()); + + // ControlList controls_ + if (data.controls_.size() > 0) { + std::vector controls; + std::tie(controls, std::ignore) = + IPADataSerializer::serialize(data.controls_, + data.controls_.infoMap() ? *data.controls_.infoMap() : RPiControls, + cs); + appendUint32(ret_data, controls.size()); + ret_data.insert(ret_data.end(), controls.begin(), controls.end()); + } else { + appendUint32(ret_data, 0); + } + + return {ret_data, {}}; + } + + static RPiActionParams deserialize(std::vector &data, + ControlSerializer *cs) + { + RPiActionParams ret; + std::vector::iterator m = data.begin(); + + // scalar op_ + ret.op_ = static_cast(extractUint32(m)); + m += 4; + + // scalar bufferId_ + ret.bufferId_ = extractUint32(m); + m += 4; + + // struct statsComplete_ + size_t statsCompleteSize = extractUint32(m); + ret.statsComplete_ = + IPADataSerializer::deserialize(m + 4, m + 4 + statsCompleteSize, cs); + m += 4 + statsCompleteSize; + + // ControlList controls_ + size_t controlsSize = extractUint32(m); + if (controlsSize > 0) + ret.controls_ = + IPADataSerializer::deserialize(m + 4, m + 4 + controlsSize, cs); + + return ret; + } + + static RPiActionParams deserialize(std::vector::iterator it1, + std::vector::iterator it2, + ControlSerializer *cs) + { + std::vector data(it1, it2); + return IPADataSerializer::deserialize(data, cs); + } + +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_INTERNAL_IPA_DATA_SERIALIZER_RASPBERRYPI_H__ */ diff --git a/src/libcamera/ipa_data_serializer.cpp b/src/libcamera/ipa_data_serializer.cpp new file mode 100644 index 00000000..86332abc --- /dev/null +++ b/src/libcamera/ipa_data_serializer.cpp @@ -0,0 +1,29 @@ +/* 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_ipa_data_serializer.h + * \brief IPA Data Serializer + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(IPADataSerializer) + +/** + * \class IPADataSerializer + * \brief IPA Data Serializer + * + */ + +// TODO the rest of the documentation + +} /* namespace libcamera */