From 7eb41aa49e9bd3e91310d258e6c9ee69c0299249 Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Tue, 1 May 2018 17:12:13 +0200 Subject: [PATCH 1/4] Deflect 1.0 --- CMakeLists.txt | 4 +- README.md | 4 +- deflect/CMakeLists.txt | 5 +- deflect/Event.h | 46 ++---- deflect/ImageSegmenter.cpp | 33 +++-- deflect/ImageSegmenter.h | 31 +++-- deflect/ImageWrapper.cpp | 23 +-- deflect/ImageWrapper.h | 25 +--- deflect/MessageHeader.h | 2 +- deflect/Observer.h | 19 ++- deflect/Segment.h | 20 +-- deflect/SegmentParameters.h | 16 ++- deflect/ServerWorker.cpp | 16 +-- deflect/ServerWorker.h | 16 +-- deflect/SizeHints.h | 8 +- deflect/Stream.h | 17 +-- deflect/StreamEventThread.cpp | 200 --------------------------- deflect/StreamEventThread.h | 88 ------------ deflect/StreamPrivate.h | 2 - deflect/StreamSendWorker.cpp | 5 +- deflect/config.h | 51 ------- deflect/types.h | 9 +- doc/Changelog.md | 7 + tests/cpp/ImageWrapperTests.cpp | 92 ------------ tests/cpp/perf/benchmarkStreamer.cpp | 5 +- tests/mock/MockServer.h | 1 - 26 files changed, 131 insertions(+), 614 deletions(-) delete mode 100644 deflect/StreamEventThread.cpp delete mode 100644 deflect/StreamEventThread.h delete mode 100644 deflect/config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 84f051d..4d8cd37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ -# Copyright (c) 2013-2017, EPFL/Blue Brain Project +# Copyright (c) 2013-2018, EPFL/Blue Brain Project # Raphael Dumusc # Daniel Nachbaur cmake_minimum_required(VERSION 3.1 FATAL_ERROR) -project(Deflect VERSION 0.14.1) +project(Deflect VERSION 1.0.0) set(Deflect_VERSION_ABI 7) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/common) diff --git a/README.md b/README.md index fe73288..0bb1033 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Welcome to Deflect, a C++ library for streaming pixels to other Deflect-based applications, for example [Tide](https://github.com/BlueBrain/Tide). -Deflect offers a stable API marked with version 1.7 (for the client part). +Deflect offers a stable API marked with version 1.0 (for the client part). ## Overview @@ -55,5 +55,5 @@ environments are tested: * Linux: Ubuntu 16.04 and RHEL 6 (Makefile, Ninja; x64) * Mac OS X: 10.7 - 10.10 (Makefile, Ninja; x86_64) -The [latest API documentation](http://bluebrain.github.io/Deflect-0.14/index.html) +The [latest API documentation](http://bluebrain.github.io/Deflect-1.0/index.html) can be found on [bluebrain.github.io](http://bluebrain.github.io). diff --git a/deflect/CMakeLists.txt b/deflect/CMakeLists.txt index 918a9f2..a2b6b31 100644 --- a/deflect/CMakeLists.txt +++ b/deflect/CMakeLists.txt @@ -1,10 +1,9 @@ -# Copyright (c) 2013-2017, EPFL/Blue Brain Project +# Copyright (c) 2013-2018, EPFL/Blue Brain Project # Raphael Dumusc # Daniel Nachbaur set(DEFLECT_PUBLIC_HEADERS - config.h Event.h EventReceiver.h Frame.h @@ -19,6 +18,8 @@ set(DEFLECT_PUBLIC_HEADERS ) set(DEFLECT_HEADERS + moodycamel/blockingconcurrentqueue.h + moodycamel/concurrentqueue.h FrameDispatcher.h ImageSegmenter.h MessageHeader.h diff --git a/deflect/Event.h b/deflect/Event.h index 9c77539..f1d544f 100644 --- a/deflect/Event.h +++ b/deflect/Event.h @@ -144,48 +144,32 @@ struct Event }; /** The type of event */ - EventType type; + EventType type = EVT_NONE; /** @name Mouse and touch events */ //@{ - double mouseX; /**< Normalized X mouse/touch position relative to the - window */ - double mouseY; /**< Normalized Y mouse/touch position relative to the - window */ - double dx; /**< Normalized horizontal delta for pan/pinch events / - delta in pixels for wheel events */ - double dy; /**< Normalized vertical delta for pan/pinch events / - delta in pixels for wheel events */ - bool mouseLeft; /**< State of the left mouse button (pressed=true) */ - bool mouseRight; /**< State of the right mouse button (pressed=true) */ - bool mouseMiddle; /**< State of the middle mouse button (pressed=true) */ + double mouseX = 0.0; /**< Normalized X mouse/touch position relative to the + window */ + double mouseY = 0.0; /**< Normalized Y mouse/touch position relative to the + window */ + double dx = 0.0; /**< Normalized horizontal delta for pan/pinch events / + delta in pixels for wheel events */ + double dy = 0.0; /**< Normalized vertical delta for pan/pinch events / + delta in pixels for wheel events */ + bool mouseLeft = false; /**< State of left mouse button (pressed=true) */ + bool mouseRight = false; /**< State of right mouse button (pressed=true) */ + bool mouseMiddle = false; /**< State of middle mouse button (pressed=true)*/ //@} /** @name Keyboard events */ //@{ - int key; /**< The key code, see QKeyEvent::key() / number of fingers + int key = 0; /**< The key code, see QKeyEvent::key() / number of fingers for gestures / point id for touch events */ - int modifiers; /**< The keyboard modifiers, see QKeyEvent::modifiers() */ + int modifiers = 0; /**< The keyboard modifiers, see QKeyEvent::modifiers()*/ char text[UNICODE_TEXT_SIZE]; /**< Carries unicode for key, see - QKeyEvent::text() */ + QKeyEvent::text() */ //@} - /** Construct a new event. @version 1.0 */ - Event() - : type(EVT_NONE) - , mouseX(0) - , mouseY(0) - , dx(0) - , dy(0) - , mouseLeft(false) - , mouseRight(false) - , mouseMiddle(false) - , key(0) - , modifiers(0) - , text() - { - } - /** The size of the QDataStream serialized output. */ static const uint32_t serializedSize; }; diff --git a/deflect/ImageSegmenter.cpp b/deflect/ImageSegmenter.cpp index 08637ad..a7c959d 100644 --- a/deflect/ImageSegmenter.cpp +++ b/deflect/ImageSegmenter.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Stefan.Eilemann@epfl.ch */ /* All rights reserved. */ @@ -53,14 +53,11 @@ namespace deflect { -namespace -{ -bool _isOnRightSideOfSideBySideImage(const Segment& segment) +bool ImageSegmenter::_isOnRightSideOfSideBySideImage(const SegmentTask& segment) { return segment.sourceImage->view == View::side_by_side && segment.view == View::right_eye; } -} bool ImageSegmenter::generate(const ImageWrapper& image, Handler handler) { @@ -71,7 +68,7 @@ bool ImageSegmenter::generate(const ImageWrapper& image, Handler handler) Segment ImageSegmenter::createSingleSegment(const ImageWrapper& image) { - auto segments = _generateSegments(image); + auto segments = _generateSegmentTasks(image); if (segments.size() > 1) throw std::runtime_error( "createSingleSegment only works for small images"); @@ -114,7 +111,7 @@ bool ImageSegmenter::_generateJpeg(const ImageWrapper& image, { #ifdef DEFLECT_USE_LIBJPEGTURBO // The resulting Jpeg segments - auto segments = _generateSegments(image); + auto segments = _generateSegmentTasks(image); // start creating JPEGs for each segment, in parallel QtConcurrent::map(segments, std::bind(&ImageSegmenter::_computeJpeg, this, @@ -129,8 +126,13 @@ bool ImageSegmenter::_generateJpeg(const ImageWrapper& image, { bool result = true; for (; i < segments.size(); ++i) - if (!handler(_sendQueue.dequeue())) + { + const auto segment = _sendQueue.dequeue(); + if (segment.exception) + std::rethrow_exception(segment.exception); + if (!handler(segment)) result = false; + } return result; } catch (...) @@ -155,7 +157,7 @@ bool ImageSegmenter::_generateJpeg(const ImageWrapper& image, #endif } -void ImageSegmenter::_computeJpeg(Segment& segment, const bool sendSegment) +void ImageSegmenter::_computeJpeg(SegmentTask& segment, const bool sendSegment) { #ifdef DEFLECT_USE_LIBJPEGTURBO QRect imageRegion(segment.parameters.x - segment.sourceImage->x, @@ -188,7 +190,7 @@ void ImageSegmenter::_computeJpeg(Segment& segment, const bool sendSegment) bool ImageSegmenter::_generateRaw(const ImageWrapper& image, const Handler& handler) const { - auto segments = _generateSegments(image); + auto segments = _generateSegmentTasks(image); for (auto& segment : segments) { segment.imageData.reserve(segment.parameters.width * @@ -230,17 +232,18 @@ bool ImageSegmenter::_generateRaw(const ImageWrapper& image, return true; } -Segments ImageSegmenter::_generateSegments(const ImageWrapper& image) const +ImageSegmenter::SegmentTasks ImageSegmenter::_generateSegmentTasks( + const ImageWrapper& image) const { - Segments segments; + SegmentTasks segments; for (const auto& params : _makeSegmentParameters(image)) { - Segment segment; + SegmentTask segment; segment.parameters = params; segment.view = image.view == View::side_by_side ? View::left_eye : image.view; - segment.sourceImage = ℑ segment.rowOrder = image.rowOrder; + segment.sourceImage = ℑ segments.push_back(segment); } @@ -262,7 +265,7 @@ Segments ImageSegmenter::_generateSegments(const ImageWrapper& image) const return segments; } -SegmentParametersList ImageSegmenter::_makeSegmentParameters( +ImageSegmenter::SegmentParametersList ImageSegmenter::_makeSegmentParameters( const ImageWrapper& image) const { const auto info = _makeSegmentationInfo(image); diff --git a/deflect/ImageSegmenter.h b/deflect/ImageSegmenter.h index fc9525e..9fa1d2b 100644 --- a/deflect/ImageSegmenter.h +++ b/deflect/ImageSegmenter.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Stefan.Eilemann@epfl.ch */ /* All rights reserved. */ @@ -66,13 +66,13 @@ class ImageSegmenter /** * Generate segments. * - * The generation might be parallelized, calling the handler function - * concurrently in multiple threads for different segments. When one handler - * fails, the remaining handlers may or may not be executed. + * The generation might be parallelized, but the Handler callback is always + * executed from the calling thread. When one handle() fails, the remaining + * handle() calls may or may not be executed. * - * @param image The image to be segmented + * @param image The image to be segmented. * @param handler the function to handle the generated segment. - * @return true if all image handlers returned true, false on failure + * @return true if all image handlers returned true, false on failure. * @see setNominalSegmentDimensions() */ DEFLECT_API bool generate(const ImageWrapper& image, Handler handler); @@ -117,11 +117,24 @@ class ImageSegmenter uint lastHeight = 0; }; + struct SegmentTask : Segment + { + /** Uncompressed source image used for compression */ + const ImageWrapper* sourceImage = nullptr; + + /** Holds potential exception from compression thread */ + std::exception_ptr exception; + }; + static bool _isOnRightSideOfSideBySideImage(const SegmentTask& segment); + bool _generateJpeg(const ImageWrapper& image, const Handler& handler); - void _computeJpeg(Segment& task, bool sendSegment); + void _computeJpeg(SegmentTask& segment, bool sendSegment); bool _generateRaw(const ImageWrapper& image, const Handler& handler) const; - Segments _generateSegments(const ImageWrapper& image) const; + using SegmentTasks = std::vector; + SegmentTasks _generateSegmentTasks(const ImageWrapper& image) const; + + using SegmentParametersList = std::vector; SegmentParametersList _makeSegmentParameters( const ImageWrapper& image) const; SegmentationInfo _makeSegmentationInfo(const ImageWrapper& image) const; @@ -129,7 +142,7 @@ class ImageSegmenter uint _nominalSegmentWidth = 0; uint _nominalSegmentHeight = 0; - MTQueue _sendQueue; + MTQueue _sendQueue; }; } #endif diff --git a/deflect/ImageWrapper.cpp b/deflect/ImageWrapper.cpp index 8cc6cc5..eb3389a 100644 --- a/deflect/ImageWrapper.cpp +++ b/deflect/ImageWrapper.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -73,25 +73,4 @@ size_t ImageWrapper::getBufferSize() const { return width * height * getBytesPerPixel(); } - -void ImageWrapper::swapYAxis(void* data, const unsigned int width, - const unsigned int height, const unsigned int bpp) -{ - unsigned char* src = (unsigned char*)data; - - size_t bytesPerLine = width * bpp; - size_t bufferSize = bytesPerLine * height; - - unsigned char* tmp = new unsigned char[bufferSize]; - - for (size_t y = 0; y < height; ++y) - { - memcpy((void*)(&tmp[y * bytesPerLine]), - (const void*)&src[(height - y - 1) * bytesPerLine], - bytesPerLine); - } - memcpy(data, (const void*)tmp, bufferSize); - - delete[] tmp; -} } diff --git a/deflect/ImageWrapper.h b/deflect/ImageWrapper.h index 27720bb..1501fbf 100644 --- a/deflect/ImageWrapper.h +++ b/deflect/ImageWrapper.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -128,12 +128,12 @@ struct ImageWrapper 100 best, default: 75). @version 1.0 */ ChromaSubsampling subsampling; /**< Chrominance sub-sampling. - (default: YUV444). @version 1.6 */ + (default: YUV444). @version 1.0 */ //@} /** * The view that this image represents. - * @version 1.6 + * @version 1.0 */ View view = View::mono; @@ -148,8 +148,7 @@ struct ImageWrapper * frame's segments need to be reordered in addtion to flipping them * individually. * - * This is an alternative to calling swapYAxis() before sending. - * @version 1.7 + * @version 1.0 */ RowOrder rowOrder = RowOrder::top_down; @@ -164,22 +163,6 @@ struct ImageWrapper * @version 1.0 */ DEFLECT_API size_t getBufferSize() const; - - /** - * Swap an image along the Y axis. - * - * Used to switch between OpenGL convention (origin in bottom-left corner) - * and "standard" image format (origin in top-left corner). - * @param data The image buffer to be modified, containing width*height*bpp - * bytes - * @param width The width of the image - * @param height The height of the image - * @param bpp The number of bytes per pixel (RGB=3, ARGB=4, etc.) - * @version 1.0 - */ - DEFLECT_API static void swapYAxis(void* data, const unsigned int width, - const unsigned int height, - const unsigned int bpp); }; } diff --git a/deflect/MessageHeader.h b/deflect/MessageHeader.h index 090cd6c..7c4ae3b 100644 --- a/deflect/MessageHeader.h +++ b/deflect/MessageHeader.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael.Dumusc@epfl.ch */ /* Daniel.Nachbaur@epfl.ch */ /* Redistribution and use in source and binary forms, with or */ diff --git a/deflect/Observer.h b/deflect/Observer.h index 1328b29..529b984 100644 --- a/deflect/Observer.h +++ b/deflect/Observer.h @@ -62,9 +62,6 @@ class StreamPrivate; * * On the server side the observer also opens and closes the stream as regular * deflect::Streams would do. - * - * This class is new since version 1.7 while sharing the same API as - * deflect::Stream prior 1.7. */ class Observer { @@ -81,7 +78,7 @@ class Observer * unique identifier will be used. * @throw std::runtime_error if DEFLECT_HOST was not provided or no * connection to server could be established - * @version 1.7 + * @version 1.0 */ DEFLECT_API Observer(); @@ -94,7 +91,7 @@ class Observer * @param port Port of the Server instance. * @throw std::runtime_error if DEFLECT_HOST was not provided or no * connection to server could be established - * @version 1.3 + * @version 1.0 */ DEFLECT_API explicit Observer(unsigned short port); @@ -131,13 +128,13 @@ class Observer */ DEFLECT_API bool isConnected() const; - /** @return the identifier defined by the constructor. @version 1.3 */ + /** @return the identifier defined by the constructor. @version 1.0 */ DEFLECT_API const std::string& getId() const; - /** @return the host defined by the constructor. @version 1.3 */ + /** @return the host defined by the constructor. @version 1.0 */ DEFLECT_API const std::string& getHost() const; - /** @return the remote port the observer is connected to. @version 1.7 */ + /** @return the remote port the observer is connected to. @version 1.0 */ DEFLECT_API unsigned short getPort() const; /** @@ -217,7 +214,7 @@ class Observer * * @param callback the function to call * @note replaces the previous disconnected signal - * @version 1.5 + * @version 1.0 */ DEFLECT_API void setDisconnectedCallback(std::function callback); @@ -227,7 +224,7 @@ class Observer * * @note blocks until all pending asynchonous send operations are finished. * @param hints the new size hints for the server - * @version 1.2 + * @version 1.0 */ DEFLECT_API void sendSizeHints(const SizeHints& hints); @@ -238,7 +235,7 @@ class Observer * @param data the pointer to the data buffer. * @param count the number of bytes to send. * @return true if the data could be sent, false otherwise - * @version 1.3 + * @version 1.0 */ DEFLECT_API bool sendData(const char* data, size_t count); diff --git a/deflect/Segment.h b/deflect/Segment.h index ae409d0..6aa516c 100644 --- a/deflect/Segment.h +++ b/deflect/Segment.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -46,28 +46,18 @@ namespace deflect { -struct ImageWrapper; - /** - * Image data and parameters for a single segment of a PixelStream. + * Image data and parameters for a single segment of a Frame. */ struct Segment { - /** Parameters of the segment. */ SegmentParameters parameters; - - View view = View::mono; //!< Eye pass for the segment - - /** Image data of the segment. */ QByteArray imageData; - RowOrder rowOrder = RowOrder::top_down; //!< imageData row order - - /** @internal raw, uncompressed source image, used for compression */ - const ImageWrapper* sourceImage = nullptr; + /** Extra parameters sent separately for network protocol compatiblity. */ - /** @internal holds potential exception from compression thread */ - std::exception_ptr exception; + View view = View::mono; //!< Eye pass for the segment + RowOrder rowOrder = RowOrder::top_down; //!< Row order of imageData }; } diff --git a/deflect/SegmentParameters.h b/deflect/SegmentParameters.h index a6e2559..e1936a2 100644 --- a/deflect/SegmentParameters.h +++ b/deflect/SegmentParameters.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -52,7 +52,7 @@ namespace deflect { /** * The possible formats for segment data. - * @version 1.6 + * @version 1.0 */ enum class DataType : std::uint8_t { @@ -64,7 +64,8 @@ enum class DataType : std::uint8_t }; /** - * Parameters for a Frame Segment. + * Parameters for a Segment of a Frame. + * @version 1.0 */ struct SegmentParameters { @@ -80,8 +81,15 @@ struct SegmentParameters uint32_t height = 0u; /**< The height in pixels. */ //@} - /** Data format of the Segment. @version 1.6 */ + /** Format in which the segment data is stored. */ DataType dataType = DataType::jpeg; + + /** + * WARNING: + * Extending this struct breaks compatibility with current + * NETWORK_PROTOCOL_VERSION == 8. This is due to the use of + * sizeof(SegmentParameters) in (de)serialization code. + */ }; } diff --git a/deflect/ServerWorker.cpp b/deflect/ServerWorker.cpp index ee4e3ab..f30b251 100644 --- a/deflect/ServerWorker.cpp +++ b/deflect/ServerWorker.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Daniel.Nachbaur@epfl.ch */ /* All rights reserved. */ @@ -59,9 +59,6 @@ ServerWorker::ServerWorker(const int socketDescriptor) // *this* so it gets moved to thread , _sourceId{socketDescriptor} , _clientProtocolVersion{NETWORK_PROTOCOL_VERSION} - , _registeredToEvents{false} - , _activeView{View::mono} - , _activeRowOrder{RowOrder::top_down} { if (!_tcpSocket->setSocketDescriptor(socketDescriptor)) { @@ -151,9 +148,9 @@ void ServerWorker::_processMessages() void ServerWorker::_receiveMessage() { - const MessageHeader mh = _receiveMessageHeader(); - const QByteArray messageByteArray = _receiveMessageBody(mh.size); - _handleMessage(mh, messageByteArray); + const auto messageHeader = _receiveMessageHeader(); + const auto messageBody = _receiveMessageBody(messageHeader.size); + _handleMessage(messageHeader, messageBody); } MessageHeader ServerWorker::_receiveMessageHeader() @@ -249,9 +246,8 @@ void ServerWorker::_handleMessage(const MessageHeader& messageHeader, case MESSAGE_TYPE_SIZE_HINTS: { - const SizeHints* hints = - reinterpret_cast(byteArray.data()); - emit receivedSizeHints(_streamId, SizeHints(*hints)); + const auto hints = reinterpret_cast(byteArray.data()); + emit receivedSizeHints(_streamId, *hints); break; } diff --git a/deflect/ServerWorker.h b/deflect/ServerWorker.h index 2f9a86b..899bb98 100644 --- a/deflect/ServerWorker.h +++ b/deflect/ServerWorker.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Daniel.Nachbaur@epfl.ch */ /* All rights reserved. */ @@ -95,18 +95,18 @@ private slots: void _processMessages(); private: - QTcpSocket* _tcpSocket; + QTcpSocket* _tcpSocket = nullptr; QString _streamId; - int _sourceId; - int _clientProtocolVersion; - bool _observer{false}; + int _sourceId = -1; + int _clientProtocolVersion = -1; + bool _observer = false; - bool _registeredToEvents; + bool _registeredToEvents = false; QQueue _events; - View _activeView; - RowOrder _activeRowOrder; + View _activeView = View::mono; + RowOrder _activeRowOrder = RowOrder::top_down; void _receiveMessage(); MessageHeader _receiveMessageHeader(); diff --git a/deflect/SizeHints.h b/deflect/SizeHints.h index 08c25ec..0805877 100644 --- a/deflect/SizeHints.h +++ b/deflect/SizeHints.h @@ -40,15 +40,13 @@ #ifndef DEFLECT_SIZEHINTS_H #define DEFLECT_SIZEHINTS_H -#include - namespace deflect { /** * A struct that contains hints about minimum, maximum and preferred sizes of a * streamer which can be interpreted by the stream server accordingly. * - * @version 1.2 + * @version 1.0 */ struct SizeHints { @@ -75,7 +73,7 @@ struct SizeHints }; /** @return true if rhs and this are equal for all sizes. */ -inline bool operator==(const SizeHints& lhs, const SizeHints& rhs) NOEXCEPT +inline bool operator==(const SizeHints& lhs, const SizeHints& rhs) noexcept { return lhs.minWidth == rhs.minWidth && lhs.minHeight == rhs.minHeight && lhs.maxWidth == rhs.maxWidth && lhs.maxHeight == rhs.maxHeight && @@ -84,7 +82,7 @@ inline bool operator==(const SizeHints& lhs, const SizeHints& rhs) NOEXCEPT } /** @return true if rhs and this not equal for any size. */ -inline bool operator!=(const SizeHints& lhs, const SizeHints& rhs) NOEXCEPT +inline bool operator!=(const SizeHints& lhs, const SizeHints& rhs) noexcept { return !(lhs == rhs); } diff --git a/deflect/Stream.h b/deflect/Stream.h index 3007638..5cda1ec 100644 --- a/deflect/Stream.h +++ b/deflect/Stream.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Stefan.Eilemann@epfl.ch */ /* Daniel.Nachbaur@epfl.ch */ @@ -71,7 +71,7 @@ class Stream : public Observer * unique identifier will be used. * @throw std::runtime_error if DEFLECT_HOST was not provided or no * connection to server could be established - * @version 1.7 + * @version 1.0 */ DEFLECT_API Stream(); @@ -84,7 +84,7 @@ class Stream : public Observer * @param port Port of the Server instance. * @throw std::runtime_error if DEFLECT_HOST was not provided or no * connection to server could be established - * @version 1.3 + * @version 1.0 */ DEFLECT_API explicit Stream(unsigned short port); @@ -118,7 +118,7 @@ class Stream : public Observer /** @name Asynchronous send API */ //@{ - /** Future signaling success of asyncSend(). @version 1.5 */ + /** Future signaling success of asyncSend(). @version 1.0 */ using Future = std::future; /** @@ -131,7 +131,7 @@ class Stream : public Observer * @throw std::invalid_argument if invalid JPEG compression arguments * @throw std::runtime_error if pending finishFrame() has not been completed * @throw std::runtime_error if JPEG compression failed - * @version 1.6 + * @version 1.0 * @sa finishFrame() */ DEFLECT_API Future send(const ImageWrapper& image); @@ -146,7 +146,7 @@ class Stream : public Observer * stereo rendering. * * @sa send() - * @version 1.6 + * @version 1.0 */ DEFLECT_API Future finishFrame(); @@ -165,12 +165,9 @@ class Stream : public Observer * @throw std::runtime_error if pending finishFrame() has not been completed * @throw std::runtime_error if JPEG compression failed * @see send() - * @version 1.6 + * @version 1.0 */ DEFLECT_API Future sendAndFinish(const ImageWrapper& image); - - /** @deprecated */ - Future asyncSend(const ImageWrapper& image) { return sendAndFinish(image); } //@} private: diff --git a/deflect/StreamEventThread.cpp b/deflect/StreamEventThread.cpp deleted file mode 100644 index 546dbe9..0000000 --- a/deflect/StreamEventThread.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ -/* All rights reserved. */ -/* */ -/* Redistribution and use in source and binary forms, with or */ -/* without modification, are permitted provided that the following */ -/* conditions are met: */ -/* */ -/* 1. Redistributions of source code must retain the above */ -/* copyright notice, this list of conditions and the following */ -/* disclaimer. */ -/* */ -/* 2. Redistributions in binary form must reproduce the above */ -/* copyright notice, this list of conditions and the following */ -/* disclaimer in the documentation and/or other materials */ -/* provided with the distribution. */ -/* */ -/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */ -/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */ -/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ -/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ -/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */ -/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */ -/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ -/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ -/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ -/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ -/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ -/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */ -/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ -/* POSSIBILITY OF SUCH DAMAGE. */ -/* */ -/* The views and conclusions contained in the software and */ -/* documentation are those of the authors and should not be */ -/* interpreted as representing official policies, either expressed */ -/* or implied, of The University of Texas at Austin. */ -/*********************************************************************/ - -#include "StreamEventThread.h" - -StreamEventThread::StreamEventThread() -{ -} - -void StreamEventThread::storeNewInteractionState(InteractionState state) -{ - QMutexLocker lock(&interactionStateMutex_); - interactionStates_.enqueue(state); -} - -bool StreamEventThread::hasPendingInteractionState() const -{ - QMutexLocker lock(&interactionStateMutex_); - return !interactionStates_.empty(); -} - -InteractionState StreamEventThread::retrieveInteractionState() -{ - QMutexLocker lock(&interactionStateMutex_); - - if (interactionStates_.empty()) - return InteractionState(); - - return interactionStates_.dequeue(); -} - -void StreamEventThread::run() -{ - put_flog(LOG_DEBUG, "started"); - - while (true) - { - // break here if we had a failure - if (!sendMessage_()) - break; - - MESSAGE_TYPE type; - receiveMessage_(type); - - // make sure the socket is still connected - if (socket_->state() != QAbstractSocket::ConnectedState) - { - put_flog(LOG_ERROR, "socket disconnected"); - break; - } - - // flush the socket - socket_->flush(); - - // break if disconnect() was called - { - QMutexLocker locker(&disconnectFlagMutex_); - - if (disconnectFlag_ == true) - { - break; - } - } - } - - // delete the socket - delete socket_; - socket_ = NULL; - - put_flog(LOG_DEBUG, "finished"); -} - -bool StreamEventThread::queueMessage(QByteArray message) -{ - // only queue the message if we're connected - if (!isConnected()) - { - return false; - } - - { - QMutexLocker locker(&sendMessagesQueueMutex_); - sendMessagesQueue_.push(message); - } - - sendMessage_(); - - return true; -} - -bool StreamEventThread::sendMessage_() -{ - // send a message if available - QByteArray sendMessage; - - { - QMutexLocker locker(&sendMessagesQueueMutex_); - - if (sendMessagesQueue_.size() > 0) - { - sendMessage = sendMessagesQueue_.front(); - sendMessagesQueue_.pop(); - } - } - - if (!sendMessage.isEmpty()) - { - bool success = socketSendMessage(sendMessage); - - if (!success) - { - put_flog(LOG_ERROR, "error sending message"); - return false; - } - } - return true; -} - -bool StreamEventThread::receiveMessage_(MESSAGE_TYPE& type) -{ - type = MESSAGE_TYPE_NONE; - - if (socket_->bytesAvailable() < (int)sizeof(MessageHeader)) - return false; - - MessageHeader messageHeader; - QByteArray message; - - bool success = socketReceiveMessage(messageHeader, message); - - if (!success) - { - put_flog(LOG_ERROR, "error receiving message"); - return false; - } - - type = messageHeader.type; - - // handle the message - if (type == MESSAGE_TYPE_ACK) - { - } - else if (type == MESSAGE_TYPE_INTERACTION) - { - InteractionState interactionState = - *(InteractionState*)(message.data()); - emit received(interactionState); - } - else if (type == MESSAGE_TYPE_BIND_INTERACTION_REPLY) - { - bool success = *(bool*)(message.data()); - emit receivedInteractionBindReply(success); - } - else if (type == MESSAGE_TYPE_QUIT) - { - put_flog(LOG_INFO, "Received QUIT - TODO implement this action"); - } - else - { - put_flog(LOG_ERROR, "unknown message header type %i", type); - return false; - } - return true; -} diff --git a/deflect/StreamEventThread.h b/deflect/StreamEventThread.h deleted file mode 100644 index 39aca20..0000000 --- a/deflect/StreamEventThread.h +++ /dev/null @@ -1,88 +0,0 @@ -/*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ -/* All rights reserved. */ -/* */ -/* Redistribution and use in source and binary forms, with or */ -/* without modification, are permitted provided that the following */ -/* conditions are met: */ -/* */ -/* 1. Redistributions of source code must retain the above */ -/* copyright notice, this list of conditions and the following */ -/* disclaimer. */ -/* */ -/* 2. Redistributions in binary form must reproduce the above */ -/* copyright notice, this list of conditions and the following */ -/* disclaimer in the documentation and/or other materials */ -/* provided with the distribution. */ -/* */ -/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */ -/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */ -/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ -/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ -/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */ -/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */ -/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ -/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ -/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ -/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ -/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ -/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */ -/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ -/* POSSIBILITY OF SUCH DAMAGE. */ -/* */ -/* The views and conclusions contained in the software and */ -/* documentation are those of the authors and should not be */ -/* interpreted as representing official policies, either expressed */ -/* or implied, of The University of Texas at Austin. */ -/*********************************************************************/ - -#ifndef DEFLECT_STREAMEVENTTHREAD_H -#define DEFLECT_STREAMEVENTTHREAD_H - -#include - -#include -#include -#include - -/** - * This class might serve as an EventProcessing thread to read InteractionStates - * from the Socket. - * - * !!! IT IS NOT IMPLEMENTED YET !!! - */ -class StreamEventThread : public QObject -{ - Q_OBJECT - -public: - StreamEventThread(); - - // queue a message to be sent (non-blocking) - bool queueMessage(QByteArray message); - - // current interaction state - mutable QMutex interactionStateMutex_; - QQueue interactionStates_; - - bool hasPendingInteractionState() const; - InteractionState retrieveInteractionState(); - - // thread execution - void run() final; - -public slots: - void storeNewInteractionState(InteractionState state); - void setInteractionBound(bool success); - -private: - // mutex and queue for messages to send - QMutex sendMessagesQueueMutex_; - std::queue sendMessagesQueue_; - - bool sendMessage_(); - bool receiveMessage_(MESSAGE_TYPE& type); -}; - -#endif diff --git a/deflect/StreamPrivate.h b/deflect/StreamPrivate.h index 11ed490..f6c4138 100644 --- a/deflect/StreamPrivate.h +++ b/deflect/StreamPrivate.h @@ -98,8 +98,6 @@ class StreamPrivate Stream::Future send(const SizeHints& hints); Stream::Future send(QByteArray&& data); Stream::Future sendImage(const ImageWrapper& image, bool finish); - Stream::Future sendSingleSegment(Segment&& segment, RowOrder orientation, - bool finish); Stream::Future sendFinishFrame(); /** @internal Called by StreamSendWorker when finishFrame was processed. */ diff --git a/deflect/StreamSendWorker.cpp b/deflect/StreamSendWorker.cpp index 14ea127..a9cc25f 100644 --- a/deflect/StreamSendWorker.cpp +++ b/deflect/StreamSendWorker.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Daniel.Nachbaur@epfl.ch */ /* Raphael Dumusc */ /* All rights reserved. */ @@ -192,9 +192,6 @@ bool StreamSendWorker::_sendClose() bool StreamSendWorker::_sendSegment(const Segment& segment) { - if (segment.exception) - std::rethrow_exception(segment.exception); - if (segment.view != _currentView) { if (!_sendImageView(segment.view)) diff --git a/deflect/config.h b/deflect/config.h deleted file mode 100644 index 15dad53..0000000 --- a/deflect/config.h +++ /dev/null @@ -1,51 +0,0 @@ -/*********************************************************************/ -/* Copyright (c) 2015, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ -/* All rights reserved. */ -/* */ -/* Redistribution and use in source and binary forms, with or */ -/* without modification, are permitted provided that the following */ -/* conditions are met: */ -/* */ -/* 1. Redistributions of source code must retain the above */ -/* copyright notice, this list of conditions and the following */ -/* disclaimer. */ -/* */ -/* 2. Redistributions in binary form must reproduce the above */ -/* copyright notice, this list of conditions and the following */ -/* disclaimer in the documentation and/or other materials */ -/* provided with the distribution. */ -/* */ -/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */ -/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */ -/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ -/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ -/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */ -/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */ -/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ -/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ -/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ -/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ -/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ -/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */ -/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ -/* POSSIBILITY OF SUCH DAMAGE. */ -/* */ -/* The views and conclusions contained in the software and */ -/* documentation are those of the authors and should not be */ -/* interpreted as representing official policies, either expressed */ -/* or implied, of The University of Texas at Austin. */ -/*********************************************************************/ - -#ifndef DEFLECT_CONFIG_H -#define DEFLECT_CONFIG_H - -#ifndef NOEXCEPT -#ifdef _MSC_VER -#define NOEXCEPT -#else -#define NOEXCEPT noexcept -#endif -#endif - -#endif diff --git a/deflect/types.h b/deflect/types.h index 53d6c2d..8248812 100644 --- a/deflect/types.h +++ b/deflect/types.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2014-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2014-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Daniel.Nachbaur@epfl.ch */ /* All rights reserved. */ @@ -41,8 +41,6 @@ #ifndef DEFLECT_TYPES_H #define DEFLECT_TYPES_H -#include - #include #include #include @@ -80,6 +78,7 @@ constexpr typename std::underlying_type::type as_underlying_type(E e) return static_cast::type>(e); } +/** Make a ready future with the given value. */ template std::future make_ready_future(T&& value) { @@ -88,6 +87,7 @@ std::future make_ready_future(T&& value) return promise.get_future(); } +/** Make a ready future with the given exception. */ template std::future make_exception_future(std::exception_ptr&& e) { @@ -95,6 +95,8 @@ std::future make_exception_future(std::exception_ptr&& e) promise.set_exception(std::move(e)); return promise.get_future(); } + +/** Make a ready future with the given exception. */ template std::future make_exception_future(Exception&& e) { @@ -119,7 +121,6 @@ struct SizeHints; using BoolPromisePtr = std::shared_ptr>; using FramePtr = std::shared_ptr; using Segments = std::vector; -using SegmentParametersList = std::vector; namespace qt { diff --git a/doc/Changelog.md b/doc/Changelog.md index cf4c804..a52fa66 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -1,6 +1,13 @@ Changelog {#Changelog} ============ +## Deflect 1.0 + +### 1.0.0 (git master) +* [194](https://github.com/BlueBrain/Deflect/pull/194): + Reset API versionning to 1.0, remove deprecated functions (Stream::asyncSend, + ImageWrapper::swapYAxis). + ## Deflect 0.14 ### 0.14.1 (01-05-2018) diff --git a/tests/cpp/ImageWrapperTests.cpp b/tests/cpp/ImageWrapperTests.cpp index ba58060..85341ce 100644 --- a/tests/cpp/ImageWrapperTests.cpp +++ b/tests/cpp/ImageWrapperTests.cpp @@ -90,95 +90,3 @@ BOOST_AUTO_TEST_CASE(testImageBytesPerPixel) BOOST_CHECK_EQUAL(imageWrapper.getBytesPerPixel(), 4); } } - -BOOST_AUTO_TEST_CASE(testImageReorderGLImageData) -{ - { - // clang-format off - char dataIn[] = - { - 1,1,1, 2,2,2, 3,3,3, 4,4,4, - 5,5,5, 6,6,6, 7,7,7, 8,8,8 - }; - char dataOut[] = - { - 5,5,5, 6,6,6, 7,7,7, 8,8,8, - 1,1,1, 2,2,2, 3,3,3, 4,4,4 - }; - // clang-format on - - deflect::ImageWrapper::swapYAxis(dataIn, 4, 2, 3); - - BOOST_CHECK_EQUAL_COLLECTIONS(dataIn, dataIn + 24, dataOut, - dataOut + 24); - } - - { - // clang-format off - char dataIn[] = - { - 1,1,1, 2,2,2, - 3,3,3, 4,4,4, - 5,5,5, 6,6,6, - 7,7,7, 8,8,8 - }; - char dataOut[] = - { - 7,7,7, 8,8,8, - 5,5,5, 6,6,6, - 3,3,3, 4,4,4, - 1,1,1, 2,2,2 - }; - // clang-format on - - deflect::ImageWrapper::swapYAxis(dataIn, 2, 4, 3); - - BOOST_CHECK_EQUAL_COLLECTIONS(dataIn, dataIn + 24, dataOut, - dataOut + 24); - } - - { - // clang-format off - char dataIn[] = - { - 1,1,1,2, 2,2,3,3, - 3,4,4,4, 5,5,5,6, - 6,6,7,7, 7,8,8,8 - }; - char dataOut[] = - { - 6,6,7,7, 7,8,8,8, - 3,4,4,4, 5,5,5,6, - 1,1,1,2, 2,2,3,3 - }; - // clang-format on - - deflect::ImageWrapper::swapYAxis(dataIn, 2, 3, 4); - - BOOST_CHECK_EQUAL_COLLECTIONS(dataIn, dataIn + 24, dataOut, - dataOut + 24); - } - - { - // clang-format off - char dataIn[] = - { - 1,1,1,2, 2,2,3,3, - 3,4,4,4, 5,5,5,6, - 6,6,7,7, 7,8,8,8 - }; - char dataOut[] = - { - 1,1,1,2, 2,2,3,3, - 3,4,4,4, 5,5,5,6, - 6,6,7,7, 7,8,8,8 - }; - // clang-format on - - deflect::ImageWrapper::swapYAxis(dataIn, 2, 3, 4); - deflect::ImageWrapper::swapYAxis(dataIn, 2, 3, 4); - - BOOST_CHECK_EQUAL_COLLECTIONS(dataIn, dataIn + 24, dataOut, - dataOut + 24); - } -} diff --git a/tests/cpp/perf/benchmarkStreamer.cpp b/tests/cpp/perf/benchmarkStreamer.cpp index ab5c376..03a2155 100644 --- a/tests/cpp/perf/benchmarkStreamer.cpp +++ b/tests/cpp/perf/benchmarkStreamer.cpp @@ -211,13 +211,10 @@ class Application deflectImage.compressionPolicy = deflect::COMPRESSION_ON; deflectImage.compressionQuality = _options.quality; - static QMutex lock; - const auto appendHandler = [&](const deflect::Segment& segment) { - QMutexLocker locker(&lock); + const auto appendHandler = [this](const deflect::Segment& segment) { _jpegSegments.push_back(segment); return true; }; - return segmenter.generate(deflectImage, appendHandler); } diff --git a/tests/mock/MockServer.h b/tests/mock/MockServer.h index 8b72596..24e61ca 100644 --- a/tests/mock/MockServer.h +++ b/tests/mock/MockServer.h @@ -44,7 +44,6 @@ typedef __int32 int32_t; #endif -#include #include #include From 9de17a509c92cde89c0509ea495feceab11bf75d Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Tue, 1 May 2018 18:23:17 +0200 Subject: [PATCH 2/4] Moved server classes to a separate DeflectServer library All the server-specific classes are now in the deflect::server namespace. --- deflect/CMakeLists.txt | 23 ++------- deflect/MetaTypeRegistration.cpp | 6 ++- deflect/Observer.h | 2 +- deflect/SegmentParameters.h | 2 +- deflect/Stream.h | 2 +- deflect/StreamPrivate.h | 2 +- deflect/qt/CMakeLists.txt | 9 ++-- deflect/qt/QmlStreamer.h | 4 +- deflect/server/CMakeLists.txt | 48 +++++++++++++++++++ deflect/{ => server}/EventReceiver.h | 10 ++-- deflect/{ => server}/Frame.cpp | 3 ++ deflect/{ => server}/Frame.h | 7 ++- deflect/{ => server}/FrameDispatcher.cpp | 3 ++ deflect/{ => server}/FrameDispatcher.h | 9 ++-- .../{ => server}/ImageJpegDecompressor.cpp | 3 ++ deflect/{ => server}/ImageJpegDecompressor.h | 7 ++- deflect/{ => server}/ReceiveBuffer.cpp | 4 ++ deflect/{ => server}/ReceiveBuffer.h | 9 ++-- deflect/{ => server}/SegmentDecoder.cpp | 9 ++-- deflect/{ => server}/SegmentDecoder.h | 7 ++- deflect/{ => server}/Server.cpp | 6 ++- deflect/{ => server}/Server.h | 13 +++-- deflect/{ => server}/ServerWorker.cpp | 11 +++-- deflect/{ => server}/ServerWorker.h | 13 +++-- deflect/{ => server}/SourceBuffer.cpp | 3 ++ deflect/{ => server}/SourceBuffer.h | 7 ++- deflect/types.h | 19 +++++--- doc/Changelog.md | 5 +- tests/cpp/CMakeLists.txt | 8 ++-- tests/cpp/FrameDispatcherTests.cpp | 15 +++--- tests/cpp/ReceiveBufferTests.cpp | 40 ++++++++-------- tests/cpp/SegmentDecoderTests.cpp | 16 +++---- tests/cpp/ServerTests.cpp | 22 +++++---- tests/cpp/perf/streamTests.cpp | 4 +- tests/mock/CMakeLists.txt | 7 +-- tests/mock/DeflectServer.cpp | 22 ++++----- tests/mock/DeflectServer.h | 14 +++--- tests/mock/FrameUtils.h | 10 ++-- tests/mock/MockServer.h | 2 +- 39 files changed, 256 insertions(+), 150 deletions(-) create mode 100644 deflect/server/CMakeLists.txt rename deflect/{ => server}/EventReceiver.h (95%) rename deflect/{ => server}/Frame.cpp (99%) rename deflect/{ => server}/Frame.h (97%) rename deflect/{ => server}/FrameDispatcher.cpp (99%) rename deflect/{ => server}/FrameDispatcher.h (97%) rename deflect/{ => server}/ImageJpegDecompressor.cpp (99%) rename deflect/{ => server}/ImageJpegDecompressor.h (97%) rename deflect/{ => server}/ReceiveBuffer.cpp (99%) rename deflect/{ => server}/ReceiveBuffer.h (97%) rename deflect/{ => server}/SegmentDecoder.cpp (99%) rename deflect/{ => server}/SegmentDecoder.h (98%) rename deflect/{ => server}/Server.cpp (99%) rename deflect/{ => server}/Server.h (95%) rename deflect/{ => server}/ServerWorker.cpp (99%) rename deflect/{ => server}/ServerWorker.h (94%) rename deflect/{ => server}/SourceBuffer.cpp (99%) rename deflect/{ => server}/SourceBuffer.h (97%) diff --git a/deflect/CMakeLists.txt b/deflect/CMakeLists.txt index a2b6b31..ffc6142 100644 --- a/deflect/CMakeLists.txt +++ b/deflect/CMakeLists.txt @@ -5,13 +5,10 @@ set(DEFLECT_PUBLIC_HEADERS Event.h - EventReceiver.h - Frame.h ImageWrapper.h Observer.h Segment.h SegmentParameters.h - Server.h SizeHints.h Stream.h types.h @@ -20,33 +17,23 @@ set(DEFLECT_PUBLIC_HEADERS set(DEFLECT_HEADERS moodycamel/blockingconcurrentqueue.h moodycamel/concurrentqueue.h - FrameDispatcher.h ImageSegmenter.h MessageHeader.h MTQueue.h NetworkProtocol.h - ReceiveBuffer.h - ServerWorker.h Socket.h - SourceBuffer.h StreamPrivate.h TaskBuilder.h ) set(DEFLECT_SOURCES Event.cpp - Frame.cpp - FrameDispatcher.cpp ImageSegmenter.cpp ImageWrapper.cpp MessageHeader.cpp MetaTypeRegistration.cpp Observer.cpp - ReceiveBuffer.cpp - Server.cpp - ServerWorker.cpp Socket.cpp - SourceBuffer.cpp Stream.cpp StreamPrivate.cpp StreamSendWorker.cpp @@ -62,23 +49,19 @@ if(APPLE) endif() if(DEFLECT_USE_LIBJPEGTURBO) - list(APPEND DEFLECT_PUBLIC_HEADERS - SegmentDecoder.h - ) list(APPEND DEFLECT_HEADERS ImageJpegCompressor.h - ImageJpegDecompressor.h ) list(APPEND DEFLECT_SOURCES ImageJpegCompressor.cpp - ImageJpegDecompressor.cpp - SegmentDecoder.cpp ) - list(APPEND DEFLECT_LINK_LIBRARIES ${LibJpegTurbo_LIBRARIES}) + list(APPEND DEFLECT_LINK_LIBRARIES PRIVATE ${LibJpegTurbo_LIBRARIES}) endif() common_library(Deflect) +add_subdirectory(server) + if(Qt5Qml_FOUND AND Qt5Quick_FOUND AND NOT Qt5Quick_VERSION VERSION_LESS 5.4) add_subdirectory(qt) endif() diff --git a/deflect/MetaTypeRegistration.cpp b/deflect/MetaTypeRegistration.cpp index 736d7e8..2620e89 100644 --- a/deflect/MetaTypeRegistration.cpp +++ b/deflect/MetaTypeRegistration.cpp @@ -55,12 +55,14 @@ struct MetaTypeRegistration MetaTypeRegistration() { qRegisterMetaType("size_t"); - qRegisterMetaType("deflect::BoolPromisePtr"); qRegisterMetaType("deflect::Segment"); qRegisterMetaType("deflect::SizeHints"); qRegisterMetaType("deflect::Event"); - qRegisterMetaType("deflect::FramePtr"); qRegisterMetaType("deflect::View"); + qRegisterMetaType( + "deflect::server::BoolPromisePtr"); + qRegisterMetaType( + "deflect::server::FramePtr"); } }; diff --git a/deflect/Observer.h b/deflect/Observer.h index 529b984..0e41f03 100644 --- a/deflect/Observer.h +++ b/deflect/Observer.h @@ -55,7 +55,7 @@ namespace deflect class StreamPrivate; /** - * Connect to a deflect::Server and register for events. + * Connect to a deflect Server and register for events. * * In case a dedicated event handling w/o the need for streaming images is * required, the Observer class can be used, in contrast to the deflect::Stream. diff --git a/deflect/SegmentParameters.h b/deflect/SegmentParameters.h index e1936a2..af1bb05 100644 --- a/deflect/SegmentParameters.h +++ b/deflect/SegmentParameters.h @@ -43,7 +43,7 @@ #ifdef _WIN32 typedef unsigned __int32 uint32_t; #else -#include +#include #endif #include diff --git a/deflect/Stream.h b/deflect/Stream.h index 5cda1ec..37ecbc2 100644 --- a/deflect/Stream.h +++ b/deflect/Stream.h @@ -50,7 +50,7 @@ namespace deflect { /** - * Stream visual data to a deflect::Server. + * Stream visual data to a deflect Server. * * A Stream can be subdivided into one or more images and eye passes. This * allows to have different applications each responsible for sending one part diff --git a/deflect/StreamPrivate.h b/deflect/StreamPrivate.h index f6c4138..aaec71e 100644 --- a/deflect/StreamPrivate.h +++ b/deflect/StreamPrivate.h @@ -57,7 +57,7 @@ class StreamPrivate { public: /** - * Create a new stream and open a new connection to the deflect::Server. + * Create a new stream and open a new connection to the deflect Server. * * @param id the unique stream identifier * @param host Address of the target Server instance. diff --git a/deflect/qt/CMakeLists.txt b/deflect/qt/CMakeLists.txt index c4f097f..23fe4a6 100644 --- a/deflect/qt/CMakeLists.txt +++ b/deflect/qt/CMakeLists.txt @@ -1,5 +1,5 @@ -# Copyright (c) 2015-2016, EPFL/Blue Brain Project +# Copyright (c) 2015-2018, EPFL/Blue Brain Project # Daniel Nachbaur # Raphael Dumusc @@ -24,9 +24,12 @@ set(DEFLECTQT_SOURCES ) set(DEFLECTQT_LINK_LIBRARIES - PUBLIC Deflect Qt5::Quick PRIVATE Qt5::Qml) + PUBLIC Deflect Qt5::Quick PRIVATE Qt5::Qml +) + set(DEFLECTQT_INCLUDE_NAME deflect/qt) -set(DEFLECTQT_NAMESPACE deflectqt) +set(DEFLECTQT_OMIT_VERSION_HEADERS ON) + common_library(DeflectQt) if(DEFLECT_QMLSTREAMER_MULTITHREADED) diff --git a/deflect/qt/QmlStreamer.h b/deflect/qt/QmlStreamer.h index ec47fec..6540d8a 100644 --- a/deflect/qt/QmlStreamer.h +++ b/deflect/qt/QmlStreamer.h @@ -40,7 +40,7 @@ #ifndef DELFECT_QT_QMLSTREAMER_H #define DELFECT_QT_QMLSTREAMER_H -#include +#include #include #include @@ -71,7 +71,7 @@ namespace qt * switch to a "mouse" interaction mode. This allows users to interact within * a WebGL canevas or select text instead of scrolling the page. */ -class DEFLECTQT_API QmlStreamer : public QObject +class DEFLECT_API QmlStreamer : public QObject { Q_OBJECT diff --git a/deflect/server/CMakeLists.txt b/deflect/server/CMakeLists.txt new file mode 100644 index 0000000..2d60f7d --- /dev/null +++ b/deflect/server/CMakeLists.txt @@ -0,0 +1,48 @@ + +# Copyright (c) 2018, EPFL/Blue Brain Project +# Raphael Dumusc + +set(DEFLECTSERVER_PUBLIC_HEADERS + EventReceiver.h + Frame.h + Server.h +) +set(DEFLECTSERVER_HEADERS + FrameDispatcher.h + ServerWorker.h + ReceiveBuffer.h + SourceBuffer.h +) +set(DEFLECTSERVER_SOURCES + Frame.cpp + FrameDispatcher.cpp + Server.cpp + ServerWorker.cpp + ReceiveBuffer.cpp + SourceBuffer.cpp +) + +set(DEFLECTSERVER_LINK_LIBRARIES + PUBLIC Deflect Qt5::Core Qt5::Network +) + +if(DEFLECT_USE_LIBJPEGTURBO) + list(APPEND DEFLECTSERVER_PUBLIC_HEADERS + SegmentDecoder.h + ) + list(APPEND DEFLECTSERVER_HEADERS + ImageJpegDecompressor.h + ) + list(APPEND DEFLECTSERVER_SOURCES + ImageJpegDecompressor.cpp + SegmentDecoder.cpp + ) + list(APPEND DEFLECTSERVER_LINK_LIBRARIES PRIVATE ${LibJpegTurbo_LIBRARIES}) +endif() + +set(DEFLECTSERVER_INCLUDE_NAME deflect/server) +set(DEFLECTSERVER_OMIT_VERSION_HEADERS ON) +# avoid conflict between server.h and Server.h on case-insensitive file systems +set(DEFLECTSERVER_OMIT_LIBRARY_HEADER ON) + +common_library(DeflectServer) diff --git a/deflect/EventReceiver.h b/deflect/server/EventReceiver.h similarity index 95% rename from deflect/EventReceiver.h rename to deflect/server/EventReceiver.h index 8998b13..c786822 100644 --- a/deflect/EventReceiver.h +++ b/deflect/server/EventReceiver.h @@ -37,8 +37,8 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_EVENTRECEIVER_H -#define DEFLECT_EVENTRECEIVER_H +#ifndef DEFLECT_SERVER_EVENTRECEIVER_H +#define DEFLECT_SERVER_EVENTRECEIVER_H #include #include @@ -47,6 +47,8 @@ namespace deflect { +namespace server +{ /** * Interface for classes to register as receivers for events. */ @@ -55,10 +57,12 @@ class DEFLECT_API EventReceiver : public QObject Q_OBJECT public: - virtual ~EventReceiver() {} + virtual ~EventReceiver() = default; + public slots: virtual void processEvent(deflect::Event event) = 0; }; } +} #endif diff --git a/deflect/Frame.cpp b/deflect/server/Frame.cpp similarity index 99% rename from deflect/Frame.cpp rename to deflect/server/Frame.cpp index a50a3d0..49139a0 100644 --- a/deflect/Frame.cpp +++ b/deflect/server/Frame.cpp @@ -41,6 +41,8 @@ namespace deflect { +namespace server +{ QSize Frame::computeDimensions() const { QSize size(0, 0); @@ -72,3 +74,4 @@ RowOrder Frame::determineRowOrder() const return frameRowOrder; } } +} diff --git a/deflect/Frame.h b/deflect/server/Frame.h similarity index 97% rename from deflect/Frame.h rename to deflect/server/Frame.h index 9d6ca22..5f69539 100644 --- a/deflect/Frame.h +++ b/deflect/server/Frame.h @@ -37,8 +37,8 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_FRAME_H -#define DEFLECT_FRAME_H +#ifndef DEFLECT_SERVER_FRAME_H +#define DEFLECT_SERVER_FRAME_H #include #include @@ -49,6 +49,8 @@ namespace deflect { +namespace server +{ /** * A frame for a PixelStream. */ @@ -71,5 +73,6 @@ class Frame DEFLECT_API RowOrder determineRowOrder() const; }; } +} #endif diff --git a/deflect/FrameDispatcher.cpp b/deflect/server/FrameDispatcher.cpp similarity index 99% rename from deflect/FrameDispatcher.cpp rename to deflect/server/FrameDispatcher.cpp index 691dfde..f8f3e10 100644 --- a/deflect/FrameDispatcher.cpp +++ b/deflect/server/FrameDispatcher.cpp @@ -47,6 +47,8 @@ namespace deflect { +namespace server +{ class FrameDispatcher::Impl { public: @@ -191,3 +193,4 @@ void FrameDispatcher::deleteStream(const QString uri) } } } +} diff --git a/deflect/FrameDispatcher.h b/deflect/server/FrameDispatcher.h similarity index 97% rename from deflect/FrameDispatcher.h rename to deflect/server/FrameDispatcher.h index 67266f9..fdc82a8 100644 --- a/deflect/FrameDispatcher.h +++ b/deflect/server/FrameDispatcher.h @@ -37,8 +37,8 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_FRAMEDISPATCHER_H -#define DEFLECT_FRAMEDISPATCHER_H +#ifndef DEFLECT_SERVER_FRAMEDISPATCHER_H +#define DEFLECT_SERVER_FRAMEDISPATCHER_H #include #include @@ -49,6 +49,8 @@ namespace deflect { +namespace server +{ /** * Gather segments from multiple sources and dispatch full frames. */ @@ -162,12 +164,13 @@ public slots: * * @param frame The latest frame available for a stream */ - void sendFrame(deflect::FramePtr frame); + void sendFrame(deflect::server::FramePtr frame); private: class Impl; std::unique_ptr _impl; }; } +} #endif diff --git a/deflect/ImageJpegDecompressor.cpp b/deflect/server/ImageJpegDecompressor.cpp similarity index 99% rename from deflect/ImageJpegDecompressor.cpp rename to deflect/server/ImageJpegDecompressor.cpp index 940dbec..f025476 100644 --- a/deflect/ImageJpegDecompressor.cpp +++ b/deflect/server/ImageJpegDecompressor.cpp @@ -62,6 +62,8 @@ deflect::ChromaSubsampling _getSubsamp(const int tjJpegSubsamp) namespace deflect { +namespace server +{ ImageJpegDecompressor::ImageJpegDecompressor() : _tjHandle(tjInitDecompress()) { @@ -141,3 +143,4 @@ ImageJpegDecompressor::YUVData ImageJpegDecompressor::decompressToYUV( #endif } +} diff --git a/deflect/ImageJpegDecompressor.h b/deflect/server/ImageJpegDecompressor.h similarity index 97% rename from deflect/ImageJpegDecompressor.h rename to deflect/server/ImageJpegDecompressor.h index 13db414..7a728e4 100644 --- a/deflect/ImageJpegDecompressor.h +++ b/deflect/server/ImageJpegDecompressor.h @@ -37,8 +37,8 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_IMAGEJPEGDECOMPRESSOR_H -#define DEFLECT_IMAGEJPEGDECOMPRESSOR_H +#ifndef DEFLECT_SERVER_IMAGEJPEGDECOMPRESSOR_H +#define DEFLECT_SERVER_IMAGEJPEGDECOMPRESSOR_H #include #include @@ -50,6 +50,8 @@ namespace deflect { +namespace server +{ /** * JPEG header information. */ @@ -107,5 +109,6 @@ class ImageJpegDecompressor tjhandle _tjHandle; }; } +} #endif diff --git a/deflect/ReceiveBuffer.cpp b/deflect/server/ReceiveBuffer.cpp similarity index 99% rename from deflect/ReceiveBuffer.cpp rename to deflect/server/ReceiveBuffer.cpp index e004961..3b81aea 100644 --- a/deflect/ReceiveBuffer.cpp +++ b/deflect/server/ReceiveBuffer.cpp @@ -40,6 +40,7 @@ #include "ReceiveBuffer.h" #include + namespace { const size_t MAX_QUEUE_SIZE = 150; // stream blocked for ~5 seconds at 30Hz @@ -47,6 +48,8 @@ const size_t MAX_QUEUE_SIZE = 150; // stream blocked for ~5 seconds at 30Hz namespace deflect { +namespace server +{ bool ReceiveBuffer::addSource(const size_t sourceIndex) { assert(!_sourceBuffers.count(sourceIndex)); @@ -134,3 +137,4 @@ bool ReceiveBuffer::isAllowedToSend() const return _allowedToSend; } } +} diff --git a/deflect/ReceiveBuffer.h b/deflect/server/ReceiveBuffer.h similarity index 97% rename from deflect/ReceiveBuffer.h rename to deflect/server/ReceiveBuffer.h index bfd483f..3635d9b 100644 --- a/deflect/ReceiveBuffer.h +++ b/deflect/server/ReceiveBuffer.h @@ -37,12 +37,12 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_RECEIVEBUFFER_H -#define DEFLECT_RECEIVEBUFFER_H +#ifndef DEFLECT_SERVER_RECEIVEBUFFER_H +#define DEFLECT_SERVER_RECEIVEBUFFER_H #include -#include #include +#include #include #include @@ -52,6 +52,8 @@ namespace deflect { +namespace server +{ /** * Buffer Segments from (multiple) sources. * @@ -117,5 +119,6 @@ class ReceiveBuffer bool _allowedToSend = false; }; } +} #endif diff --git a/deflect/SegmentDecoder.cpp b/deflect/server/SegmentDecoder.cpp similarity index 99% rename from deflect/SegmentDecoder.cpp rename to deflect/server/SegmentDecoder.cpp index 7b5c3fe..6eac463 100644 --- a/deflect/SegmentDecoder.cpp +++ b/deflect/server/SegmentDecoder.cpp @@ -40,15 +40,17 @@ #include "SegmentDecoder.h" #include "ImageJpegDecompressor.h" -#include "Segment.h" - -#include +#include "deflect/Segment.h" #include #include +#include + namespace deflect { +namespace server +{ class SegmentDecoder::Impl { public: @@ -198,3 +200,4 @@ bool SegmentDecoder::isRunning() const return _impl->decodingFuture.isRunning(); } } +} diff --git a/deflect/SegmentDecoder.h b/deflect/server/SegmentDecoder.h similarity index 98% rename from deflect/SegmentDecoder.h rename to deflect/server/SegmentDecoder.h index afde1ae..9914b27 100644 --- a/deflect/SegmentDecoder.h +++ b/deflect/server/SegmentDecoder.h @@ -37,8 +37,8 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_SEGMENTDECODER_H -#define DEFLECT_SEGMENTDECODER_H +#ifndef DEFLECT_SERVER_SEGMENTDECODER_H +#define DEFLECT_SERVER_SEGMENTDECODER_H #include #include @@ -46,6 +46,8 @@ namespace deflect { +namespace server +{ /** * Decode a Segment's image asynchronously. */ @@ -117,5 +119,6 @@ class SegmentDecoder std::unique_ptr _impl; }; } +} #endif diff --git a/deflect/Server.cpp b/deflect/server/Server.cpp similarity index 99% rename from deflect/Server.cpp rename to deflect/server/Server.cpp index 2a1630e..d8a6e0f 100644 --- a/deflect/Server.cpp +++ b/deflect/server/Server.cpp @@ -41,15 +41,18 @@ #include "Server.h" #include "FrameDispatcher.h" -#include "NetworkProtocol.h" #include "ServerWorker.h" +#include "deflect/NetworkProtocol.h" #include #include + #include namespace deflect { +namespace server +{ const int Server::defaultPortNumber = DEFAULT_PORT_NUMBER; class Server::Impl @@ -157,3 +160,4 @@ void Server::incomingConnection(const qintptr socketHandle) workerThread->start(); } } +} diff --git a/deflect/Server.h b/deflect/server/Server.h similarity index 95% rename from deflect/Server.h rename to deflect/server/Server.h index 960a94e..c2b02ed 100644 --- a/deflect/Server.h +++ b/deflect/server/Server.h @@ -38,8 +38,8 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_SERVER_H -#define DEFLECT_SERVER_H +#ifndef DEFLECT_SERVER_SERVER_H +#define DEFLECT_SERVER_SERVER_H #include #include @@ -49,6 +49,8 @@ namespace deflect { +namespace server +{ /** * Listen to incoming connections from multiple Stream clients. * @@ -130,7 +132,7 @@ public slots: * * @param frame The latest frame that was received for a stream. */ - void receivedFrame(deflect::FramePtr frame); + void receivedFrame(deflect::server::FramePtr frame); /** * Emitted when a remote client wants to register for receiving events. @@ -141,8 +143,8 @@ public slots: * @param success the promise that must receive the success of the operation */ void registerToEvents(QString uri, bool exclusive, - deflect::EventReceiver* receiver, - deflect::BoolPromisePtr success); + deflect::server::EventReceiver* receiver, + deflect::server::BoolPromisePtr success); /** * Emitted when a remote client sends size hints for displaying the stream. @@ -171,5 +173,6 @@ public slots: void _closePixelStream(QString uri); }; } +} #endif diff --git a/deflect/ServerWorker.cpp b/deflect/server/ServerWorker.cpp similarity index 99% rename from deflect/ServerWorker.cpp rename to deflect/server/ServerWorker.cpp index f30b251..f00115f 100644 --- a/deflect/ServerWorker.cpp +++ b/deflect/server/ServerWorker.cpp @@ -40,13 +40,13 @@ #include "ServerWorker.h" -#include "NetworkProtocol.h" - -#include -#include +#include "deflect/NetworkProtocol.h" #include +#include +#include + namespace { const int RECEIVE_TIMEOUT_MS = 3000; @@ -54,6 +54,8 @@ const int RECEIVE_TIMEOUT_MS = 3000; namespace deflect { +namespace server +{ ServerWorker::ServerWorker(const int socketDescriptor) : _tcpSocket{new QTcpSocket(this)} // Ensure that _tcpSocket parent is // *this* so it gets moved to thread @@ -377,3 +379,4 @@ bool ServerWorker::_isConnected() const return _tcpSocket->state() == QTcpSocket::ConnectedState; } } +} diff --git a/deflect/ServerWorker.h b/deflect/server/ServerWorker.h similarity index 94% rename from deflect/ServerWorker.h rename to deflect/server/ServerWorker.h index 899bb98..da4354d 100644 --- a/deflect/ServerWorker.h +++ b/deflect/server/ServerWorker.h @@ -38,14 +38,14 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_SERVER_WORKER_H -#define DEFLECT_SERVER_WORKER_H +#ifndef DEFLECT_SERVER_SERVERWORKER_H +#define DEFLECT_SERVER_SERVERWORKER_H #include -#include #include #include #include +#include #include #include @@ -53,6 +53,8 @@ namespace deflect { +namespace server +{ class ServerWorker : public EventReceiver { Q_OBJECT @@ -79,8 +81,8 @@ public slots: void receivedFrameFinished(QString uri, size_t sourceIndex); void registerToEvents(QString uri, bool exclusive, - deflect::EventReceiver* receiver, - deflect::BoolPromisePtr success); + deflect::server::EventReceiver* receiver, + deflect::server::BoolPromisePtr success); void receivedSizeHints(QString uri, deflect::SizeHints hints); @@ -126,5 +128,6 @@ private slots: bool _isConnected() const; }; } +} #endif diff --git a/deflect/SourceBuffer.cpp b/deflect/server/SourceBuffer.cpp similarity index 99% rename from deflect/SourceBuffer.cpp rename to deflect/server/SourceBuffer.cpp index 0c9edea..065de3e 100644 --- a/deflect/SourceBuffer.cpp +++ b/deflect/server/SourceBuffer.cpp @@ -43,6 +43,8 @@ namespace deflect { +namespace server +{ SourceBuffer::SourceBuffer() { _segments.push(Segments()); @@ -84,3 +86,4 @@ size_t SourceBuffer::getQueueSize() const return _segments.size(); } } +} diff --git a/deflect/SourceBuffer.h b/deflect/server/SourceBuffer.h similarity index 97% rename from deflect/SourceBuffer.h rename to deflect/server/SourceBuffer.h index c7ee888..3946f34 100644 --- a/deflect/SourceBuffer.h +++ b/deflect/server/SourceBuffer.h @@ -37,8 +37,8 @@ /* or implied, of Ecole polytechnique federale de Lausanne. */ /*********************************************************************/ -#ifndef DEFLECT_SOURCEBUFFER_H -#define DEFLECT_SOURCEBUFFER_H +#ifndef DEFLECT_SERVER_SOURCEBUFFER_H +#define DEFLECT_SERVER_SOURCEBUFFER_H #include #include @@ -49,6 +49,8 @@ namespace deflect { +namespace server +{ using FrameIndex = unsigned int; /** @@ -89,5 +91,6 @@ class SourceBuffer FrameIndex _backFrameIndex = 0u; }; } +} #endif diff --git a/deflect/types.h b/deflect/types.h index 8248812..296cf70 100644 --- a/deflect/types.h +++ b/deflect/types.h @@ -103,24 +103,29 @@ std::future make_exception_future(Exception&& e) return make_exception_future(std::make_exception_ptr(std::move(e))); } -class EventReceiver; -class Frame; -class FrameDispatcher; class ImageSegmenter; -class SegmentDecoder; -class Server; +class MessageHeader; class Stream; struct Event; struct ImageWrapper; -struct MessageHeader; struct Segment; struct SegmentParameters; struct SizeHints; +using Segments = std::vector; + +namespace server +{ +class EventReceiver; +class Frame; +class FrameDispatcher; +class SegmentDecoder; +class Server; + using BoolPromisePtr = std::shared_ptr>; using FramePtr = std::shared_ptr; -using Segments = std::vector; +} namespace qt { diff --git a/doc/Changelog.md b/doc/Changelog.md index a52fa66..8e5ecfe 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -6,7 +6,8 @@ Changelog {#Changelog} ### 1.0.0 (git master) * [194](https://github.com/BlueBrain/Deflect/pull/194): Reset API versionning to 1.0, remove deprecated functions (Stream::asyncSend, - ImageWrapper::swapYAxis). + ImageWrapper::swapYAxis). Moved all server-specific classes to a separate + namespace. ## Deflect 0.14 @@ -131,7 +132,7 @@ Changelog {#Changelog} are available in Qml from a "deflectgestures" context property. * [119](https://github.com/BlueBrain/Deflect/pull/119): Added deflect::Stream::sendData() to allow sending user-defined information - to the deflect::Server. + to the deflect Server. * [118](https://github.com/BlueBrain/Deflect/pull/118): New "pan" event for multi-finger pan gestures. * [117](https://github.com/BlueBrain/Deflect/pull/117): diff --git a/tests/cpp/CMakeLists.txt b/tests/cpp/CMakeLists.txt index 810fbba..b1b7173 100644 --- a/tests/cpp/CMakeLists.txt +++ b/tests/cpp/CMakeLists.txt @@ -1,11 +1,11 @@ -# Copyright (c) 2013-2015, EPFL/Blue Brain Project -# Daniel Nachbaur -# Raphael Dumusc +# Copyright (c) 2013-2018, EPFL/Blue Brain Project +# Daniel Nachbaur +# Raphael Dumusc # # Change this number when adding tests to force a CMake run: 0 -set(TEST_LIBRARIES Deflect DeflectMock ${Boost_LIBRARIES} Qt5::Widgets) +set(TEST_LIBRARIES DeflectServer DeflectMock ${Boost_LIBRARIES} Qt5::Widgets) add_definitions(-DBOOST_PROGRAM_OPTIONS_DYN_LINK) if(NOT DEFLECT_USE_LIBJPEGTURBO) set(EXCLUDE_FROM_TESTS SegmentDecoderTests.cpp) diff --git a/tests/cpp/FrameDispatcherTests.cpp b/tests/cpp/FrameDispatcherTests.cpp index 5d40351..f63d6ee 100644 --- a/tests/cpp/FrameDispatcherTests.cpp +++ b/tests/cpp/FrameDispatcherTests.cpp @@ -44,7 +44,7 @@ namespace ut = boost::unit_test; #include "FrameUtils.h" -#include +#include namespace { @@ -53,17 +53,20 @@ const char* streamId = "test"; struct Fixture { - deflect::FrameDispatcher dispatcher; - deflect::FramePtr receivedFrame; + deflect::server::FrameDispatcher dispatcher; + deflect::server::FramePtr receivedFrame; Fixture() { - QObject::connect(&dispatcher, &deflect::FrameDispatcher::sendFrame, - [&](deflect::FramePtr f) { receivedFrame = f; }); + QObject::connect(&dispatcher, + &deflect::server::FrameDispatcher::sendFrame, + [&](deflect::server::FramePtr f) { + receivedFrame = f; + }); dispatcher.addSource(streamId, 0); } - void dispatch(const deflect::Frame& frame) + void dispatch(const deflect::server::Frame& frame) { for (auto& segment : frame.segments) dispatcher.processSegment(streamId, 0, segment); diff --git a/tests/cpp/ReceiveBufferTests.cpp b/tests/cpp/ReceiveBufferTests.cpp index e09a557..42d087f 100644 --- a/tests/cpp/ReceiveBufferTests.cpp +++ b/tests/cpp/ReceiveBufferTests.cpp @@ -41,9 +41,9 @@ #include namespace ut = boost::unit_test; -#include -#include #include +#include +#include inline std::ostream& operator<<(std::ostream& str, const QSize& s) { @@ -53,7 +53,7 @@ inline std::ostream& operator<<(std::ostream& str, const QSize& s) BOOST_AUTO_TEST_CASE(TestAddAndRemoveSources) { - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; BOOST_REQUIRE_EQUAL(buffer.getSourceCount(), 0); @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(TestAddAndRemoveSources) BOOST_AUTO_TEST_CASE(TestAllowedToSend) { - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; BOOST_CHECK(!buffer.isAllowedToSend()); @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(TestCompleteAFrame) { const size_t sourceIndex = 46; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex); deflect::Segment segment; @@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(TestCompleteAFrame) BOOST_CHECK_EQUAL(segments.size(), 1); BOOST_CHECK(!buffer.hasCompleteFrame()); - deflect::Frame frame; + deflect::server::Frame frame; frame.segments = segments; const QSize frameSize = frame.computeDimensions(); BOOST_CHECK_EQUAL(frameSize.width(), segment.parameters.width); @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameSingleSource) { const size_t sourceIndex = 46; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex); deflect::Segments testSegments = generateTestSegments(); @@ -181,7 +181,7 @@ BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameSingleSource) BOOST_CHECK_EQUAL(segments.size(), 4); BOOST_CHECK(!buffer.hasCompleteFrame()); - deflect::Frame frame; + deflect::server::Frame frame; frame.segments = segments; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 768)); } @@ -192,7 +192,7 @@ BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameMultipleSources) const size_t sourceIndex2 = 819; const size_t sourceIndex3 = 11; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); buffer.addSource(sourceIndex3); @@ -218,7 +218,7 @@ BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameMultipleSources) BOOST_CHECK_EQUAL(segments.size(), 4); BOOST_CHECK(!buffer.hasCompleteFrame()); - deflect::Frame frame; + deflect::server::Frame frame; frame.segments = segments; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 768)); } @@ -228,7 +228,7 @@ BOOST_AUTO_TEST_CASE(TestRemoveSourceWhileStreaming) const size_t sourceIndex1 = 46; const size_t sourceIndex2 = 819; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(TestRemoveSourceWhileStreaming) BOOST_CHECK_EQUAL(segments.size(), 2); BOOST_CHECK(!buffer.hasCompleteFrame()); - deflect::Frame frame; + deflect::server::Frame frame; frame.segments = segments; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 256)); } @@ -273,7 +273,7 @@ BOOST_AUTO_TEST_CASE(TestOneOfTwoSourceStopsSendingSegments) const size_t sourceIndex1 = 46; const size_t sourceIndex2 = 819; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); @@ -310,14 +310,14 @@ BOOST_AUTO_TEST_CASE(TestOneOfTwoSourceStopsSendingSegments) std::runtime_error); } -void _insert(deflect::ReceiveBuffer& buffer, const size_t sourceIndex, +void _insert(deflect::server::ReceiveBuffer& buffer, const size_t sourceIndex, const deflect::Segments& frame) { for (const auto& segment : frame) buffer.insert(segment, sourceIndex); } -void _testStereoBuffer(deflect::ReceiveBuffer& buffer) +void _testStereoBuffer(deflect::server::ReceiveBuffer& buffer) { const auto segments = buffer.popFrame(); BOOST_CHECK_EQUAL(segments.size(), 8); @@ -343,7 +343,7 @@ void _testStereoBuffer(deflect::ReceiveBuffer& buffer) BOOST_CHECK_EQUAL(left, 4); BOOST_CHECK_EQUAL(right, 4); - deflect::Frame frame; + deflect::server::Frame frame; frame.segments = segments; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 768)); } @@ -352,7 +352,7 @@ BOOST_AUTO_TEST_CASE(TestStereoOneSource) { const size_t sourceIndex = 46; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex); auto leftSegments = generateTestSegments(deflect::View::left_eye); @@ -374,7 +374,7 @@ BOOST_AUTO_TEST_CASE(TestStereoTwoSourcesScreenSpaceSplit) const size_t sourceIndex1 = 46; const size_t sourceIndex2 = 819; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); @@ -406,7 +406,7 @@ BOOST_AUTO_TEST_CASE(TestStereoTwoSourcesStereoSplit) const size_t sourceIndex1 = 46; const size_t sourceIndex2 = 819; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); @@ -434,7 +434,7 @@ BOOST_AUTO_TEST_CASE(TestStereoFourSourcesScreenSpaceAndStereoSplit) const size_t sourceIndex3 = 489; const size_t sourceIndex4 = 113; - deflect::ReceiveBuffer buffer; + deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); buffer.addSource(sourceIndex3); diff --git a/tests/cpp/SegmentDecoderTests.cpp b/tests/cpp/SegmentDecoderTests.cpp index fb6adbd..7f0a05b 100644 --- a/tests/cpp/SegmentDecoderTests.cpp +++ b/tests/cpp/SegmentDecoderTests.cpp @@ -42,11 +42,11 @@ namespace ut = boost::unit_test; #include -#include #include #include #include -#include +#include +#include #include #include // std::round @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(testImageCompressionAndDecompression) BOOST_REQUIRE(jpegData.size() != (int)data.size()); // Decompress image - deflect::ImageJpegDecompressor decompressor; + deflect::server::ImageJpegDecompressor decompressor; QByteArray decodedData = decompressor.decompress(jpegData); // Check decoded image in format RGBA @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(testImageCompressionAndDecompression) QByteArray decodeToYUVWithDecompressor( const QByteArray& jpegData, const deflect::ChromaSubsampling expected) { - deflect::ImageJpegDecompressor decompressor; + deflect::server::ImageJpegDecompressor decompressor; const auto yuvData = decompressor.decompressToYUV(jpegData); BOOST_CHECK_EQUAL(yuvData.second, expected); return yuvData.first; @@ -152,7 +152,7 @@ QByteArray decodeToYUVWithSegmentDecoder( segment.imageData = QByteArray::fromRawData(jpegData.data(), jpegData.size()); - deflect::SegmentDecoder decoder; + deflect::server::SegmentDecoder decoder; BOOST_CHECK_EQUAL(decoder.decodeType(segment), expected); decoder.decodeToYUV(segment); @@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(testImageSegmentationWithCompressionAndDecompression) BOOST_REQUIRE(segment.imageData.size() != (int)data.size()); // Decompress image - deflect::SegmentDecoder decoder; + deflect::server::SegmentDecoder decoder; decoder.startDecoding(segment); decoder.waitDecoding(); @@ -279,7 +279,7 @@ BOOST_AUTO_TEST_CASE(testImageSegmentationWithCompressionAndDecompression) BOOST_AUTO_TEST_CASE(testDecompressionOfInvalidData) { const QByteArray invalidJpegData{"notjpeg923%^#8"}; - deflect::ImageJpegDecompressor decompressor; + deflect::server::ImageJpegDecompressor decompressor; BOOST_CHECK_THROW(decompressor.decompress(invalidJpegData), std::runtime_error); @@ -288,7 +288,7 @@ BOOST_AUTO_TEST_CASE(testDecompressionOfInvalidData) segment.parameters.height = 32; segment.imageData = invalidJpegData; - deflect::SegmentDecoder decoder; + deflect::server::SegmentDecoder decoder; BOOST_CHECK_THROW(decoder.decode(segment), std::runtime_error); BOOST_CHECK_NO_THROW(decoder.startDecoding(segment)); diff --git a/tests/cpp/ServerTests.cpp b/tests/cpp/ServerTests.cpp index b3dbdab..fb09456 100644 --- a/tests/cpp/ServerTests.cpp +++ b/tests/cpp/ServerTests.cpp @@ -45,8 +45,8 @@ namespace ut = boost::unit_test; #include "MinimalGlobalQtApp.h" #include "boost_test_thread_safe.h" -#include #include +#include #include #include @@ -89,13 +89,15 @@ BOOST_AUTO_TEST_CASE(sizeHintsReceivedByServer) BOOST_AUTO_TEST_CASE(registerForEventReceivedByServer) { bool received = false; - setRegisterToEventsCallback([&](const QString id, const bool exclusive, - deflect::EventReceiver* eventReceiver) { - SAFE_BOOST_CHECK_EQUAL(id.toStdString(), testStreamId.toStdString()); - SAFE_BOOST_CHECK(exclusive); - SAFE_BOOST_CHECK(eventReceiver); - received = true; - }); + setRegisterToEventsCallback( + [&](const QString id, const bool exclusive, + deflect::server::EventReceiver* eventReceiver) { + SAFE_BOOST_CHECK_EQUAL(id.toStdString(), + testStreamId.toStdString()); + SAFE_BOOST_CHECK(exclusive); + SAFE_BOOST_CHECK(eventReceiver); + received = true; + }); { deflect::Stream stream(testStreamId.toStdString(), "localhost", @@ -136,7 +138,7 @@ BOOST_AUTO_TEST_CASE(dataReceivedByServer) BOOST_AUTO_TEST_CASE(oneObserverAndOneStream) { - setFrameReceivedCallback([&](deflect::FramePtr frame) { + setFrameReceivedCallback([&](deflect::server::FramePtr frame) { SAFE_BOOST_CHECK_EQUAL(frame->segments.size(), 1); SAFE_BOOST_CHECK_EQUAL(frame->uri.toStdString(), testStreamId.toStdString()); @@ -333,7 +335,7 @@ BOOST_AUTO_TEST_CASE(threadedSmallSegmentStream) std::ceil((float)width / segmentSize) * std::ceil((float)height / segmentSize)); - setFrameReceivedCallback([&](deflect::FramePtr frame) { + setFrameReceivedCallback([&](deflect::server::FramePtr frame) { SAFE_BOOST_CHECK_EQUAL(frame->segments.size(), numSegments); SAFE_BOOST_CHECK_EQUAL(frame->uri.toStdString(), testStreamId.toStdString()); diff --git a/tests/cpp/perf/streamTests.cpp b/tests/cpp/perf/streamTests.cpp index 41846d7..3d2ca14 100644 --- a/tests/cpp/perf/streamTests.cpp +++ b/tests/cpp/perf/streamTests.cpp @@ -44,8 +44,8 @@ namespace ut = boost::unit_test; #include "MinimalGlobalQtApp.h" #include "Timer.h" -#include #include +#include #include @@ -140,7 +140,7 @@ class DCThread : public QThread BOOST_AUTO_TEST_CASE(testSocketConnection) { - deflect::Server server; + deflect::server::Server server; #ifdef NTHREADS QThreadPool::globalInstance()->setMaxThreadCount(NTHREADS); #endif diff --git a/tests/mock/CMakeLists.txt b/tests/mock/CMakeLists.txt index 828c01a..45cae91 100644 --- a/tests/mock/CMakeLists.txt +++ b/tests/mock/CMakeLists.txt @@ -1,7 +1,7 @@ -# Copyright (c) 2013-2017, EPFL/Blue Brain Project -# Daniel Nachbaur -# Raphael Dumusc +# Copyright (c) 2013-2018, EPFL/Blue Brain Project +# Daniel Nachbaur +# Raphael Dumusc # # Generates a mock library used by the cpp unit tests. @@ -26,6 +26,7 @@ set(DEFLECTMOCK_LINK_LIBRARIES Deflect ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} set(DEFLECTMOCK_INCLUDE_NAME deflect/mock) set(DEFLECTMOCK_OMIT_LIBRARY_HEADER ON) +set(DEFLECTMOCK_OMIT_VERSION_HEADERS ON) set(DEFLECTMOCK_OMIT_CHECK_TARGETS ON) set(DEFLECTMOCK_OMIT_INSTALL ON) common_library(DeflectMock) diff --git a/tests/mock/DeflectServer.cpp b/tests/mock/DeflectServer.cpp index 3b7ce76..fa37a1e 100644 --- a/tests/mock/DeflectServer.cpp +++ b/tests/mock/DeflectServer.cpp @@ -43,13 +43,13 @@ DeflectServer::DeflectServer() { - _server = new deflect::Server(0 /* OS-chosen port */); + _server = new deflect::server::Server(0 /* OS-chosen port */); _server->moveToThread(&_thread); _thread.connect(&_thread, &QThread::finished, _server, - &deflect::Server::deleteLater); + &deflect::server::Server::deleteLater); _thread.start(); - _server->connect(_server, &deflect::Server::pixelStreamOpened, + _server->connect(_server, &deflect::server::Server::pixelStreamOpened, [&](const QString) { ++_openedStreams; _mutex.lock(); @@ -58,7 +58,7 @@ DeflectServer::DeflectServer() _mutex.unlock(); }); - _server->connect(_server, &deflect::Server::pixelStreamClosed, + _server->connect(_server, &deflect::server::Server::pixelStreamClosed, [&](const QString) { --_openedStreams; _mutex.lock(); @@ -67,7 +67,7 @@ DeflectServer::DeflectServer() _mutex.unlock(); }); - _server->connect(_server, &deflect::Server::receivedSizeHints, + _server->connect(_server, &deflect::server::Server::receivedSizeHints, [&](const QString id, const deflect::SizeHints hints) { if (_sizeHintsCallback) _sizeHintsCallback(id, hints); @@ -77,7 +77,7 @@ DeflectServer::DeflectServer() _mutex.unlock(); }); - _server->connect(_server, &deflect::Server::receivedData, + _server->connect(_server, &deflect::server::Server::receivedData, [&](const QString id, QByteArray data) { if (_dataReceivedCallback) _dataReceivedCallback(id, data); @@ -87,8 +87,8 @@ DeflectServer::DeflectServer() _mutex.unlock(); }); - _server->connect(_server, &deflect::Server::receivedFrame, - [&](deflect::FramePtr frame) { + _server->connect(_server, &deflect::server::Server::receivedFrame, + [&](deflect::server::FramePtr frame) { if (_frameReceivedCallback) _frameReceivedCallback(frame); ++_receivedFrames; @@ -98,10 +98,10 @@ DeflectServer::DeflectServer() _mutex.unlock(); }); - _server->connect(_server, &deflect::Server::registerToEvents, + _server->connect(_server, &deflect::server::Server::registerToEvents, [&](const QString id, const bool exclusive, - deflect::EventReceiver* evtReceiver, - deflect::BoolPromisePtr success) { + deflect::server::EventReceiver* evtReceiver, + deflect::server::BoolPromisePtr success) { if (_registerToEventsCallback) _registerToEventsCallback(id, exclusive, diff --git a/tests/mock/DeflectServer.h b/tests/mock/DeflectServer.h index 62ef3ab..55d114e 100644 --- a/tests/mock/DeflectServer.h +++ b/tests/mock/DeflectServer.h @@ -48,8 +48,8 @@ typedef __int32 int32_t; #include #include -#include -#include +#include +#include class DeflectServer { @@ -71,7 +71,8 @@ class DeflectServer } using RegisterToEventsCallback = - std::function; + std::function; void setRegisterToEventsCallback(const RegisterToEventsCallback& callback) { _registerToEventsCallback = callback; @@ -83,7 +84,8 @@ class DeflectServer _dataReceivedCallback = callback; } - using FrameReceivedCallback = std::function; + using FrameReceivedCallback = + std::function; void setFrameReceivedCallback(const FrameReceivedCallback& callback) { _frameReceivedCallback = callback; @@ -93,7 +95,7 @@ class DeflectServer private: QThread _thread; - deflect::Server* _server; + deflect::server::Server* _server; bool _receivedState{false}; QWaitCondition _received; @@ -107,7 +109,7 @@ class DeflectServer DataReceivedCallback _dataReceivedCallback; FrameReceivedCallback _frameReceivedCallback; - deflect::EventReceiver* _eventReceiver{nullptr}; + deflect::server::EventReceiver* _eventReceiver{nullptr}; }; #endif diff --git a/tests/mock/FrameUtils.h b/tests/mock/FrameUtils.h index 36a51d6..9bd93f8 100644 --- a/tests/mock/FrameUtils.h +++ b/tests/mock/FrameUtils.h @@ -37,11 +37,12 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#include +#include #include // std::ceil -inline deflect::Frame makeTestFrame(int width, int height, int segmentSize) +inline deflect::server::Frame makeTestFrame(int width, int height, + int segmentSize) { const int numSegmentsX = std::ceil((float)width / (float)segmentSize); const int numSegmentsY = std::ceil((float)height / (float)segmentSize); @@ -51,7 +52,7 @@ inline deflect::Frame makeTestFrame(int width, int height, int segmentSize) const int lastSegmentHeight = (height % segmentSize) > 0 ? (height % segmentSize) : segmentSize; - deflect::Frame frame; + deflect::server::Frame frame; for (int y = 0; y < numSegmentsY; ++y) { for (int x = 0; x < numSegmentsX; ++x) @@ -71,7 +72,8 @@ inline deflect::Frame makeTestFrame(int width, int height, int segmentSize) return frame; } -inline void compare(const deflect::Frame& frame1, const deflect::Frame& frame2) +inline void compare(const deflect::server::Frame& frame1, + const deflect::server::Frame& frame2) { BOOST_REQUIRE_EQUAL(frame1.segments.size(), frame2.segments.size()); diff --git a/tests/mock/MockServer.h b/tests/mock/MockServer.h index 24e61ca..1ca2ee6 100644 --- a/tests/mock/MockServer.h +++ b/tests/mock/MockServer.h @@ -44,7 +44,7 @@ typedef __int32 int32_t; #endif -#include +#include #include From 2fe474831d20688e4df135b68ff34c61b2deb544 Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Wed, 2 May 2018 16:11:29 +0200 Subject: [PATCH 3/4] New server::Tile class in Frame replaces Segment, now private --- deflect/CMakeLists.txt | 4 +- deflect/ImageJpegCompressor.h | 2 +- deflect/ImageSegmenter.cpp | 6 +- deflect/ImageWrapper.h | 2 +- deflect/MetaTypeRegistration.cpp | 3 + deflect/Segment.h | 2 +- deflect/SegmentParameters.h | 17 +- deflect/qt/CMakeLists.txt | 1 + deflect/qt/types.h | 55 ++++ deflect/server/CMakeLists.txt | 6 +- deflect/server/Frame.cpp | 22 +- deflect/server/Frame.h | 18 +- deflect/server/FrameDispatcher.cpp | 21 +- deflect/server/FrameDispatcher.h | 23 +- deflect/server/ImageJpegDecompressor.h | 2 +- deflect/server/ReceiveBuffer.cpp | 14 +- deflect/server/ReceiveBuffer.h | 26 +- deflect/server/Server.cpp | 4 +- deflect/server/Server.h | 2 +- deflect/server/ServerWorker.cpp | 20 +- deflect/server/ServerWorker.h | 7 +- deflect/server/SourceBuffer.cpp | 22 +- deflect/server/SourceBuffer.h | 24 +- deflect/server/Tile.h | 85 +++++++ .../{SegmentDecoder.cpp => TileDecoder.cpp} | 82 +++--- .../{SegmentDecoder.h => TileDecoder.h} | 50 ++-- deflect/server/types.h | 63 +++++ deflect/types.h | 31 +-- doc/Changelog.md | 2 +- tests/cpp/CMakeLists.txt | 2 +- tests/cpp/FrameDispatcherTests.cpp | 20 +- tests/cpp/FrameTests.cpp | 12 +- tests/cpp/ReceiveBufferTests.cpp | 237 +++++++++--------- tests/cpp/ServerTests.cpp | 4 +- ...tDecoderTests.cpp => TileDecoderTests.cpp} | 86 ++++--- tests/mock/CMakeLists.txt | 4 +- tests/mock/FrameUtils.h | 66 +++-- 37 files changed, 612 insertions(+), 435 deletions(-) create mode 100644 deflect/qt/types.h create mode 100644 deflect/server/Tile.h rename deflect/server/{SegmentDecoder.cpp => TileDecoder.cpp} (69%) rename deflect/server/{SegmentDecoder.h => TileDecoder.h} (74%) create mode 100644 deflect/server/types.h rename tests/cpp/{SegmentDecoderTests.cpp => TileDecoderTests.cpp} (82%) diff --git a/deflect/CMakeLists.txt b/deflect/CMakeLists.txt index ffc6142..8f39c0a 100644 --- a/deflect/CMakeLists.txt +++ b/deflect/CMakeLists.txt @@ -7,8 +7,6 @@ set(DEFLECT_PUBLIC_HEADERS Event.h ImageWrapper.h Observer.h - Segment.h - SegmentParameters.h SizeHints.h Stream.h types.h @@ -21,6 +19,8 @@ set(DEFLECT_HEADERS MessageHeader.h MTQueue.h NetworkProtocol.h + Segment.h + SegmentParameters.h Socket.h StreamPrivate.h TaskBuilder.h diff --git a/deflect/ImageJpegCompressor.h b/deflect/ImageJpegCompressor.h index 9c07e63..5ba65b8 100644 --- a/deflect/ImageJpegCompressor.h +++ b/deflect/ImageJpegCompressor.h @@ -51,7 +51,7 @@ namespace deflect { /** - * Perform JPEG compression for a PixelStreamSegment + * Perform JPEG compression for a region of an image. */ class ImageJpegCompressor { diff --git a/deflect/ImageSegmenter.cpp b/deflect/ImageSegmenter.cpp index a7c959d..b54a2de 100644 --- a/deflect/ImageSegmenter.cpp +++ b/deflect/ImageSegmenter.cpp @@ -80,7 +80,7 @@ Segment ImageSegmenter::createSingleSegment(const ImageWrapper& image) segment.imageData.reserve(segment.parameters.width * segment.parameters.height * image.getBytesPerPixel()); - segment.parameters.dataType = DataType::rgba; + segment.parameters.format = Format::rgba; segment.imageData.append((const char*)image.data, int(image.getBufferSize())); } @@ -181,7 +181,7 @@ void ImageSegmenter::_computeJpeg(SegmentTask& segment, const bool sendSegment) segment.exception = std::current_exception(); } - segment.parameters.dataType = DataType::jpeg; + segment.parameters.format = Format::jpeg; if (sendSegment) _sendQueue.enqueue(segment); #endif @@ -196,7 +196,7 @@ bool ImageSegmenter::_generateRaw(const ImageWrapper& image, segment.imageData.reserve(segment.parameters.width * segment.parameters.height * image.getBytesPerPixel()); - segment.parameters.dataType = DataType::rgba; + segment.parameters.format = Format::rgba; if (segments.size() == 1) { diff --git a/deflect/ImageWrapper.h b/deflect/ImageWrapper.h index 1501fbf..2598e71 100644 --- a/deflect/ImageWrapper.h +++ b/deflect/ImageWrapper.h @@ -145,7 +145,7 @@ struct ImageWrapper * * All images that form a frame (possibly from multiple Streams) must have * the same row order, otherwise the frame is invalid. This is because the - * frame's segments need to be reordered in addtion to flipping them + * frame's tiles need to be reordered in addtion to flipping them * individually. * * @version 1.0 diff --git a/deflect/MetaTypeRegistration.cpp b/deflect/MetaTypeRegistration.cpp index 2620e89..344a996 100644 --- a/deflect/MetaTypeRegistration.cpp +++ b/deflect/MetaTypeRegistration.cpp @@ -41,6 +41,8 @@ #include "Event.h" #include "Segment.h" #include "SizeHints.h" +#include "server/Tile.h" +#include "server/types.h" #include "types.h" #include @@ -63,6 +65,7 @@ struct MetaTypeRegistration "deflect::server::BoolPromisePtr"); qRegisterMetaType( "deflect::server::FramePtr"); + qRegisterMetaType("deflect::server::Tile"); } }; diff --git a/deflect/Segment.h b/deflect/Segment.h index 6aa516c..fafbcfb 100644 --- a/deflect/Segment.h +++ b/deflect/Segment.h @@ -47,7 +47,7 @@ namespace deflect { /** - * Image data and parameters for a single segment of a Frame. + * Image data and parameters for a segment of a larger image. */ struct Segment { diff --git a/deflect/SegmentParameters.h b/deflect/SegmentParameters.h index af1bb05..3490306 100644 --- a/deflect/SegmentParameters.h +++ b/deflect/SegmentParameters.h @@ -51,20 +51,7 @@ typedef unsigned __int32 uint32_t; namespace deflect { /** - * The possible formats for segment data. - * @version 1.0 - */ -enum class DataType : std::uint8_t -{ - rgba = 0, // equivalent to old compressed=false property - jpeg = 1, // equivalent to old compressed=true property - yuv444, - yuv422, - yuv420 -}; - -/** - * Parameters for a Segment of a Frame. + * Parameters for a Segment of an image. * @version 1.0 */ struct SegmentParameters @@ -82,7 +69,7 @@ struct SegmentParameters //@} /** Format in which the segment data is stored. */ - DataType dataType = DataType::jpeg; + Format format = Format::jpeg; /** * WARNING: diff --git a/deflect/qt/CMakeLists.txt b/deflect/qt/CMakeLists.txt index 23fe4a6..0d394d5 100644 --- a/deflect/qt/CMakeLists.txt +++ b/deflect/qt/CMakeLists.txt @@ -7,6 +7,7 @@ set(DEFLECTQT_HEADERS EventReceiver.h QmlGestures.h QmlStreamerImpl.h + types.h ) set(DEFLECTQT_PUBLIC_HEADERS OffscreenQuickView.h diff --git a/deflect/qt/types.h b/deflect/qt/types.h new file mode 100644 index 0000000..f891393 --- /dev/null +++ b/deflect/qt/types.h @@ -0,0 +1,55 @@ +/*********************************************************************/ +/* Copyright (c) 2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or */ +/* without modification, are permitted provided that the following */ +/* conditions are met: */ +/* */ +/* 1. Redistributions of source code must retain the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer. */ +/* */ +/* 2. Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */ +/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */ +/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */ +/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ +/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ +/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ +/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ +/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */ +/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ +/* POSSIBILITY OF SUCH DAMAGE. */ +/* */ +/* The views and conclusions contained in the software and */ +/* documentation are those of the authors and should not be */ +/* interpreted as representing official policies, either expressed */ +/* or implied, of The University of Texas at Austin. */ +/*********************************************************************/ + +#ifndef DEFLECT_QT_TYPES_H +#define DEFLECT_QT_TYPES_H + +#include + +namespace deflect +{ +namespace qt +{ +class QuickRenderer; +class QmlStreamer; +class TouchInjector; +} +} + +#endif diff --git a/deflect/server/CMakeLists.txt b/deflect/server/CMakeLists.txt index 2d60f7d..99594cd 100644 --- a/deflect/server/CMakeLists.txt +++ b/deflect/server/CMakeLists.txt @@ -6,6 +6,8 @@ set(DEFLECTSERVER_PUBLIC_HEADERS EventReceiver.h Frame.h Server.h + Tile.h + types.h ) set(DEFLECTSERVER_HEADERS FrameDispatcher.h @@ -28,14 +30,14 @@ set(DEFLECTSERVER_LINK_LIBRARIES if(DEFLECT_USE_LIBJPEGTURBO) list(APPEND DEFLECTSERVER_PUBLIC_HEADERS - SegmentDecoder.h + TileDecoder.h ) list(APPEND DEFLECTSERVER_HEADERS ImageJpegDecompressor.h ) list(APPEND DEFLECTSERVER_SOURCES ImageJpegDecompressor.cpp - SegmentDecoder.cpp + TileDecoder.cpp ) list(APPEND DEFLECTSERVER_LINK_LIBRARIES PRIVATE ${LibJpegTurbo_LIBRARIES}) endif() diff --git a/deflect/server/Frame.cpp b/deflect/server/Frame.cpp index 49139a0..818a332 100644 --- a/deflect/server/Frame.cpp +++ b/deflect/server/Frame.cpp @@ -1,6 +1,6 @@ /*********************************************************************/ -/* Copyright (c) 2015, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ +/* Copyright (c) 2015-2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or */ @@ -47,12 +47,10 @@ QSize Frame::computeDimensions() const { QSize size(0, 0); - for (const auto& segment : segments) + for (const auto& tile : tiles) { - const auto& params = segment.parameters; - size.setWidth(std::max(size.width(), (int)(params.width + params.x))); - size.setHeight( - std::max(size.height(), (int)(params.height + params.y))); + size.setWidth(std::max(size.width(), (int)(tile.width + tile.x))); + size.setHeight(std::max(size.height(), (int)(tile.height + tile.y))); } return size; @@ -60,14 +58,14 @@ QSize Frame::computeDimensions() const RowOrder Frame::determineRowOrder() const { - if (segments.empty()) - throw std::runtime_error("frame has no segements"); + if (tiles.empty()) + throw std::runtime_error("frame has no tiles"); - const auto frameRowOrder = segments[0].rowOrder; + const auto frameRowOrder = tiles[0].rowOrder; - for (const auto& segment : segments) + for (const auto& tile : tiles) { - if (segment.rowOrder != frameRowOrder) + if (tile.rowOrder != frameRowOrder) throw std::runtime_error("frame has incoherent row orders"); } diff --git a/deflect/server/Frame.h b/deflect/server/Frame.h index 5f69539..06f99a5 100644 --- a/deflect/server/Frame.h +++ b/deflect/server/Frame.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2014-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2014-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -40,9 +40,8 @@ #ifndef DEFLECT_SERVER_FRAME_H #define DEFLECT_SERVER_FRAME_H -#include #include -#include +#include #include #include @@ -54,21 +53,20 @@ namespace server /** * A frame for a PixelStream. */ -class Frame +struct Frame { -public: - /** The full set of segments for this frame. */ - Segments segments; + /** The full set of tiles for this frame. */ + Tiles tiles; /** The PixelStream uri to which this frame is associated. */ QString uri; - /** Get the total dimensions of this frame. */ + /** @return the total dimensions of this frame. */ DEFLECT_API QSize computeDimensions() const; /** - * @return the row order of all frame segments - * @throws std::runtime_error if not all segments have the same RowOrder + * @return the row order of all frame tiles. + * @throws std::runtime_error if not all tiles have the same RowOrder. */ DEFLECT_API RowOrder determineRowOrder() const; }; diff --git a/deflect/server/FrameDispatcher.cpp b/deflect/server/FrameDispatcher.cpp index f8f3e10..e839266 100644 --- a/deflect/server/FrameDispatcher.cpp +++ b/deflect/server/FrameDispatcher.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -61,12 +61,12 @@ class FrameDispatcher::Impl ReceiveBuffer& buffer = streamBuffers[uri]; while (buffer.hasCompleteFrame()) - frame->segments = buffer.popFrame(); + frame->tiles = buffer.popFrame(); - assert(!frame->segments.empty()); + assert(!frame->tiles.empty()); if (frame->determineRowOrder() == RowOrder::bottom_up) - mirrorSegmentsPositionsVertically(*frame); + mirrorTilesPositionsVertically(*frame); // receiver will request a new frame once this frame was consumed buffer.setAllowedToSend(false); @@ -74,11 +74,11 @@ class FrameDispatcher::Impl return frame; } - void mirrorSegmentsPositionsVertically(Frame& frame) const + void mirrorTilesPositionsVertically(Frame& frame) const { const auto height = frame.computeDimensions().height(); - for (auto& s : frame.segments) - s.parameters.y = height - s.parameters.y - s.parameters.height; + for (auto& tile : frame.tiles) + tile.y = height - tile.y - tile.height; } typedef std::map StreamBuffers; @@ -138,12 +138,11 @@ void FrameDispatcher::removeObserver(QString uri) deleteStream(uri); } -void FrameDispatcher::processSegment(const QString uri, - const size_t sourceIndex, - deflect::Segment segment) +void FrameDispatcher::processTile(const QString uri, const size_t sourceIndex, + deflect::server::Tile tile) { if (_impl->streamBuffers.count(uri)) - _impl->streamBuffers[uri].insert(segment, sourceIndex); + _impl->streamBuffers[uri].insert(tile, sourceIndex); } void FrameDispatcher::processFrameFinished(const QString uri, diff --git a/deflect/server/FrameDispatcher.h b/deflect/server/FrameDispatcher.h index fdc82a8..9ef105d 100644 --- a/deflect/server/FrameDispatcher.h +++ b/deflect/server/FrameDispatcher.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -40,9 +40,8 @@ #ifndef DEFLECT_SERVER_FRAMEDISPATCHER_H #define DEFLECT_SERVER_FRAMEDISPATCHER_H -#include #include -#include +#include #include #include @@ -52,7 +51,7 @@ namespace deflect namespace server { /** - * Gather segments from multiple sources and dispatch full frames. + * Gather Tiles from multiple sources and dispatch full frames. */ class FrameDispatcher : public QObject { @@ -67,7 +66,7 @@ class FrameDispatcher : public QObject public slots: /** - * Add a source of Segments for a Stream. + * Add a source of Tiles for a Stream. * * @param uri Identifier for the stream * @param sourceIndex Identifier for the source in this stream @@ -75,7 +74,7 @@ public slots: void addSource(QString uri, size_t sourceIndex); /** - * Remove a source of Segments for a Stream. + * Remove a source of Tiles for a Stream. * * @param uri Identifier for the stream * @param sourceIndex Identifier for the source in this stream @@ -83,7 +82,7 @@ public slots: void removeSource(QString uri, size_t sourceIndex); /** - * Add a stream source as an observer which does not contribute segments. + * Add a stream source as an observer which does not contribute tiles. * Emits pixelStreamOpened() if no other observer or source is present. * * @param uri Identifier for the stream @@ -99,17 +98,17 @@ public slots: void removeObserver(QString uri); /** - * Process a new Segment. + * Process a new Tile. * * @param uri Identifier for the stream * @param sourceIndex Identifier for the source in the stream - * @param segment to process + * @param tile to process */ - void processSegment(QString uri, size_t sourceIndex, - deflect::Segment segment); + void processTile(QString uri, size_t sourceIndex, + deflect::server::Tile tile); /** - * The given source has finished sending segments for the current frame. + * The given source has finished sending Tiles for the current frame. * * @param uri Identifier for the stream * @param sourceIndex Identifier for the source in the stream diff --git a/deflect/server/ImageJpegDecompressor.h b/deflect/server/ImageJpegDecompressor.h index 7a728e4..20f15cb 100644 --- a/deflect/server/ImageJpegDecompressor.h +++ b/deflect/server/ImageJpegDecompressor.h @@ -42,7 +42,7 @@ #include #include -#include +#include #include diff --git a/deflect/server/ReceiveBuffer.cpp b/deflect/server/ReceiveBuffer.cpp index 3b81aea..c2dc707 100644 --- a/deflect/server/ReceiveBuffer.cpp +++ b/deflect/server/ReceiveBuffer.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -77,11 +77,11 @@ size_t ReceiveBuffer::getSourceCount() const return _sourceBuffers.size(); } -void ReceiveBuffer::insert(const Segment& segment, const size_t sourceIndex) +void ReceiveBuffer::insert(const Tile& tile, const size_t sourceIndex) { assert(_sourceBuffers.count(sourceIndex)); - _sourceBuffers[sourceIndex].insert(segment); + _sourceBuffers[sourceIndex].insert(tile); } void ReceiveBuffer::finishFrameForSource(const size_t sourceIndex) @@ -110,16 +110,16 @@ bool ReceiveBuffer::hasCompleteFrame() const return !_sourceBuffers.empty(); } -Segments ReceiveBuffer::popFrame() +Tiles ReceiveBuffer::popFrame() { - Segments frame; + Tiles frame; for (auto& kv : _sourceBuffers) { auto& buffer = kv.second; if (buffer.getBackFrameIndex() > _lastFrameComplete) { - const auto& segments = buffer.getSegments(); - frame.insert(frame.end(), segments.begin(), segments.end()); + const auto& tiles = buffer.getTiles(); + frame.insert(frame.end(), tiles.begin(), tiles.end()); buffer.pop(); } } diff --git a/deflect/server/ReceiveBuffer.h b/deflect/server/ReceiveBuffer.h index 3635d9b..298df6e 100644 --- a/deflect/server/ReceiveBuffer.h +++ b/deflect/server/ReceiveBuffer.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -40,12 +40,8 @@ #ifndef DEFLECT_SERVER_RECEIVEBUFFER_H #define DEFLECT_SERVER_RECEIVEBUFFER_H -#include #include #include -#include - -#include #include #include @@ -55,16 +51,16 @@ namespace deflect namespace server { /** - * Buffer Segments from (multiple) sources. + * Buffer Tiles from (multiple) sources. * - * The buffer aggregates segments coming from different sources and delivers + * The buffer aggregates tiles coming from different sources and delivers * complete frames. */ class ReceiveBuffer { public: /** - * Add a source of segments. + * Add a source of tiles. * @param sourceIndex Unique source identifier * @return false if the source was already added or if * finishFrameForSource() has already been called for all existing @@ -73,7 +69,7 @@ class ReceiveBuffer DEFLECT_API bool addSource(size_t sourceIndex); /** - * Remove a source of segments. + * Remove a source of tiles. * @param sourceIndex Unique source identifier */ DEFLECT_API void removeSource(size_t sourceIndex); @@ -82,14 +78,14 @@ class ReceiveBuffer DEFLECT_API size_t getSourceCount() const; /** - * Insert a segment for the current frame and source. - * @param segment The segment to insert + * Insert a tile for the current frame and source. + * @param tile The tile to insert * @param sourceIndex Unique source identifier */ - DEFLECT_API void insert(const Segment& segment, size_t sourceIndex); + DEFLECT_API void insert(const Tile& tile, size_t sourceIndex); /** - * Call when the source has finished sending segments for the current frame. + * Call when the source has finished sending tiles for the current frame. * @param sourceIndex Unique source identifier * @throw std::runtime_error if the buffer exceeds its maximum size */ @@ -100,9 +96,9 @@ class ReceiveBuffer /** * Get the finished frame. - * @return A collection of segments that form a frame + * @return A collection of tiles that form a frame */ - DEFLECT_API Segments popFrame(); + DEFLECT_API Tiles popFrame(); /** Allow this buffer to be used by the next * FrameDispatcher::sendLatestFrame */ diff --git a/deflect/server/Server.cpp b/deflect/server/Server.cpp index d8a6e0f..fc56a68 100644 --- a/deflect/server/Server.cpp +++ b/deflect/server/Server.cpp @@ -146,8 +146,8 @@ void Server::incomingConnection(const qintptr socketHandle) // FrameDispatcher connect(worker, &ServerWorker::addStreamSource, _impl->frameDispatcher, &FrameDispatcher::addSource); - connect(worker, &ServerWorker::receivedSegment, _impl->frameDispatcher, - &FrameDispatcher::processSegment); + connect(worker, &ServerWorker::receivedTile, _impl->frameDispatcher, + &FrameDispatcher::processTile); connect(worker, &ServerWorker::receivedFrameFinished, _impl->frameDispatcher, &FrameDispatcher::processFrameFinished); connect(worker, &ServerWorker::removeStreamSource, _impl->frameDispatcher, diff --git a/deflect/server/Server.h b/deflect/server/Server.h index c2b02ed..7bd17b3 100644 --- a/deflect/server/Server.h +++ b/deflect/server/Server.h @@ -43,7 +43,7 @@ #include #include -#include +#include #include diff --git a/deflect/server/ServerWorker.cpp b/deflect/server/ServerWorker.cpp index f00115f..49f9d29 100644 --- a/deflect/server/ServerWorker.cpp +++ b/deflect/server/ServerWorker.cpp @@ -41,6 +41,7 @@ #include "ServerWorker.h" #include "deflect/NetworkProtocol.h" +#include "deflect/SegmentParameters.h" #include @@ -311,16 +312,19 @@ void ServerWorker::_parseClientProtocolVersion(const QByteArray& message) void ServerWorker::_handlePixelStreamMessage(const QByteArray& message) { - Segment segment; + Tile tile; const auto data = message.data(); - segment.parameters = *reinterpret_cast(data); - segment.imageData = - message.right(message.size() - sizeof(SegmentParameters)); - segment.view = _activeView; - segment.rowOrder = _activeRowOrder; - - emit(receivedSegment(_streamId, _sourceId, segment)); + const auto params = reinterpret_cast(data); + tile.x = params->x; + tile.y = params->y; + tile.width = params->width; + tile.height = params->height; + tile.imageData = message.right(message.size() - sizeof(SegmentParameters)); + tile.view = _activeView; + tile.rowOrder = _activeRowOrder; + + emit(receivedTile(_streamId, _sourceId, tile)); } void ServerWorker::_sendProtocolVersion() diff --git a/deflect/server/ServerWorker.h b/deflect/server/ServerWorker.h index da4354d..d55a5cd 100644 --- a/deflect/server/ServerWorker.h +++ b/deflect/server/ServerWorker.h @@ -43,10 +43,9 @@ #include #include -#include #include #include -#include +#include #include #include @@ -76,8 +75,8 @@ public slots: void addObserver(QString uri); void removeObserver(QString uri); - void receivedSegment(QString uri, size_t sourceIndex, - deflect::Segment segment); + void receivedTile(QString uri, size_t sourceIndex, + deflect::server::Tile tile); void receivedFrameFinished(QString uri, size_t sourceIndex); void registerToEvents(QString uri, bool exclusive, diff --git a/deflect/server/SourceBuffer.cpp b/deflect/server/SourceBuffer.cpp index 065de3e..1c546d1 100644 --- a/deflect/server/SourceBuffer.cpp +++ b/deflect/server/SourceBuffer.cpp @@ -1,6 +1,6 @@ /*********************************************************************/ -/* Copyright (c) 2017, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ +/* Copyright (c) 2017-2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or */ @@ -47,12 +47,12 @@ namespace server { SourceBuffer::SourceBuffer() { - _segments.push(Segments()); + _tiles.push(Tiles()); } -const Segments& SourceBuffer::getSegments() const +const Tiles& SourceBuffer::getTiles() const { - return _segments.front(); + return _tiles.front(); } FrameIndex SourceBuffer::getBackFrameIndex() const @@ -62,28 +62,28 @@ FrameIndex SourceBuffer::getBackFrameIndex() const bool SourceBuffer::isBackFrameEmpty() const { - return _segments.back().empty(); + return _tiles.back().empty(); } void SourceBuffer::pop() { - _segments.pop(); + _tiles.pop(); } void SourceBuffer::push() { - _segments.push(Segments()); + _tiles.push(Tiles()); ++_backFrameIndex; } -void SourceBuffer::insert(const Segment& segment) +void SourceBuffer::insert(const Tile& tile) { - _segments.back().push_back(segment); + _tiles.back().push_back(tile); } size_t SourceBuffer::getQueueSize() const { - return _segments.size(); + return _tiles.size(); } } } diff --git a/deflect/server/SourceBuffer.h b/deflect/server/SourceBuffer.h index 3946f34..5a264a1 100644 --- a/deflect/server/SourceBuffer.h +++ b/deflect/server/SourceBuffer.h @@ -1,6 +1,6 @@ /*********************************************************************/ -/* Copyright (c) 2017, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ +/* Copyright (c) 2017-2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or */ @@ -40,9 +40,7 @@ #ifndef DEFLECT_SERVER_SOURCEBUFFER_H #define DEFLECT_SERVER_SOURCEBUFFER_H -#include -#include -#include +#include #include #include @@ -54,7 +52,7 @@ namespace server using FrameIndex = unsigned int; /** - * Buffer for a single source of segments. + * Buffer for a single source of tiles. */ class SourceBuffer { @@ -62,17 +60,17 @@ class SourceBuffer /** Construct an empty buffer. */ SourceBuffer(); - /** @return the segments at the front of the queue. */ - const Segments& getSegments() const; + /** @return the tiles at the front of the queue. */ + const Tiles& getTiles() const; /** @return the frame index of the back of the buffer. */ FrameIndex getBackFrameIndex() const; - /** @return true if the back frame has no segments. */ + /** @return true if the back frame has no tiles. */ bool isBackFrameEmpty() const; - /** Insert a segment into the back frame. */ - void insert(const Segment& segment); + /** Insert a tile into the back frame. */ + void insert(const Tile& tile); /** Push a new frame to the back. */ void push(); @@ -84,8 +82,8 @@ class SourceBuffer size_t getQueueSize() const; private: - /** The collections of segments for each mono/left/right view. */ - std::queue _segments; + /** The collections of tiles for each mono/left/right view. */ + std::queue _tiles; /** The current indices of the mono/left/right frame for this source. */ FrameIndex _backFrameIndex = 0u; diff --git a/deflect/server/Tile.h b/deflect/server/Tile.h new file mode 100644 index 0000000..951c80f --- /dev/null +++ b/deflect/server/Tile.h @@ -0,0 +1,85 @@ +/*********************************************************************/ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or */ +/* without modification, are permitted provided that the following */ +/* conditions are met: */ +/* */ +/* 1. Redistributions of source code must retain the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer. */ +/* */ +/* 2. Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */ +/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */ +/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */ +/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ +/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ +/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ +/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ +/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */ +/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ +/* POSSIBILITY OF SUCH DAMAGE. */ +/* */ +/* The views and conclusions contained in the software and */ +/* documentation are those of the authors and should not be */ +/* interpreted as representing official policies, either expressed */ +/* or implied, of The University of Texas at Austin. */ +/*********************************************************************/ + +#ifndef DEFLECT_SERVER_TILE_H +#define DEFLECT_SERVER_TILE_H + +#include + +#include + +namespace deflect +{ +namespace server +{ +/** + * A Tile is a sub-region of an image in a Frame. + */ +struct Tile +{ + /** @name Coordinates */ + //@{ + uint32_t x = 0u; /**< The x position in pixels. */ + uint32_t y = 0u; /**< The y position in pixels. */ + //@} + + /** @name Dimensions */ + //@{ + uint32_t width = 0u; /**< The width in pixels. */ + uint32_t height = 0u; /**< The height in pixels. */ + //@} + + /** Image data. */ + QByteArray imageData; + + /** @name Image data parameters */ + //@{ + Format format = Format::jpeg; //!< Format in which the data is stored + RowOrder rowOrder = RowOrder::top_down; //!< Row order of imageData + //@} + + /** @name Metadata */ + //@{ + View view = View::mono; //!< Eye pass for the Tile + //@} +}; +} +} + +#endif diff --git a/deflect/server/SegmentDecoder.cpp b/deflect/server/TileDecoder.cpp similarity index 69% rename from deflect/server/SegmentDecoder.cpp rename to deflect/server/TileDecoder.cpp index 6eac463..db82557 100644 --- a/deflect/server/SegmentDecoder.cpp +++ b/deflect/server/TileDecoder.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -37,10 +37,10 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#include "SegmentDecoder.h" +#include "TileDecoder.h" #include "ImageJpegDecompressor.h" -#include "deflect/Segment.h" +#include "Tile.h" #include #include @@ -51,7 +51,7 @@ namespace deflect { namespace server { -class SegmentDecoder::Impl +class TileDecoder::Impl { public: Impl() {} @@ -62,67 +62,66 @@ class SegmentDecoder::Impl QFuture decodingFuture; }; -SegmentDecoder::SegmentDecoder() +TileDecoder::TileDecoder() : _impl(new Impl) { } -SegmentDecoder::~SegmentDecoder() +TileDecoder::~TileDecoder() { } -ChromaSubsampling SegmentDecoder::decodeType(const Segment& segment) +ChromaSubsampling TileDecoder::decodeType(const Tile& tile) { - if (segment.parameters.dataType != DataType::jpeg) - throw std::runtime_error("Segment is not in JPEG format"); + if (tile.format != Format::jpeg) + throw std::runtime_error("Tile is not in JPEG format"); - return _impl->decompressor.decompressHeader(segment.imageData).subsampling; + return _impl->decompressor.decompressHeader(tile.imageData).subsampling; } -size_t _getExpectedSize(const DataType dataType, - const SegmentParameters& params) +size_t _getExpectedSize(const Format format, const Tile& tile) { - const size_t imageSize = params.height * params.width; - switch (dataType) + const size_t imageSize = tile.height * tile.width; + switch (format) { - case DataType::rgba: + case Format::rgba: return imageSize * 4; - case DataType::yuv444: + case Format::yuv444: return imageSize * 3; - case DataType::yuv422: + case Format::yuv422: return imageSize * 2; - case DataType::yuv420: + case Format::yuv420: return imageSize + (imageSize >> 1); default: return 0; }; } -void _decodeSegment(ImageJpegDecompressor* decompressor, Segment* segment, - const bool skipRgbConversion) +void _decodeTile(ImageJpegDecompressor* decompressor, Tile* tile, + const bool skipRgbConversion) { - if (segment->parameters.dataType != DataType::jpeg) + if (tile->format != Format::jpeg) return; QByteArray decodedData; - DataType dataType; + Format format; try { #ifndef DEFLECT_USE_LEGACY_LIBJPEGTURBO if (skipRgbConversion) { - const auto yuv = decompressor->decompressToYUV(segment->imageData); + const auto yuv = decompressor->decompressToYUV(tile->imageData); decodedData = yuv.first; switch (yuv.second) { case ChromaSubsampling::YUV444: - dataType = DataType::yuv444; + format = Format::yuv444; break; case ChromaSubsampling::YUV422: - dataType = DataType::yuv422; + format = Format::yuv422; break; case ChromaSubsampling::YUV420: - dataType = DataType::yuv420; + format = Format::yuv420; break; default: throw std::runtime_error("unexpected ChromaSubsampling mode"); @@ -133,8 +132,8 @@ void _decodeSegment(ImageJpegDecompressor* decompressor, Segment* segment, Q_UNUSED(skipRgbConversion); #endif { - decodedData = decompressor->decompress(segment->imageData); - dataType = DataType::rgba; + decodedData = decompressor->decompress(tile->imageData); + format = Format::rgba; } } catch (const std::runtime_error&) @@ -142,29 +141,29 @@ void _decodeSegment(ImageJpegDecompressor* decompressor, Segment* segment, throw; } - const auto expectedSize = _getExpectedSize(dataType, segment->parameters); + const auto expectedSize = _getExpectedSize(format, *tile); if (size_t(decodedData.size()) != expectedSize) - throw std::runtime_error("unexpected segment size"); + throw std::runtime_error("unexpected tile size"); - segment->imageData = decodedData; - segment->parameters.dataType = dataType; + tile->imageData = decodedData; + tile->format = format; } -void SegmentDecoder::decode(Segment& segment) +void TileDecoder::decode(Tile& tile) { - _decodeSegment(&_impl->decompressor, &segment, false); + _decodeTile(&_impl->decompressor, &tile, false); } #ifndef DEFLECT_USE_LEGACY_LIBJPEGTURBO -void SegmentDecoder::decodeToYUV(Segment& segment) +void TileDecoder::decodeToYUV(Tile& tile) { - _decodeSegment(&_impl->decompressor, &segment, true); + _decodeTile(&_impl->decompressor, &tile, true); } #endif -void SegmentDecoder::startDecoding(Segment& segment) +void TileDecoder::startDecoding(Tile& tile) { // drop frames if we're currently processing if (isRunning()) @@ -176,11 +175,10 @@ void SegmentDecoder::startDecoding(Segment& segment) } _impl->decodingFuture = - QtConcurrent::run(_decodeSegment, &_impl->decompressor, &segment, - false); + QtConcurrent::run(_decodeTile, &_impl->decompressor, &tile, false); } -void SegmentDecoder::waitDecoding() +void TileDecoder::waitDecoding() { try { @@ -191,11 +189,11 @@ void SegmentDecoder::waitDecoding() // Let Qt throws a QUnhandledException and rewrite the error message. // QtConcurrent::run can only forward QException subclasses, which does // not even work on 5.7.1: https://bugreports.qt.io/browse/QTBUG-58021 - throw std::runtime_error("Segment decoding failed"); + throw std::runtime_error("Tile decoding failed"); } } -bool SegmentDecoder::isRunning() const +bool TileDecoder::isRunning() const { return _impl->decodingFuture.isRunning(); } diff --git a/deflect/server/SegmentDecoder.h b/deflect/server/TileDecoder.h similarity index 74% rename from deflect/server/SegmentDecoder.h rename to deflect/server/TileDecoder.h index 9914b27..a214ab0 100644 --- a/deflect/server/SegmentDecoder.h +++ b/deflect/server/TileDecoder.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -37,75 +37,75 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#ifndef DEFLECT_SERVER_SEGMENTDECODER_H -#define DEFLECT_SERVER_SEGMENTDECODER_H +#ifndef DEFLECT_SERVER_TILEDECODER_H +#define DEFLECT_SERVER_TILEDECODER_H #include #include -#include +#include namespace deflect { namespace server { /** - * Decode a Segment's image asynchronously. + * Decode a Tile's image asynchronously. */ -class SegmentDecoder +class TileDecoder { public: /** Construct a Decoder */ - DEFLECT_API SegmentDecoder(); + DEFLECT_API TileDecoder(); /** Destruct a Decoder */ - DEFLECT_API ~SegmentDecoder(); + DEFLECT_API ~TileDecoder(); /** - * Decode the data type of a JPEG segment. + * Decode the data type of a JPEG tile. * - * @param segment The segment to decode. + * @param tile The tile to decode. * @throw std::runtime_error if a decompression error occured */ - DEFLECT_API ChromaSubsampling decodeType(const Segment& segment); + DEFLECT_API ChromaSubsampling decodeType(const Tile& tile); /** - * Decode a JPEG segment to RGB. + * Decode a JPEG tile to RGB. * - * @param segment The segment to decode. Upon success, its imageData member - * will hold the decompressed RGB image and its "dataType" flag will - * be set to DataType::rgba. + * @param tile The tile to decode. Upon success, its imageData member + * will hold the decompressed RGB image and its "format" flag will + * be set to Format::rgba. * @throw std::runtime_error if a decompression error occured */ - DEFLECT_API void decode(Segment& segment); + DEFLECT_API void decode(Tile& tile); #ifndef DEFLECT_USE_LEGACY_LIBJPEGTURBO /** - * Decode a JPEG segment to YUV, skipping the YUV -> RGB step. + * Decode a JPEG tile to YUV, skipping the YUV -> RGB step. * - * @param segment The segment to decode. Upon success, its imageData member - * will hold the decompressed YUV image and its "dataType" flag will - * be set to the matching DataType::yuv4**. + * @param tile The tile to decode. Upon success, its imageData member + * will hold the decompressed YUV image and its "format" flag will + * be set to the matching Format::yuv4**. * @throw std::runtime_error if a decompression error occured */ - DEFLECT_API void decodeToYUV(Segment& segment); + DEFLECT_API void decodeToYUV(Tile& tile); #endif /** - * Start decoding a segment. + * Start decoding a tile. * * This function will silently ignore the request if a decoding is already * in progress. - * @param segment The segement to decode. The segment will be modified by + * @param tile The tile to decode. The tile will be modified by * this function. It must remain valid and should not be accessed * until the decoding procedure has completed. * @see isRunning() */ - DEFLECT_API void startDecoding(Segment& segment); + DEFLECT_API void startDecoding(Tile& tile); /** - * Waits for the decoding of a segment to finish, initiated by + * Waits for the decoding of a tile to finish, initiated by * startDecoding(). * @throw std::runtime_error if a decompression error occured */ diff --git a/deflect/server/types.h b/deflect/server/types.h new file mode 100644 index 0000000..ebc361c --- /dev/null +++ b/deflect/server/types.h @@ -0,0 +1,63 @@ +/*********************************************************************/ +/* Copyright (c) 2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or */ +/* without modification, are permitted provided that the following */ +/* conditions are met: */ +/* */ +/* 1. Redistributions of source code must retain the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer. */ +/* */ +/* 2. Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */ +/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */ +/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */ +/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ +/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ +/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ +/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ +/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */ +/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ +/* POSSIBILITY OF SUCH DAMAGE. */ +/* */ +/* The views and conclusions contained in the software and */ +/* documentation are those of the authors and should not be */ +/* interpreted as representing official policies, either expressed */ +/* or implied, of The University of Texas at Austin. */ +/*********************************************************************/ + +#ifndef DEFLECT_SERVER_TYPES_H +#define DEFLECT_SERVER_TYPES_H + +#include + +namespace deflect +{ +namespace server +{ +class EventReceiver; +class FrameDispatcher; +class TileDecoder; +class Server; + +struct Frame; +struct Tile; + +using Tiles = std::vector; +using BoolPromisePtr = std::shared_ptr>; +using FramePtr = std::shared_ptr; +} +} + +#endif diff --git a/deflect/types.h b/deflect/types.h index 296cf70..4e568b7 100644 --- a/deflect/types.h +++ b/deflect/types.h @@ -71,6 +71,16 @@ enum class RowOrder bottom_up /**< OpenGL image with (0,0) at the bottom-left corner. */ }; +/** The possible formats for image data. */ +enum class Format : std::uint8_t +{ + rgba = 0, + jpeg = 1, + yuv444, + yuv422, + yuv420 +}; + /** Cast an enum class value to its underlying type. */ template constexpr typename std::underlying_type::type as_underlying_type(E e) @@ -104,36 +114,17 @@ std::future make_exception_future(Exception&& e) } class ImageSegmenter; -class MessageHeader; class Stream; struct Event; struct ImageWrapper; +struct MessageHeader; struct Segment; struct SegmentParameters; struct SizeHints; using Segments = std::vector; -namespace server -{ -class EventReceiver; -class Frame; -class FrameDispatcher; -class SegmentDecoder; -class Server; - -using BoolPromisePtr = std::shared_ptr>; -using FramePtr = std::shared_ptr; -} - -namespace qt -{ -class QuickRenderer; -class QmlStreamer; -class TouchInjector; -} - /** @internal */ namespace test { diff --git a/doc/Changelog.md b/doc/Changelog.md index 8e5ecfe..1e2e134 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -5,7 +5,7 @@ Changelog {#Changelog} ### 1.0.0 (git master) * [194](https://github.com/BlueBrain/Deflect/pull/194): - Reset API versionning to 1.0, remove deprecated functions (Stream::asyncSend, + Reset API versioning to 1.0, remove deprecated functions (Stream::asyncSend, ImageWrapper::swapYAxis). Moved all server-specific classes to a separate namespace. diff --git a/tests/cpp/CMakeLists.txt b/tests/cpp/CMakeLists.txt index b1b7173..97ff24b 100644 --- a/tests/cpp/CMakeLists.txt +++ b/tests/cpp/CMakeLists.txt @@ -8,6 +8,6 @@ set(TEST_LIBRARIES DeflectServer DeflectMock ${Boost_LIBRARIES} Qt5::Widgets) add_definitions(-DBOOST_PROGRAM_OPTIONS_DYN_LINK) if(NOT DEFLECT_USE_LIBJPEGTURBO) - set(EXCLUDE_FROM_TESTS SegmentDecoderTests.cpp) + set(EXCLUDE_FROM_TESTS TileDecoderTests.cpp) endif() include(CommonCTest) diff --git a/tests/cpp/FrameDispatcherTests.cpp b/tests/cpp/FrameDispatcherTests.cpp index f63d6ee..e10143a 100644 --- a/tests/cpp/FrameDispatcherTests.cpp +++ b/tests/cpp/FrameDispatcherTests.cpp @@ -1,6 +1,6 @@ /*********************************************************************/ -/* Copyright (c) 2017, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ +/* Copyright (c) 2017-2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or */ @@ -68,8 +68,8 @@ struct Fixture void dispatch(const deflect::server::Frame& frame) { - for (auto& segment : frame.segments) - dispatcher.processSegment(streamId, 0, segment); + for (auto& tile : frame.tiles) + dispatcher.processTile(streamId, 0, tile); dispatcher.processFrameFinished(streamId, 0); dispatcher.requestFrame(streamId); } @@ -97,15 +97,15 @@ BOOST_FIXTURE_TEST_CASE(dispatch_multiple_frames, Fixture) BOOST_FIXTURE_TEST_CASE(dispatch_frame_bottom_up, Fixture) { auto frame = makeTestFrame(640, 480, 64); - for (auto& segment : frame.segments) - segment.rowOrder = deflect::RowOrder::bottom_up; + for (auto& tile : frame.tiles) + tile.rowOrder = deflect::RowOrder::bottom_up; dispatch(frame); BOOST_REQUIRE(receivedFrame); - // mirror segments positions vertically - for (auto& s : frame.segments) - s.parameters.y = 480 - s.parameters.y - s.parameters.height; + // mirror tiles positions vertically + for (auto& tile : frame.tiles) + tile.y = 480 - tile.y - tile.height; compare(frame, *receivedFrame); } @@ -113,7 +113,7 @@ BOOST_FIXTURE_TEST_CASE(dispatch_frame_bottom_up, Fixture) BOOST_FIXTURE_TEST_CASE(dispatch_frame_with_inconsistent_row_order, Fixture) { auto frame = makeTestFrame(640, 480, 64); - frame.segments[2].rowOrder = deflect::RowOrder::bottom_up; + frame.tiles[2].rowOrder = deflect::RowOrder::bottom_up; dispatch(frame); BOOST_CHECK(!receivedFrame); } diff --git a/tests/cpp/FrameTests.cpp b/tests/cpp/FrameTests.cpp index 4537abe..2e9e9d0 100644 --- a/tests/cpp/FrameTests.cpp +++ b/tests/cpp/FrameTests.cpp @@ -1,6 +1,6 @@ /*********************************************************************/ -/* Copyright (c) 2017, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ +/* Copyright (c) 2017-2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or */ @@ -64,13 +64,13 @@ BOOST_AUTO_TEST_CASE(determine_frame_row_order) auto frame = makeTestFrame(640, 480, 64); BOOST_CHECK(frame.determineRowOrder() == deflect::RowOrder::top_down); - frame.segments[0].rowOrder = deflect::RowOrder::bottom_up; + frame.tiles[0].rowOrder = deflect::RowOrder::bottom_up; BOOST_CHECK_THROW(frame.determineRowOrder(), std::runtime_error); - for (auto& segment : frame.segments) - segment.rowOrder = deflect::RowOrder::bottom_up; + for (auto& tile : frame.tiles) + tile.rowOrder = deflect::RowOrder::bottom_up; BOOST_CHECK(frame.determineRowOrder() == deflect::RowOrder::bottom_up); - frame.segments[0].rowOrder = deflect::RowOrder::top_down; + frame.tiles[0].rowOrder = deflect::RowOrder::top_down; BOOST_CHECK_THROW(frame.determineRowOrder(), std::runtime_error); } diff --git a/tests/cpp/ReceiveBufferTests.cpp b/tests/cpp/ReceiveBufferTests.cpp index 42d087f..d8f8b7b 100644 --- a/tests/cpp/ReceiveBufferTests.cpp +++ b/tests/cpp/ReceiveBufferTests.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -41,7 +41,6 @@ #include namespace ut = boost::unit_test; -#include #include #include @@ -94,69 +93,69 @@ BOOST_AUTO_TEST_CASE(TestCompleteAFrame) deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex); - deflect::Segment segment; - segment.parameters.x = 0; - segment.parameters.y = 0; - segment.parameters.width = 128; - segment.parameters.height = 256; + deflect::server::Tile tile; + tile.x = 0; + tile.y = 0; + tile.width = 128; + tile.height = 256; - buffer.insert(segment, sourceIndex); + buffer.insert(tile, sourceIndex); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex); BOOST_CHECK(buffer.hasCompleteFrame()); - deflect::Segments segments = buffer.popFrame(); + const auto tiles = buffer.popFrame(); - BOOST_CHECK_EQUAL(segments.size(), 1); + BOOST_CHECK_EQUAL(tiles.size(), 1); BOOST_CHECK(!buffer.hasCompleteFrame()); deflect::server::Frame frame; - frame.segments = segments; + frame.tiles = tiles; const QSize frameSize = frame.computeDimensions(); - BOOST_CHECK_EQUAL(frameSize.width(), segment.parameters.width); - BOOST_CHECK_EQUAL(frameSize.height(), segment.parameters.height); + BOOST_CHECK_EQUAL(frameSize.width(), tile.width); + BOOST_CHECK_EQUAL(frameSize.height(), tile.height); } -deflect::Segments generateTestSegments( +deflect::server::Tiles generateTestTiles( const deflect::View view = deflect::View::mono) { - deflect::Segments segments; - - deflect::Segment segment1; - segment1.parameters.x = 0; - segment1.parameters.y = 0; - segment1.parameters.width = 128; - segment1.parameters.height = 256; - segment1.view = view; - - deflect::Segment segment2; - segment2.parameters.x = 128; - segment2.parameters.y = 0; - segment2.parameters.width = 64; - segment2.parameters.height = 256; - segment2.view = view; - - deflect::Segment segment3; - segment3.parameters.x = 0; - segment3.parameters.y = 256; - segment3.parameters.width = 128; - segment3.parameters.height = 512; - segment3.view = view; - - deflect::Segment segment4; - segment4.parameters.x = 128; - segment4.parameters.y = 256; - segment4.parameters.width = 64; - segment4.parameters.height = 512; - segment4.view = view; - - segments.push_back(segment1); - segments.push_back(segment2); - segments.push_back(segment3); - segments.push_back(segment4); - - return segments; + deflect::server::Tiles tiles; + + deflect::server::Tile tile1; + tile1.x = 0; + tile1.y = 0; + tile1.width = 128; + tile1.height = 256; + tile1.view = view; + + deflect::server::Tile tile2; + tile2.x = 128; + tile2.y = 0; + tile2.width = 64; + tile2.height = 256; + tile2.view = view; + + deflect::server::Tile tile3; + tile3.x = 0; + tile3.y = 256; + tile3.width = 128; + tile3.height = 512; + tile3.view = view; + + deflect::server::Tile tile4; + tile4.x = 128; + tile4.y = 256; + tile4.width = 64; + tile4.height = 512; + tile4.view = view; + + tiles.push_back(tile1); + tiles.push_back(tile2); + tiles.push_back(tile3); + tiles.push_back(tile4); + + return tiles; } BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameSingleSource) @@ -166,23 +165,23 @@ BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameSingleSource) deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex); - deflect::Segments testSegments = generateTestSegments(); + const auto testTiles = generateTestTiles(); - buffer.insert(testSegments[0], sourceIndex); - buffer.insert(testSegments[1], sourceIndex); - buffer.insert(testSegments[2], sourceIndex); - buffer.insert(testSegments[3], sourceIndex); + buffer.insert(testTiles[0], sourceIndex); + buffer.insert(testTiles[1], sourceIndex); + buffer.insert(testTiles[2], sourceIndex); + buffer.insert(testTiles[3], sourceIndex); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex); BOOST_CHECK(buffer.hasCompleteFrame()); - deflect::Segments segments = buffer.popFrame(); - BOOST_CHECK_EQUAL(segments.size(), 4); + const auto tiles = buffer.popFrame(); + BOOST_CHECK_EQUAL(tiles.size(), 4); BOOST_CHECK(!buffer.hasCompleteFrame()); deflect::server::Frame frame; - frame.segments = segments; + frame.tiles = tiles; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 768)); } @@ -197,11 +196,11 @@ BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameMultipleSources) buffer.addSource(sourceIndex2); buffer.addSource(sourceIndex3); - deflect::Segments testSegments = generateTestSegments(); + const auto testTiles = generateTestTiles(); - buffer.insert(testSegments[0], sourceIndex1); - buffer.insert(testSegments[1], sourceIndex2); - buffer.insert(testSegments[2], sourceIndex3); + buffer.insert(testTiles[0], sourceIndex1); + buffer.insert(testTiles[1], sourceIndex2); + buffer.insert(testTiles[2], sourceIndex3); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex1); @@ -210,16 +209,16 @@ BOOST_AUTO_TEST_CASE(TestCompleteACompositeFrameMultipleSources) buffer.finishFrameForSource(sourceIndex2); BOOST_CHECK(!buffer.hasCompleteFrame()); - buffer.insert(testSegments[3], sourceIndex3); + buffer.insert(testTiles[3], sourceIndex3); buffer.finishFrameForSource(sourceIndex3); BOOST_CHECK(buffer.hasCompleteFrame()); - deflect::Segments segments = buffer.popFrame(); - BOOST_CHECK_EQUAL(segments.size(), 4); + const auto tiles = buffer.popFrame(); + BOOST_CHECK_EQUAL(tiles.size(), 4); BOOST_CHECK(!buffer.hasCompleteFrame()); deflect::server::Frame frame; - frame.segments = segments; + frame.tiles = tiles; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 768)); } @@ -232,43 +231,43 @@ BOOST_AUTO_TEST_CASE(TestRemoveSourceWhileStreaming) buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); - deflect::Segments testSegments = generateTestSegments(); + const auto testTiles = generateTestTiles(); // First Frame - 2 sources - buffer.insert(testSegments[0], sourceIndex1); - buffer.insert(testSegments[1], sourceIndex1); - buffer.insert(testSegments[2], sourceIndex2); - buffer.insert(testSegments[3], sourceIndex2); + buffer.insert(testTiles[0], sourceIndex1); + buffer.insert(testTiles[1], sourceIndex1); + buffer.insert(testTiles[2], sourceIndex2); + buffer.insert(testTiles[3], sourceIndex2); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex1); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex2); BOOST_CHECK(buffer.hasCompleteFrame()); - deflect::Segments segments = buffer.popFrame(); + auto tiles = buffer.popFrame(); - BOOST_CHECK_EQUAL(segments.size(), 4); + BOOST_CHECK_EQUAL(tiles.size(), 4); BOOST_CHECK(!buffer.hasCompleteFrame()); // Second frame - 1 source buffer.removeSource(sourceIndex2); - buffer.insert(testSegments[0], sourceIndex1); - buffer.insert(testSegments[1], sourceIndex1); + buffer.insert(testTiles[0], sourceIndex1); + buffer.insert(testTiles[1], sourceIndex1); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex1); BOOST_CHECK(buffer.hasCompleteFrame()); - segments = buffer.popFrame(); - BOOST_CHECK_EQUAL(segments.size(), 2); + tiles = buffer.popFrame(); + BOOST_CHECK_EQUAL(tiles.size(), 2); BOOST_CHECK(!buffer.hasCompleteFrame()); deflect::server::Frame frame; - frame.segments = segments; + frame.tiles = tiles; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 256)); } -BOOST_AUTO_TEST_CASE(TestOneOfTwoSourceStopsSendingSegments) +BOOST_AUTO_TEST_CASE(TestOneOfTwoSourceStopsSendingTiles) { const size_t sourceIndex1 = 46; const size_t sourceIndex2 = 819; @@ -277,57 +276,57 @@ BOOST_AUTO_TEST_CASE(TestOneOfTwoSourceStopsSendingSegments) buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); - deflect::Segments testSegments = generateTestSegments(); + const auto testTiles = generateTestTiles(); // First Frame - 2 sources - buffer.insert(testSegments[0], sourceIndex1); - buffer.insert(testSegments[1], sourceIndex1); - buffer.insert(testSegments[2], sourceIndex2); - buffer.insert(testSegments[3], sourceIndex2); + buffer.insert(testTiles[0], sourceIndex1); + buffer.insert(testTiles[1], sourceIndex1); + buffer.insert(testTiles[2], sourceIndex2); + buffer.insert(testTiles[3], sourceIndex2); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex1); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex2); BOOST_CHECK(buffer.hasCompleteFrame()); - deflect::Segments segments = buffer.popFrame(); + const auto tiles = buffer.popFrame(); - BOOST_CHECK_EQUAL(segments.size(), 4); + BOOST_CHECK_EQUAL(tiles.size(), 4); BOOST_CHECK(!buffer.hasCompleteFrame()); - // Next frames - one source stops sending segments + // Next frames - one source stops sending tiles for (int i = 0; i < 150; ++i) { - buffer.insert(testSegments[0], sourceIndex1); - buffer.insert(testSegments[1], sourceIndex1); + buffer.insert(testTiles[0], sourceIndex1); + buffer.insert(testTiles[1], sourceIndex1); BOOST_REQUIRE_NO_THROW(buffer.finishFrameForSource(sourceIndex1)); BOOST_REQUIRE(!buffer.hasCompleteFrame()); } // Test buffer exceeds maximum allowed size - buffer.insert(testSegments[0], sourceIndex1); - buffer.insert(testSegments[1], sourceIndex1); + buffer.insert(testTiles[0], sourceIndex1); + buffer.insert(testTiles[1], sourceIndex1); BOOST_CHECK_THROW(buffer.finishFrameForSource(sourceIndex1), std::runtime_error); } void _insert(deflect::server::ReceiveBuffer& buffer, const size_t sourceIndex, - const deflect::Segments& frame) + const deflect::server::Tiles& frame) { - for (const auto& segment : frame) - buffer.insert(segment, sourceIndex); + for (const auto& tile : frame) + buffer.insert(tile, sourceIndex); } void _testStereoBuffer(deflect::server::ReceiveBuffer& buffer) { - const auto segments = buffer.popFrame(); - BOOST_CHECK_EQUAL(segments.size(), 8); + const auto tiles = buffer.popFrame(); + BOOST_CHECK_EQUAL(tiles.size(), 8); BOOST_CHECK(!buffer.hasCompleteFrame()); size_t left = 0; size_t right = 0; - for (const auto segment : segments) + for (const auto tile : tiles) { - switch (segment.view) + switch (tile.view) { case deflect::View::left_eye: ++left; @@ -344,7 +343,7 @@ void _testStereoBuffer(deflect::server::ReceiveBuffer& buffer) BOOST_CHECK_EQUAL(right, 4); deflect::server::Frame frame; - frame.segments = segments; + frame.tiles = tiles; BOOST_CHECK_EQUAL(frame.computeDimensions(), QSize(192, 768)); } @@ -355,12 +354,12 @@ BOOST_AUTO_TEST_CASE(TestStereoOneSource) deflect::server::ReceiveBuffer buffer; buffer.addSource(sourceIndex); - auto leftSegments = generateTestSegments(deflect::View::left_eye); - _insert(buffer, sourceIndex, leftSegments); + auto leftTiles = generateTestTiles(deflect::View::left_eye); + _insert(buffer, sourceIndex, leftTiles); BOOST_CHECK(!buffer.hasCompleteFrame()); - auto rightSegments = generateTestSegments(deflect::View::right_eye); - _insert(buffer, sourceIndex, rightSegments); + auto rightTiles = generateTestTiles(deflect::View::right_eye); + _insert(buffer, sourceIndex, rightTiles); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex); @@ -378,18 +377,18 @@ BOOST_AUTO_TEST_CASE(TestStereoTwoSourcesScreenSpaceSplit) buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); - const auto leftSegments = generateTestSegments(deflect::View::left_eye); - const auto rightSegments = generateTestSegments(deflect::View::right_eye); + const auto leftTiles = generateTestTiles(deflect::View::left_eye); + const auto rightTiles = generateTestTiles(deflect::View::right_eye); - _insert(buffer, sourceIndex1, {leftSegments[0], leftSegments[1]}); + _insert(buffer, sourceIndex1, {leftTiles[0], leftTiles[1]}); BOOST_CHECK(!buffer.hasCompleteFrame()); - _insert(buffer, sourceIndex1, {rightSegments[0], rightSegments[1]}); + _insert(buffer, sourceIndex1, {rightTiles[0], rightTiles[1]}); BOOST_CHECK(!buffer.hasCompleteFrame()); - _insert(buffer, sourceIndex2, {leftSegments[2], leftSegments[3]}); + _insert(buffer, sourceIndex2, {leftTiles[2], leftTiles[3]}); BOOST_CHECK(!buffer.hasCompleteFrame()); - _insert(buffer, sourceIndex2, {rightSegments[2], rightSegments[3]}); + _insert(buffer, sourceIndex2, {rightTiles[2], rightTiles[3]}); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex1); @@ -410,12 +409,12 @@ BOOST_AUTO_TEST_CASE(TestStereoTwoSourcesStereoSplit) buffer.addSource(sourceIndex1); buffer.addSource(sourceIndex2); - const auto leftSegments = generateTestSegments(deflect::View::left_eye); - const auto rightSegments = generateTestSegments(deflect::View::right_eye); + const auto leftTiles = generateTestTiles(deflect::View::left_eye); + const auto rightTiles = generateTestTiles(deflect::View::right_eye); - _insert(buffer, sourceIndex1, leftSegments); + _insert(buffer, sourceIndex1, leftTiles); BOOST_CHECK(!buffer.hasCompleteFrame()); - _insert(buffer, sourceIndex2, rightSegments); + _insert(buffer, sourceIndex2, rightTiles); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex1); @@ -440,19 +439,19 @@ BOOST_AUTO_TEST_CASE(TestStereoFourSourcesScreenSpaceAndStereoSplit) buffer.addSource(sourceIndex3); buffer.addSource(sourceIndex4); - const auto leftSegments = generateTestSegments(deflect::View::left_eye); - const auto rightSegments = generateTestSegments(deflect::View::right_eye); + const auto leftTiles = generateTestTiles(deflect::View::left_eye); + const auto rightTiles = generateTestTiles(deflect::View::right_eye); - _insert(buffer, sourceIndex1, {leftSegments[0], leftSegments[1]}); + _insert(buffer, sourceIndex1, {leftTiles[0], leftTiles[1]}); BOOST_CHECK(!buffer.hasCompleteFrame()); - _insert(buffer, sourceIndex2, {rightSegments[0], rightSegments[1]}); + _insert(buffer, sourceIndex2, {rightTiles[0], rightTiles[1]}); BOOST_CHECK(!buffer.hasCompleteFrame()); - _insert(buffer, sourceIndex3, {leftSegments[2], leftSegments[3]}); + _insert(buffer, sourceIndex3, {leftTiles[2], leftTiles[3]}); BOOST_CHECK(!buffer.hasCompleteFrame()); - _insert(buffer, sourceIndex4, {rightSegments[2], rightSegments[3]}); + _insert(buffer, sourceIndex4, {rightTiles[2], rightTiles[3]}); BOOST_CHECK(!buffer.hasCompleteFrame()); buffer.finishFrameForSource(sourceIndex1); diff --git a/tests/cpp/ServerTests.cpp b/tests/cpp/ServerTests.cpp index fb09456..f0d3202 100644 --- a/tests/cpp/ServerTests.cpp +++ b/tests/cpp/ServerTests.cpp @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(dataReceivedByServer) BOOST_AUTO_TEST_CASE(oneObserverAndOneStream) { setFrameReceivedCallback([&](deflect::server::FramePtr frame) { - SAFE_BOOST_CHECK_EQUAL(frame->segments.size(), 1); + SAFE_BOOST_CHECK_EQUAL(frame->tiles.size(), 1); SAFE_BOOST_CHECK_EQUAL(frame->uri.toStdString(), testStreamId.toStdString()); }); @@ -336,7 +336,7 @@ BOOST_AUTO_TEST_CASE(threadedSmallSegmentStream) std::ceil((float)height / segmentSize)); setFrameReceivedCallback([&](deflect::server::FramePtr frame) { - SAFE_BOOST_CHECK_EQUAL(frame->segments.size(), numSegments); + SAFE_BOOST_CHECK_EQUAL(frame->tiles.size(), numSegments); SAFE_BOOST_CHECK_EQUAL(frame->uri.toStdString(), testStreamId.toStdString()); const auto dim = frame->computeDimensions(); diff --git a/tests/cpp/SegmentDecoderTests.cpp b/tests/cpp/TileDecoderTests.cpp similarity index 82% rename from tests/cpp/SegmentDecoderTests.cpp rename to tests/cpp/TileDecoderTests.cpp index 7f0a05b..9e3f3db 100644 --- a/tests/cpp/SegmentDecoderTests.cpp +++ b/tests/cpp/TileDecoderTests.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -37,16 +37,17 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ -#define BOOST_TEST_MODULE SegmentDecoderTests +#define BOOST_TEST_MODULE TileDecoderTests + #include namespace ut = boost::unit_test; #include #include #include -#include #include -#include +#include +#include #include #include // std::round @@ -77,9 +78,9 @@ const std::vector expectedVData(8 * 8, _toV(92, 28, 0)); namespace deflect { -inline std::ostream& operator<<(std::ostream& str, const DataType t) +inline std::ostream& operator<<(std::ostream& str, const Format t) { - str << "DataType(" << as_underlying_type(t) << ")"; + str << "Format(" << as_underlying_type(t) << ")"; return str; } inline std::ostream& operator<<(std::ostream& str, const ChromaSubsampling s) @@ -142,23 +143,22 @@ QByteArray decodeToYUVWithDecompressor( return yuvData.first; } -QByteArray decodeToYUVWithSegmentDecoder( - const QByteArray& jpegData, const deflect::ChromaSubsampling expected) +QByteArray decodeToYUVWithTileDecoder(const QByteArray& jpegData, + const deflect::ChromaSubsampling expected) { - deflect::Segment segment; - segment.parameters.width = 8; - segment.parameters.height = 8; - segment.parameters.dataType = deflect::DataType::jpeg; - segment.imageData = - QByteArray::fromRawData(jpegData.data(), jpegData.size()); - - deflect::server::SegmentDecoder decoder; - BOOST_CHECK_EQUAL(decoder.decodeType(segment), expected); - - decoder.decodeToYUV(segment); - BOOST_CHECK_NE(segment.parameters.dataType, deflect::DataType::jpeg); - BOOST_CHECK_NE(segment.parameters.dataType, deflect::DataType::rgba); - return segment.imageData; + deflect::server::Tile tile; + tile.width = 8; + tile.height = 8; + tile.format = deflect::Format::jpeg; + tile.imageData = QByteArray::fromRawData(jpegData.data(), jpegData.size()); + + deflect::server::TileDecoder decoder; + BOOST_CHECK_EQUAL(decoder.decodeType(tile), expected); + + decoder.decodeToYUV(tile); + BOOST_CHECK_NE(tile.format, deflect::Format::jpeg); + BOOST_CHECK_NE(tile.format, deflect::Format::rgba); + return tile.imageData; } using DecodeFunc = @@ -223,11 +223,11 @@ BOOST_AUTO_TEST_CASE(testImageCompressionAndDecompressionYUV) &decodeToYUVWithDecompressor); testImageDecompressionToYUV(deflect::ChromaSubsampling::YUV444, - &decodeToYUVWithSegmentDecoder); + &decodeToYUVWithTileDecoder); testImageDecompressionToYUV(deflect::ChromaSubsampling::YUV422, - &decodeToYUVWithSegmentDecoder); + &decodeToYUVWithTileDecoder); testImageDecompressionToYUV(deflect::ChromaSubsampling::YUV420, - &decodeToYUVWithSegmentDecoder); + &decodeToYUVWithTileDecoder); } #endif @@ -258,22 +258,28 @@ BOOST_AUTO_TEST_CASE(testImageSegmentationWithCompressionAndDecompression) BOOST_REQUIRE_EQUAL(segments.size(), 1); deflect::Segment& segment = segments.front(); - BOOST_REQUIRE_EQUAL(segment.parameters.dataType, deflect::DataType::jpeg); + BOOST_REQUIRE_EQUAL(segment.parameters.format, deflect::Format::jpeg); BOOST_REQUIRE(segment.imageData.size() != (int)data.size()); // Decompress image - deflect::server::SegmentDecoder decoder; - decoder.startDecoding(segment); + deflect::server::Tile tile; + tile.width = segment.parameters.width; + tile.height = segment.parameters.height; + tile.format = segment.parameters.format; + tile.imageData = segment.imageData; + + deflect::server::TileDecoder decoder; + decoder.startDecoding(tile); decoder.waitDecoding(); // Check decoded image in format RGBA - BOOST_REQUIRE_EQUAL(segment.parameters.dataType, deflect::DataType::rgba); - BOOST_REQUIRE_EQUAL(segment.imageData.size(), data.size()); + BOOST_REQUIRE_EQUAL(tile.format, deflect::Format::rgba); + BOOST_REQUIRE_EQUAL(tile.imageData.size(), data.size()); - const char* dataOut = segment.imageData.constData(); + const char* dataOut = tile.imageData.constData(); BOOST_CHECK_EQUAL_COLLECTIONS(data.data(), - data.data() + segment.imageData.size(), - dataOut, dataOut + segment.imageData.size()); + data.data() + tile.imageData.size(), dataOut, + dataOut + tile.imageData.size()); } BOOST_AUTO_TEST_CASE(testDecompressionOfInvalidData) @@ -283,14 +289,14 @@ BOOST_AUTO_TEST_CASE(testDecompressionOfInvalidData) BOOST_CHECK_THROW(decompressor.decompress(invalidJpegData), std::runtime_error); - deflect::Segment segment; - segment.parameters.width = 32; - segment.parameters.height = 32; - segment.imageData = invalidJpegData; + deflect::server::Tile tile; + tile.width = 32; + tile.height = 32; + tile.imageData = invalidJpegData; - deflect::server::SegmentDecoder decoder; - BOOST_CHECK_THROW(decoder.decode(segment), std::runtime_error); + deflect::server::TileDecoder decoder; + BOOST_CHECK_THROW(decoder.decode(tile), std::runtime_error); - BOOST_CHECK_NO_THROW(decoder.startDecoding(segment)); + BOOST_CHECK_NO_THROW(decoder.startDecoding(tile)); BOOST_CHECK_THROW(decoder.waitDecoding(), std::runtime_error); } diff --git a/tests/mock/CMakeLists.txt b/tests/mock/CMakeLists.txt index 45cae91..1f5b8b6 100644 --- a/tests/mock/CMakeLists.txt +++ b/tests/mock/CMakeLists.txt @@ -21,8 +21,8 @@ set(DEFLECTMOCK_SOURCES MockServer.cpp ) -set(DEFLECTMOCK_LINK_LIBRARIES Deflect ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} - Qt5::Core Qt5::Network) +set(DEFLECTMOCK_LINK_LIBRARIES Deflect DeflectServer Qt5::Core Qt5::Network + ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) set(DEFLECTMOCK_INCLUDE_NAME deflect/mock) set(DEFLECTMOCK_OMIT_LIBRARY_HEADER ON) diff --git a/tests/mock/FrameUtils.h b/tests/mock/FrameUtils.h index 9bd93f8..ff41485 100644 --- a/tests/mock/FrameUtils.h +++ b/tests/mock/FrameUtils.h @@ -1,6 +1,6 @@ /*********************************************************************/ -/* Copyright (c) 2017, EPFL/Blue Brain Project */ -/* Raphael Dumusc */ +/* Copyright (c) 2017-2018, EPFL/Blue Brain Project */ +/* Raphael Dumusc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or */ @@ -41,32 +41,31 @@ #include // std::ceil -inline deflect::server::Frame makeTestFrame(int width, int height, - int segmentSize) +inline deflect::server::Frame makeTestFrame(int width, int height, int tileSize) { - const int numSegmentsX = std::ceil((float)width / (float)segmentSize); - const int numSegmentsY = std::ceil((float)height / (float)segmentSize); + const int numTilesX = std::ceil((float)width / (float)tileSize); + const int numTilesY = std::ceil((float)height / (float)tileSize); - const int lastSegmentWidth = - (width % segmentSize) > 0 ? (width % segmentSize) : segmentSize; - const int lastSegmentHeight = - (height % segmentSize) > 0 ? (height % segmentSize) : segmentSize; + const int lastTileWidth = + (width % tileSize) > 0 ? (width % tileSize) : tileSize; + const int lastTileHeight = + (height % tileSize) > 0 ? (height % tileSize) : tileSize; deflect::server::Frame frame; - for (int y = 0; y < numSegmentsY; ++y) + for (int y = 0; y < numTilesY; ++y) { - for (int x = 0; x < numSegmentsX; ++x) + for (int x = 0; x < numTilesX; ++x) { - deflect::Segment segment; - segment.parameters.x = x * segmentSize; - segment.parameters.y = y * segmentSize; - segment.parameters.width = segmentSize; - segment.parameters.height = segmentSize; - if (x == numSegmentsX - 1) - segment.parameters.width = lastSegmentWidth; - if (y == numSegmentsY - 1) - segment.parameters.height = lastSegmentHeight; - frame.segments.push_back(segment); + deflect::server::Tile tile; + tile.x = x * tileSize; + tile.y = y * tileSize; + tile.width = tileSize; + tile.height = tileSize; + if (x == numTilesX - 1) + tile.width = lastTileWidth; + if (y == numTilesY - 1) + tile.height = lastTileHeight; + frame.tiles.push_back(tile); } } return frame; @@ -75,21 +74,18 @@ inline deflect::server::Frame makeTestFrame(int width, int height, inline void compare(const deflect::server::Frame& frame1, const deflect::server::Frame& frame2) { - BOOST_REQUIRE_EQUAL(frame1.segments.size(), frame2.segments.size()); + BOOST_REQUIRE_EQUAL(frame1.tiles.size(), frame2.tiles.size()); - for (size_t i = 0; i < frame1.segments.size(); ++i) + for (size_t i = 0; i < frame1.tiles.size(); ++i) { - const auto& s1 = frame1.segments[i]; - const auto& s2 = frame2.segments[i]; - BOOST_CHECK(s1.view == s2.view); - BOOST_CHECK(s1.rowOrder == s2.rowOrder); - - const auto& p1 = s1.parameters; - const auto& p2 = s2.parameters; - BOOST_CHECK_EQUAL(p1.x, p2.x); - BOOST_CHECK_EQUAL(p1.y, p2.y); - BOOST_CHECK_EQUAL(p1.width, p2.width); - BOOST_CHECK_EQUAL(p1.height, p2.height); + const auto& t1 = frame1.tiles[i]; + const auto& t2 = frame2.tiles[i]; + BOOST_CHECK(t1.view == t2.view); + BOOST_CHECK(t1.rowOrder == t2.rowOrder); + BOOST_CHECK_EQUAL(t1.x, t2.x); + BOOST_CHECK_EQUAL(t1.y, t2.y); + BOOST_CHECK_EQUAL(t1.width, t2.width); + BOOST_CHECK_EQUAL(t1.height, t2.height); } } From ce40e41c28d5151bff979f1eacc5e00a0f0b2204 Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Thu, 3 May 2018 14:10:24 +0200 Subject: [PATCH 4/4] Made Qt5::Network dependency private --- deflect/server/CMakeLists.txt | 2 +- deflect/server/Server.cpp | 153 +++++++++++++++++++--------------- deflect/server/Server.h | 13 +-- tests/mock/DeflectServer.h | 5 +- 4 files changed, 95 insertions(+), 78 deletions(-) diff --git a/deflect/server/CMakeLists.txt b/deflect/server/CMakeLists.txt index 99594cd..f05dd32 100644 --- a/deflect/server/CMakeLists.txt +++ b/deflect/server/CMakeLists.txt @@ -25,7 +25,7 @@ set(DEFLECTSERVER_SOURCES ) set(DEFLECTSERVER_LINK_LIBRARIES - PUBLIC Deflect Qt5::Core Qt5::Network + PUBLIC Deflect Qt5::Core PRIVATE Qt5::Network ) if(DEFLECT_USE_LIBJPEGTURBO) diff --git a/deflect/server/Server.cpp b/deflect/server/Server.cpp index fc56a68..8f57742 100644 --- a/deflect/server/Server.cpp +++ b/deflect/server/Server.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Daniel.Nachbaur@epfl.ch */ /* All rights reserved. */ @@ -44,8 +44,9 @@ #include "ServerWorker.h" #include "deflect/NetworkProtocol.h" -#include #include +#include +#include #include @@ -55,30 +56,90 @@ namespace server { const int Server::defaultPortNumber = DEFAULT_PORT_NUMBER; -class Server::Impl +class Server::Impl : public QTcpServer { public: - Impl(QObject* parent) - : frameDispatcher( - new FrameDispatcher(parent)) // will be deleted by parent + Impl(const int port, Server* parent_) + : QTcpServer(parent_) + , server{parent_} + , frameDispatcher{new FrameDispatcher{parent_}} { + setProxy(QNetworkProxy::NoProxy); + if (!listen(QHostAddress::Any, port)) + { + const auto err = + QString("could not listen on port: %1. QTcpServer: %2") + .arg(port) + .arg(QTcpServer::errorString()); + throw std::runtime_error(err.toStdString()); + } } - FrameDispatcher* frameDispatcher; -}; + ~Impl() + { + for (auto child : children()) + { + if (auto workerThread = qobject_cast(child)) + { + workerThread->quit(); + workerThread->wait(); + } + } + } -Server::Server(const int port) - : _impl(new Impl(this)) -{ - setProxy(QNetworkProxy::NoProxy); - if (!listen(QHostAddress::Any, port)) + /** Re-implemented handling of connections from QTCPSocket. */ + void incomingConnection(const qintptr socketHandle) final { - const auto err = QString("could not listen on port: %1. QTcpServer: %2") - .arg(port) - .arg(QTcpServer::errorString()); - throw std::runtime_error(err.toStdString()); + auto workerThread = new QThread(this); + auto worker = new ServerWorker(socketHandle); + + worker->moveToThread(workerThread); + + connect(workerThread, &QThread::started, worker, + &ServerWorker::initConnection); + connect(worker, &ServerWorker::connectionClosed, workerThread, + &QThread::quit); + + // Make sure the thread will be deleted + connect(workerThread, &QThread::finished, worker, + &ServerWorker::deleteLater); + connect(workerThread, &QThread::finished, workerThread, + &QThread::deleteLater); + + // public signals/slots, forwarding from/to worker + connect(worker, &ServerWorker::registerToEvents, server, + &Server::registerToEvents); + connect(worker, &ServerWorker::receivedSizeHints, server, + &Server::receivedSizeHints); + connect(worker, &ServerWorker::receivedData, server, + &Server::receivedData); + connect(server, &Server::_closePixelStream, worker, + &ServerWorker::closeConnection); + + // FrameDispatcher + connect(worker, &ServerWorker::addStreamSource, frameDispatcher, + &FrameDispatcher::addSource); + connect(worker, &ServerWorker::receivedTile, frameDispatcher, + &FrameDispatcher::processTile); + connect(worker, &ServerWorker::receivedFrameFinished, frameDispatcher, + &FrameDispatcher::processFrameFinished); + connect(worker, &ServerWorker::removeStreamSource, frameDispatcher, + &FrameDispatcher::removeSource); + connect(worker, &ServerWorker::addObserver, frameDispatcher, + &FrameDispatcher::addObserver); + connect(worker, &ServerWorker::removeObserver, frameDispatcher, + &FrameDispatcher::removeObserver); + + workerThread->start(); } + Server* server = nullptr; + FrameDispatcher* frameDispatcher = nullptr; // owned by QObject's parent +}; + +Server::Server(const int port) + : _impl(new Impl(port, this)) +{ // Forward FrameDispatcher signals connect(_impl->frameDispatcher, &FrameDispatcher::pixelStreamOpened, this, &Server::pixelStreamOpened); @@ -95,14 +156,12 @@ Server::Server(const int port) Server::~Server() { - for (QObject* child : children()) - { - if (QThread* workerThread = qobject_cast(child)) - { - workerThread->quit(); - workerThread->wait(); - } - } + _impl.release(); // avoid double-deletion of child QObject +} + +quint16 Server::getPort() const +{ + return _impl->serverPort(); } void Server::requestFrame(const QString uri) @@ -115,49 +174,5 @@ void Server::closePixelStream(const QString uri) emit _closePixelStream(uri); _impl->frameDispatcher->deleteStream(uri); } - -void Server::incomingConnection(const qintptr socketHandle) -{ - QThread* workerThread = new QThread(this); - ServerWorker* worker = new ServerWorker(socketHandle); - - worker->moveToThread(workerThread); - - connect(workerThread, &QThread::started, worker, - &ServerWorker::initConnection); - connect(worker, &ServerWorker::connectionClosed, workerThread, - &QThread::quit); - - // Make sure the thread will be deleted - connect(workerThread, &QThread::finished, worker, - &ServerWorker::deleteLater); - connect(workerThread, &QThread::finished, workerThread, - &QThread::deleteLater); - - // public signals/slots, forwarding from/to worker - connect(worker, &ServerWorker::registerToEvents, this, - &Server::registerToEvents); - connect(worker, &ServerWorker::receivedSizeHints, this, - &Server::receivedSizeHints); - connect(worker, &ServerWorker::receivedData, this, &Server::receivedData); - connect(this, &Server::_closePixelStream, worker, - &ServerWorker::closeConnection); - - // FrameDispatcher - connect(worker, &ServerWorker::addStreamSource, _impl->frameDispatcher, - &FrameDispatcher::addSource); - connect(worker, &ServerWorker::receivedTile, _impl->frameDispatcher, - &FrameDispatcher::processTile); - connect(worker, &ServerWorker::receivedFrameFinished, - _impl->frameDispatcher, &FrameDispatcher::processFrameFinished); - connect(worker, &ServerWorker::removeStreamSource, _impl->frameDispatcher, - &FrameDispatcher::removeSource); - connect(worker, &ServerWorker::addObserver, _impl->frameDispatcher, - &FrameDispatcher::addObserver); - connect(worker, &ServerWorker::removeObserver, _impl->frameDispatcher, - &FrameDispatcher::removeObserver); - - workerThread->start(); -} } } diff --git a/deflect/server/Server.h b/deflect/server/Server.h index 7bd17b3..ad7c392 100644 --- a/deflect/server/Server.h +++ b/deflect/server/Server.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013-2017, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2018, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* Daniel.Nachbaur@epfl.ch */ /* All rights reserved. */ @@ -45,7 +45,7 @@ #include #include -#include +#include namespace deflect { @@ -59,7 +59,7 @@ namespace server * The server integrates a flow-control mechanism to ensure that new frames are * dispatched only as fast as the application is capable of processing them. */ -class DEFLECT_API Server : public QTcpServer +class DEFLECT_API Server : public QObject { Q_OBJECT @@ -78,6 +78,9 @@ class DEFLECT_API Server : public QTcpServer /** Stop the server and close all open pixel stream connections. */ ~Server(); + /** @return the port on which the server is running. */ + quint16 getPort() const; + public slots: /** * Request the dispatching of the next frame for a given pixel stream. @@ -166,10 +169,8 @@ public slots: class Impl; std::unique_ptr _impl; - /** Re-implemented handling of connections from QTCPSocket. */ - void incomingConnection(qintptr socketHandle) final; - signals: + /** @internal */ void _closePixelStream(QString uri); }; } diff --git a/tests/mock/DeflectServer.h b/tests/mock/DeflectServer.h index 55d114e..6273386 100644 --- a/tests/mock/DeflectServer.h +++ b/tests/mock/DeflectServer.h @@ -57,7 +57,7 @@ class DeflectServer explicit DeflectServer(); ~DeflectServer(); - quint16 serverPort() const { return _server->serverPort(); } + quint16 serverPort() const { return _server->getPort(); } void requestFrame(QString uri) { _server->requestFrame(uri); } void waitForMessage(); @@ -95,7 +95,8 @@ class DeflectServer private: QThread _thread; - deflect::server::Server* _server; + // destroyed by Object::deleteLater + deflect::server::Server* _server = nullptr; bool _receivedState{false}; QWaitCondition _received;