From dc4a0de72306e5c8fd7bc3c8d8c45133c59c7b15 Mon Sep 17 00:00:00 2001 From: Paulchen Panther Date: Tue, 21 Dec 2021 13:52:53 +0100 Subject: [PATCH] Transfer RGBA data to flatbuffer server --- CMakeLists.txt | 41 ++--- src/ColorRgb.h | 119 -------------- src/FlatBufferConnection.cpp | 12 +- src/FlatBufferConnection.h | 10 +- ...erion_request.fbs => FlatBufferSchema.fbs} | 8 + src/Image.h | 155 +++--------------- src/ImageData.h | 115 +------------ src/hyperion-obs.cpp | 23 +-- src/hyperion_reply.fbs | 9 - 9 files changed, 55 insertions(+), 437 deletions(-) delete mode 100644 src/ColorRgb.h rename src/{hyperion_request.fbs => FlatBufferSchema.fbs} (84%) delete mode 100644 src/hyperion_reply.fbs diff --git a/CMakeLists.txt b/CMakeLists.txt index 3503457..8e9f88a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,44 +135,29 @@ set(FLATBUFFERS_FLATC_EXECUTABLE "$") include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${FLATBUFFERS_INCLUDE_DIRS} + ${OBS_FRONTEND_INCLUDE_DIR} + ${LIBOBS_INCLUDE_DIR} ) -set(Flatbuffer_GENERATED_FBS - hyperion_reply_generated.h - hyperion_request_generated.h -) +set(FLATBUFFERS_SCHEMA "${CMAKE_SOURCE_DIR}/src/FlatBufferSchema.fbs") +set(FLATBUFFERS_HEADER "${CMAKE_BINARY_DIR}/FlatBufferSchema_generated.h") -set(Flatbuffer_FBS - ${CMAKE_SOURCE_DIR}/src/hyperion_reply.fbs - ${CMAKE_SOURCE_DIR}/src/hyperion_request.fbs +add_custom_command( + OUTPUT ${FLATBUFFERS_HEADER} + COMMAND ${FLATBUFFERS_FLATC_EXECUTABLE} + ARGS -c --no-includes --gen-mutable -o ${CMAKE_CURRENT_BINARY_DIR} ${FLATBUFFERS_SCHEMA} + DEPENDS ${FLATBUFFERS_FLATC_EXECUTABLE} ${FLATBUFFERS_SCHEMA} + COMMENT "Building Flatbuffer header file" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -foreach(FBS_FILE ${Flatbuffer_FBS}) - get_filename_component(FLATC_OUTPUT ${FBS_FILE} NAME_WE) - set(FLATC_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${FLATC_OUTPUT}_generated.h) - - add_custom_command( - OUTPUT ${FLATC_OUTPUT} - COMMAND ${FLATBUFFERS_FLATC_EXECUTABLE} - ARGS -c --no-includes --gen-mutable -o ${CMAKE_CURRENT_BINARY_DIR} ${FBS_FILE} - DEPENDS ${FLATBUFFERS_FLATC_EXECUTABLE} ${FBS_FILE} - COMMENT "Building C++ header for ${FBS_FILE}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) -endforeach() - -set_source_files_properties(${Flatbuffer_GENERATED_FBS} PROPERTIES GENERATED TRUE) +set_source_files_properties(${FLATBUFFERS_HEADER} PROPERTIES GENERATED TRUE) FILE ( GLOB hyperion_obs_SOURCES "${CMAKE_SOURCE_DIR}/src/*.h" "${CMAKE_SOURCE_DIR}/src/*.cpp" ) add_library(${PROJECT_NAME} MODULE ${hyperion_obs_SOURCES} - ${Flatbuffer_GENERATED_FBS} -) - -include_directories( - ${OBS_FRONTEND_INCLUDE_DIR} - ${LIBOBS_INCLUDE_DIR} + ${FLATBUFFERS_HEADER} ) if (UNIX) diff --git a/src/ColorRgb.h b/src/ColorRgb.h deleted file mode 100644 index 7f11849..0000000 --- a/src/ColorRgb.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -// STL includes -#include -#include - -#include - -/// -/// Plain-Old-Data structure containing the red-green-blue color specification. Size of the -/// structure is exactly 3-bytes for easy writing to led-device -/// -struct ColorRgb -{ - /// The red color channel - uint8_t red; - /// The green color channel - uint8_t green; - /// The blue color channel - uint8_t blue; - - /// 'Black' RgbColor (0, 0, 0) - static const ColorRgb BLACK; - /// 'Red' RgbColor (255, 0, 0) - static const ColorRgb RED; - /// 'Green' RgbColor (0, 255, 0) - static const ColorRgb GREEN; - /// 'Blue' RgbColor (0, 0, 255) - static const ColorRgb BLUE; - /// 'Yellow' RgbColor (255, 255, 0) - static const ColorRgb YELLOW; - /// 'White' RgbColor (255, 255, 255) - static const ColorRgb WHITE; -}; - -/// Assert to ensure that the size of the structure is 'only' 3 bytes -static_assert(sizeof(ColorRgb) == 3, "Incorrect size of ColorRgb"); - -/// -/// Stream operator to write ColorRgb to an outputstream (format "'{'[red]','[green]','[blue]'}'") -/// -/// @param os The output stream -/// @param color The color to write -/// @return The output stream (with the color written to it) -/// -inline std::ostream& operator<<(std::ostream& os, const ColorRgb& color) -{ - os << "{" - << static_cast(color.red) << "," - << static_cast(color.green) << "," - << static_cast(color.blue) - << "}"; - - return os; -} - -/// -/// Stream operator to write ColorRgb to a QTextStream (format "'{'[red]','[green]','[blue]'}'") -/// -/// @param os The output stream -/// @param color The color to write -/// @return The output stream (with the color written to it) -/// -inline QTextStream& operator<<(QTextStream &os, const ColorRgb& color) -{ - os << "{" - << static_cast(color.red) << "," - << static_cast(color.green) << "," - << static_cast(color.blue) - << "}"; - - return os; -} - -/// Compare operator to check if a color is 'equal' to another color -inline bool operator==(const ColorRgb & lhs, const ColorRgb & rhs) -{ - return lhs.red == rhs.red && - lhs.green == rhs.green && - lhs.blue == rhs.blue; -} - -/// Compare operator to check if a color is 'smaller' than another color -inline bool operator<(const ColorRgb & lhs, const ColorRgb & rhs) -{ - return lhs.red < rhs.red && - lhs.green < rhs.green && - lhs.blue < rhs.blue; -} - -/// Compare operator to check if a color is 'not equal' to another color -inline bool operator!=(const ColorRgb & lhs, const ColorRgb & rhs) -{ - return !(lhs == rhs); -} - -/// Compare operator to check if a color is 'smaller' than or 'equal' to another color -inline bool operator<=(const ColorRgb & lhs, const ColorRgb & rhs) -{ - return lhs.red <= rhs.red && - lhs.green <= rhs.green && - lhs.blue <= rhs.blue; -} - -/// Compare operator to check if a color is 'greater' to another color -inline bool operator>(const ColorRgb & lhs, const ColorRgb & rhs) -{ - return lhs.red > rhs.red && - lhs.green > rhs.green && - lhs.blue > rhs.blue; -} - -/// Compare operator to check if a color is 'greater' than or 'equal' to another color -inline bool operator>=(const ColorRgb & lhs, const ColorRgb & rhs) -{ - return lhs.red >= rhs.red && - lhs.green >= rhs.green && - lhs.blue >= rhs.blue; -} diff --git a/src/FlatBufferConnection.cpp b/src/FlatBufferConnection.cpp index eb48d56..049db2a 100644 --- a/src/FlatBufferConnection.cpp +++ b/src/FlatBufferConnection.cpp @@ -1,15 +1,9 @@ // stl includes #include -// Qt includes -#include - -// flatbuffer includes +// includes flatbuffer header and generated schema #include "FlatBufferConnection.h" - -// flatbuffer FBS -#include "hyperion_reply_generated.h" -#include "hyperion_request_generated.h" +#include "FlatBufferSchema_generated.h" FlatBufferConnection::FlatBufferConnection(const QString& origin, const QString& host, int priority, quint16 port) : _socket() @@ -97,7 +91,7 @@ void FlatBufferConnection::setRegister(const QString& origin, int priority) _builder.Clear(); } -void FlatBufferConnection::setImage(const Image &image) +void FlatBufferConnection::setImage(const Image &image) { auto imgData = _builder.CreateVector(reinterpret_cast(image.memptr()), image.size()); auto rawImg = hyperionnet::CreateRawImage(_builder, imgData, image.width(), image.height()); diff --git a/src/FlatBufferConnection.h b/src/FlatBufferConnection.h index f09396d..3a91ab7 100644 --- a/src/FlatBufferConnection.h +++ b/src/FlatBufferConnection.h @@ -3,17 +3,11 @@ // Qt includes #include -#include #include #include -#include #include - -// hyperion util -#include "Image.h" -#include "ColorRgb.h" - #include +#include "Image.h" const int FLATBUFFER_DEFAULT_PORT = 19400; @@ -62,7 +56,7 @@ public slots: /// @brief Set the leds according to the given image /// @param image The image /// - void setImage(const Image &image); + void setImage(const Image &image); signals: diff --git a/src/hyperion_request.fbs b/src/FlatBufferSchema.fbs similarity index 84% rename from src/hyperion_request.fbs rename to src/FlatBufferSchema.fbs index 1c6e3d4..37975d1 100644 --- a/src/hyperion_request.fbs +++ b/src/FlatBufferSchema.fbs @@ -35,3 +35,11 @@ table Request { } root_type Request; + +table Reply { + error:string; + video:int = -1; + registered:int = -1; +} + +root_type Reply; \ No newline at end of file diff --git a/src/Image.h b/src/Image.h index f9d2af4..c129399 100644 --- a/src/Image.h +++ b/src/Image.h @@ -1,8 +1,21 @@ #pragma once -#include +#include -#include "ImageData.h" +// QT includes +#include + +struct ColorRgba +{ + /// The red color channel + uint8_t red; + /// The green color channel + uint8_t green; + /// The blue color channel + uint8_t blue; + /// The alpha mask channel + uint8_t alpha; +}; template class Image @@ -10,14 +23,11 @@ class Image public: typedef Pixel_T pixel_type; + /// + /// Default constructor for an image + /// Image() : - Image(1, 1, Pixel_T()) - { - } - - Image(unsigned width, unsigned height) : - Image(width, height, Pixel_T()) - + _d_ptr(new ImageData(1, 1, Pixel_T())) { } @@ -26,50 +36,9 @@ class Image /// /// @param width The width of the image /// @param height The height of the image - /// @param background The color of the image - /// - Image(unsigned width, unsigned height, const Pixel_T background) : - _d_ptr(new ImageData(width, height, background)) - { - } - - /// - /// Copy constructor for an image - /// @param other The image which will be copied - /// - Image(const Image & other) - { - _d_ptr = other._d_ptr; - } - - Image& operator=(Image rhs) - { - // Define assignment operator in terms of the copy constructor - // More to read: https://stackoverflow.com/questions/255612/dynamically-allocating-an-array-of-objects?answertab=active#tab-top - _d_ptr = rhs._d_ptr; - return *this; - } - - void swap(Image& s) - { - std::swap(this->_d_ptr, s._d_ptr); - } - - Image(Image&& src) noexcept - { - std::swap(this->_d_ptr, src._d_ptr); - } - - Image& operator=(Image&& src) noexcept - { - src.swap(*this); - return *this; - } - - /// - /// Destructor /// - ~Image() + Image(unsigned width, unsigned height) : + _d_ptr(new ImageData(width, height, Pixel_T())) { } @@ -93,55 +62,6 @@ class Image return _d_ptr->height(); } - uint8_t red(unsigned pixel) const - { - return _d_ptr->red(pixel); - } - - uint8_t green(unsigned pixel) const - { - return _d_ptr->green(pixel); - } - - /// - /// Returns a const reference to a specified pixel in the image - /// - /// @param x The x index - /// @param y The y index - /// - /// @return const reference to specified pixel - /// - uint8_t blue(unsigned pixel) const - { - return _d_ptr->blue(pixel); - } - - /// - /// Returns a reference to a specified pixel in the image - /// - /// @param x The x index - /// @param y The y index - const Pixel_T& operator()(unsigned x, unsigned y) const - { - return _d_ptr->operator()(x, y); - } - - /// - /// @return reference to specified pixel - /// - Pixel_T& operator()(unsigned x, unsigned y) - { - return _d_ptr->operator()(x, y); - } - - /// Resize the image - /// @param width The width of the image - /// @param height The height of the image - void resize(unsigned width, unsigned height) - { - _d_ptr->resize(width, height); - } - /// /// Returns a memory pointer to the first pixel in the image /// @return The memory pointer to the first pixel @@ -160,16 +80,6 @@ class Image return _d_ptr->memptr(); } - /// - /// Convert image of any color order to a RGB image. - /// - /// @param[out] image The image that buffers the output - /// - void toRgb(Image& image) const - { - _d_ptr->toRgb(*image._d_ptr); - } - /// /// Get size of buffer /// @@ -178,32 +88,11 @@ class Image return _d_ptr->size(); } - /// - /// Clear the image - /// - void clear() - { - _d_ptr->clear(); - } - private: template friend class Image; - /// - /// Translate x and y coordinate to index of the underlying vector - /// - /// @param x The x index - /// @param y The y index - /// - /// @return The index into the underlying data-vector - /// - inline unsigned toIndex(unsigned x, unsigned y) const - { - return _d_ptr->toIndex(x, y); - } - private: - QSharedDataPointer> _d_ptr; + QExplicitlySharedDataPointer> _d_ptr; }; diff --git a/src/ImageData.h b/src/ImageData.h index 89cd9a3..5f1088b 100644 --- a/src/ImageData.h +++ b/src/ImageData.h @@ -7,15 +7,14 @@ #include #include #include -#include "ColorRgb.h" // QT includes #include // https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#ssize-t #if defined(_MSC_VER) -#include -typedef SSIZE_T ssize_t; + #include + typedef SSIZE_T ssize_t; #endif template @@ -32,43 +31,6 @@ class ImageData : public QSharedData std::fill(_pixels, _pixels + width * height, background); } - ImageData(const ImageData & other) : - QSharedData(other), - _width(other._width), - _height(other._height), - _pixels(new Pixel_T[other._width * other._height + 1]) - { - memcpy(_pixels, other._pixels, static_cast(other._width) * static_cast(other._height) * sizeof(Pixel_T)); - } - - ImageData& operator=(ImageData rhs) - { - rhs.swap(*this); - return *this; - } - - void swap(ImageData& s) noexcept - { - using std::swap; - swap(this->_width, s._width); - swap(this->_height, s._height); - swap(this->_pixels, s._pixels); - } - - ImageData(ImageData&& src) noexcept - : _width(0) - , _height(0) - , _pixels(NULL) - { - src.swap(*this); - } - - ImageData& operator=(ImageData&& src) noexcept - { - src.swap(*this); - return *this; - } - ~ImageData() { delete[] _pixels; @@ -84,46 +46,6 @@ class ImageData : public QSharedData return _height; } - uint8_t red(unsigned pixel) const - { - return (_pixels + pixel)->red; - } - - uint8_t green(unsigned pixel) const - { - return (_pixels + pixel)->green; - } - - uint8_t blue(unsigned pixel) const - { - return (_pixels + pixel)->blue; - } - - const Pixel_T& operator()(unsigned x, unsigned y) const - { - return _pixels[toIndex(x,y)]; - } - - Pixel_T& operator()(unsigned x, unsigned y) - { - return _pixels[toIndex(x,y)]; - } - - void resize(unsigned width, unsigned height) - { - if (width == _width && height == _height) - return; - - if ((width * height) > unsigned((_width * _height))) - { - delete[] _pixels; - _pixels = new Pixel_T[width*height + 1]; - } - - _width = width; - _height = height; - } - Pixel_T* memptr() { return _pixels; @@ -134,44 +56,11 @@ class ImageData : public QSharedData return _pixels; } - void toRgb(ImageData& image) const - { - if (image.width() != _width || image.height() != _height) - image.resize(_width, _height); - - const unsigned imageSize = _width * _height; - - for (unsigned idx = 0; idx < imageSize; idx++) - { - const Pixel_T & color = _pixels[idx]; - image.memptr()[idx] = ColorRgb{color.red, color.green, color.blue}; - } - } - ssize_t size() const { return static_cast(_width) * static_cast(_height) * sizeof(Pixel_T); } - void clear() - { - if (_width != 1 || _height != 1) - { - _width = 1; - _height = 1; - delete[] _pixels; - _pixels = new Pixel_T[2]; - } - - memset(_pixels, 0, static_cast(_width) * static_cast(_height) * sizeof(Pixel_T)); - } - -private: - inline unsigned toIndex(unsigned x, unsigned y) const - { - return y * _width + x; - } - private: /// The width of the image unsigned _width; diff --git a/src/hyperion-obs.cpp b/src/hyperion-obs.cpp index c461703..283b28f 100644 --- a/src/hyperion-obs.cpp +++ b/src/hyperion-obs.cpp @@ -135,7 +135,7 @@ static bool hyperion_output_start(void *data) conv.height = out_data->height; obs_output_set_video_conversion(out_data->output, &conv); - // double video_frame_rate = video_output_get_frame_rate(video); + // double video_frame_rate = video_output_get_frame_rate(video); //TODO if (!obs_output_can_begin_data_capture(out_data->output, 0)) { @@ -165,22 +165,9 @@ static void hyperion_output_raw_video(void *param, struct video_data *frame) if(out_data->active) { pthread_mutex_lock(&out_data->mutex); - - Image outputImage(out_data->width, out_data->height); - uint8_t* rgba = frame->data[0]; - uint8_t* rgb = (uint8_t*)outputImage.memptr(); - - int ptr_src = 0, ptr_dst = 0; - for (uint32_t i = 0; i < out_data->width * out_data->height; ++i) - { - rgb[ptr_dst++] = rgba[ptr_src++]; - rgb[ptr_dst++] = rgba[ptr_src++]; - rgb[ptr_dst++] = rgba[ptr_src++]; - ptr_src++; - } - - QMetaObject::invokeMethod(out_data->client, "setImage", Qt::QueuedConnection, Q_ARG(Image, outputImage)); - + Image outputImage(out_data->width, out_data->height); + memmove(outputImage.memptr(), frame->data[0], out_data->width * out_data->height * sizeof(ColorRgba)); + QMetaObject::invokeMethod(out_data->client, "setImage", Qt::QueuedConnection, Q_ARG(Image, outputImage)); pthread_mutex_unlock(&out_data->mutex); } } @@ -205,7 +192,7 @@ OBS_MODULE_USE_DEFAULT_LOCALE(OBS_MODULE_NAME, OBS_DEFAULT_LOCALE) bool obs_module_load(void) { - qRegisterMetaType>("Image"); + qRegisterMetaType>("Image"); obs_output_info hyperion_output_info = create_hyperion_output_info(); obs_register_output(&hyperion_output_info); diff --git a/src/hyperion_reply.fbs b/src/hyperion_reply.fbs deleted file mode 100644 index c80d1b6..0000000 --- a/src/hyperion_reply.fbs +++ /dev/null @@ -1,9 +0,0 @@ -namespace hyperionnet; - -table Reply { - error:string; - video:int = -1; - registered:int = -1; -} - -root_type Reply;