diff --git a/CMakeLists.txt b/CMakeLists.txt index 12c759a85a38fb029459d35f2a3174b66bcf4e0b..67542ca4c5c26761b6d3ab355418d266af7dc0d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,6 +196,7 @@ add_library(beyond-protocol STATIC src/service.cpp src/codecs/golomb.cpp src/codecs/h264.cpp + src/codecs/data.cpp ) target_include_directories(beyond-protocol PUBLIC diff --git a/include/ftl/codec/data.hpp b/include/ftl/codec/data.hpp new file mode 100644 index 0000000000000000000000000000000000000000..916432d442962f1d99227d7cb5d775ec07e05103 --- /dev/null +++ b/include/ftl/codec/data.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include <vector> +#include <string> +#include <tuple> +#include <cstdint> + +#include <ftl/data/camera.hpp> +#include <ftl/protocol/channels.hpp> + +namespace ftl { +namespace data { + +using Pose = std::vector<double>; +using StereoPose = std::tuple<Pose, Pose>; +using Intrinsics = std::tuple<ftl::data::Camera, int, int>; + +} +namespace codec { + +template <typename T> +void pack(const T &v, std::vector<uint8_t> &out); + +template <typename T> +T unpack(const std::vector<uint8_t> &in); + +} +} diff --git a/include/ftl/codec/msgpack.hpp b/include/ftl/codec/msgpack.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4f8eba90a3b1b252b5ea2f447b3a59a73b823451 --- /dev/null +++ b/include/ftl/codec/msgpack.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include <msgpack.hpp> +#include <ftl/codec/data.hpp> +#include <ftl/utility/vectorbuffer.hpp> + +template <typename T> +void ftl::codec::pack(const T &v, std::vector<uint8_t> &out) { + out.resize(0); + ftl::util::FTLVectorBuffer buf(out); + msgpack::pack(buf, v); +} + +template <typename T> +T ftl::codec::unpack(const std::vector<uint8_t> &in) { + auto unpacked = msgpack::unpack((const char*)in.data(), in.size()); + T t; + unpacked.get().convert<T>(t); + return t; +} diff --git a/include/ftl/data/camera.hpp b/include/ftl/data/camera.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6a931fecf8e018abdfbebc2896c01f668d5008ec --- /dev/null +++ b/include/ftl/data/camera.hpp @@ -0,0 +1,24 @@ +#pragma once + +namespace ftl { +namespace data { + +/** + * All properties associated with cameras. This structure is designed to + * operate on CPU and GPU. + */ +struct Camera { + float fx; // Focal length X + float fy; // Focal length Y (usually same as fx) + float cx; // Principle point Y + float cy; // Principle point Y + unsigned int width; // Pixel width + unsigned int height; // Pixel height + float minDepth; // Near clip in meters + float maxDepth; // Far clip in meters + float baseline; // For stereo pair + float doffs; // Disparity offset +}; + +} // namespace data +} // namespace ftl diff --git a/include/ftl/data/capabilities.hpp b/include/ftl/data/capabilities.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f81f4c733625503bfd003ba8071a95610fd9556f --- /dev/null +++ b/include/ftl/data/capabilities.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace ftl { +namespace data { + +/** + * To be added to the capabilities channel to indicate what the source device + * is capable of. These properties should be features of the source that + * cannot be determined by simply checking for channels, and may include + * status information about processing that has been performed. + */ +enum class Capability : int { + MOVABLE = 0, // Is a pose controllable camera + ACTIVE, // An active depth sensor + VIDEO, // Is video and not just static + ADJUSTABLE, // Camera properties can be changed (exposure etc) + VIRTUAL, // Is not a physical camera + TOUCH, // Touch related feedback supported + VR, // Is a VR device, so provides own active pose etc + LIVE, // Live, not recorded (removed from ftl file sources) + FUSED, // Reconstruction has been performed + STREAMED, // Means it came from a stream and not device + EQUI_RECT, // 360 rendered (Equirectangular Render) + STEREO // Side-by-side stereo render +}; + +} // namespace data +} // namespace ftl diff --git a/include/ftl/utility/vectorbuffer.hpp b/include/ftl/utility/vectorbuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..104ca312ae35814bb24b35ea041719e629fe53f3 --- /dev/null +++ b/include/ftl/utility/vectorbuffer.hpp @@ -0,0 +1,29 @@ +/** + * @file vectorbuffer.hpp + * @copyright Copyright (c) 2020 University of Turku, MIT License + * @author Nicolas Pope + */ + +#pragma once + +#include <vector> + +namespace ftl { +namespace util { + +/** + * Used for msgpack encoding into an existing std::vector object. + */ +class FTLVectorBuffer { + public: + inline explicit FTLVectorBuffer(std::vector<unsigned char> &v) : vector_(v) {} + + inline void write(const char *data, std::size_t size) { + vector_.insert(vector_.end(), (const unsigned char*)data, (const unsigned char*)data+size); + } + + private: + std::vector<unsigned char> &vector_; +}; +} // namespace util +} // namespace ftl diff --git a/src/codecs/data.cpp b/src/codecs/data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab136651e1aaf06dcfc7d61b01fc1d4eea643c68 --- /dev/null +++ b/src/codecs/data.cpp @@ -0,0 +1,42 @@ +#include <ftl/codec/msgpack.hpp> + +using ftl::codec::pack; +using ftl::codec::unpack; + +struct CameraMSGPACK : public ftl::data::Camera { + MSGPACK_DEFINE(fx, fy, cx, cy, width, height, minDepth, maxDepth, baseline, doffs); +}; + +// Instantiations supported without the msgpack.hpp header +template void pack<int>(const int &v, std::vector<uint8_t> &out); +template void pack<float>(const float &v, std::vector<uint8_t> &out); +template void pack<std::string>(const std::string &v, std::vector<uint8_t> &out); +template void pack<double>(const double &v, std::vector<uint8_t> &out); +template void pack<std::vector<float>>(const std::vector<float> &v, std::vector<uint8_t> &out); +template void pack<ftl::data::Pose>(const ftl::data::Pose &v, std::vector<uint8_t> &out); +template void pack<std::vector<int>>(const std::vector<int> &v, std::vector<uint8_t> &out); +template void pack<std::vector<std::string>>(const std::vector<std::string> &v, std::vector<uint8_t> &out); +template void pack<ftl::data::StereoPose>(const ftl::data::StereoPose &v, std::vector<uint8_t> &out); +template <> void ftl::codec::pack(const ftl::data::Intrinsics &v, std::vector<uint8_t> &out) { + std::tuple<CameraMSGPACK, int, int> data; + reinterpret_cast<ftl::data::Camera&>(std::get<0>(data)) = std::get<0>(v); + std::get<1>(data) = std::get<1>(v); + std::get<2>(data) = std::get<2>(v); + pack(data, out); +} +template void pack<ftl::data::Intrinsics>(const ftl::data::Intrinsics &v, std::vector<uint8_t> &out); + +template int unpack<int>(const std::vector<uint8_t> &in); +template float unpack<float>(const std::vector<uint8_t> &in); +template std::string unpack<std::string>(const std::vector<uint8_t> &in); +template double unpack<double>(const std::vector<uint8_t> &in); +template std::vector<float> unpack<std::vector<float>>(const std::vector<uint8_t> &in); +template ftl::data::Pose unpack<ftl::data::Pose>(const std::vector<uint8_t> &in); +template std::vector<int> unpack<std::vector<int>>(const std::vector<uint8_t> &in); +template std::vector<std::string> unpack<std::vector<std::string>>(const std::vector<uint8_t> &in); +template ftl::data::StereoPose unpack<ftl::data::StereoPose>(const std::vector<uint8_t> &in); +template <> ftl::data::Intrinsics ftl::codec::unpack(const std::vector<uint8_t> &in) { + auto data = unpack<std::tuple<CameraMSGPACK, int, int>>(in); + return data; +} +template ftl::data::Intrinsics unpack<ftl::data::Intrinsics>(const std::vector<uint8_t> &in); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5788d7966ae1d67db2ac76ba8430239e8c037ec4..e6f9fe36108dc2b4e2b2b566762e66cce4659ab1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -151,3 +151,14 @@ target_link_libraries(rpc_integration beyond-protocol ${URIPARSER_LIBRARIES}) add_test(RPCIntegrationTest rpc_integration) + +### Data Codec Unit ############################################################ +add_executable(datacodec_unit + $<TARGET_OBJECTS:CatchTestFTL> + ./datacodec.cpp) +target_include_directories(datacodec_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include") +target_link_libraries(datacodec_unit beyond-protocol + Threads::Threads ${OS_LIBS} + ${URIPARSER_LIBRARIES}) + +add_test(DataCodecTest datacodec_unit) diff --git a/test/datacodec.cpp b/test/datacodec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e94b1c4e3c50f8cd90a5556e447bf31cd0ae2939 --- /dev/null +++ b/test/datacodec.cpp @@ -0,0 +1,30 @@ +#include "catch.hpp" +#include <ftl/codec/data.hpp> + +SCENARIO( "Intrinsics pack/unpack" ) { + GIVEN( "a valid instrincs object it packs" ) { + ftl::data::Intrinsics intrin; + std::get<0>(intrin).fx = 10.0f; + + std::vector<uint8_t> buffer; + ftl::codec::pack(intrin, buffer); + REQUIRE(buffer.size() > 0); + + auto result = ftl::codec::unpack<ftl::data::Intrinsics>(buffer); + REQUIRE(std::get<0>(result).fx == 10.0f); + } +} + +SCENARIO( "Vector of strings pack/unpack" ) { + GIVEN( "a valid instrincs object it packs" ) { + std::vector<std::string> data = {"hello", "world"}; + + std::vector<uint8_t> buffer; + ftl::codec::pack(data, buffer); + REQUIRE(buffer.size() > 0); + + auto result = ftl::codec::unpack<std::vector<std::string>>(buffer); + REQUIRE(result[0] == "hello"); + REQUIRE(result[1] == "world"); + } +}