diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a6cb1152496a1a34ad41e0631195457ade43a1d..3b073fbbc83639e3661228c7745902d2a0134856 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ ADD_DEFINITIONS("-std=c++1y") ADD_DEFINITIONS( ${QT_DEFINITIONS} -fexceptions + -O2 ) PROJECT(ringclient) diff --git a/src/private/directrenderer.cpp b/src/private/directrenderer.cpp index a5a2d78d296e2c8bdb8aa7added8d873c91297f9..6fcb1bcb128185621c3e719e0e9762831de35483 100644 --- a/src/private/directrenderer.cpp +++ b/src/private/directrenderer.cpp @@ -40,17 +40,13 @@ class DirectRendererPrivate : public QObject Q_OBJECT public: DirectRendererPrivate(Video::DirectRenderer* parent); - - //Attributes - private: - Video::DirectRenderer* q_ptr; - +// Video::DirectRenderer* q_ptr; }; } -Video::DirectRendererPrivate::DirectRendererPrivate(Video::DirectRenderer* parent) : QObject(parent), q_ptr(parent) +Video::DirectRendererPrivate::DirectRendererPrivate(Video::DirectRenderer* parent) : QObject(parent)/*, q_ptr(parent)*/ { } @@ -67,29 +63,30 @@ Video::DirectRenderer::~DirectRenderer() void Video::DirectRenderer::startRendering() { - - qWarning() << "STARTING RENDERING"; - setRendering(true); - emit started(); + qWarning() << "STARTING RENDERING"; + Video::Renderer::d_ptr->m_isRendering = true; + emit started(); } void Video::DirectRenderer::stopRendering () { - qWarning() << "STOPPING RENDERING"; - setRendering(false); - emit stopped(); + qWarning() << "STOPPING RENDERING"; + Video::Renderer::d_ptr->m_isRendering = false; + emit stopped(); } void Video::DirectRenderer::onNewFrame(const QByteArray& frame) { -// qDebug("Frame received by DirectRenderer, size: w %d, h %d", size().width(), size().height()); - if (!isRendering()) { - return; - } - if (static_cast<Video::Renderer*>(this)->d_ptr->otherFrame().size() != (size().height() * size().width())) - static_cast<Video::Renderer*>(this)->d_ptr->otherFrame().resize(size().height() * size().width()*4); - ::memcpy(static_cast<Video::Renderer*>(this)->d_ptr->otherFrame().data(),frame,static_cast<Video::Renderer*>(this)->d_ptr->otherFrame().size()); - static_cast<Video::Renderer*>(this)->d_ptr->updateFrameIndex(); - emit frameUpdated(); + if (!isRendering()) { + return; + } + + Video::Renderer::d_ptr->m_pFrame = const_cast<char*>(frame.data()); + emit frameUpdated(); +} + +Video::Renderer::ColorSpace Video::DirectRenderer::colorSpace() const +{ + return Video::Renderer::ColorSpace::RGBA; } #include <directrenderer.moc> diff --git a/src/private/directrenderer.h b/src/private/directrenderer.h index a71fb06b25a66e5c472ab9bd76da6a5a8bb49f39..db6a2d99dfc528d24a4acb5dbfffa3b55d7d8904 100644 --- a/src/private/directrenderer.h +++ b/src/private/directrenderer.h @@ -42,21 +42,24 @@ class LIB_EXPORT DirectRenderer : public Renderer { Q_OBJECT #pragma GCC diagnostic pop - public: +public: - //Constructor - DirectRenderer (const QByteArray& id, const QSize& res); - virtual ~DirectRenderer(); + //Constructor + DirectRenderer (const QByteArray& id, const QSize& res); + virtual ~DirectRenderer(); - void onNewFrame(const QByteArray& frame); + //Getter + virtual ColorSpace colorSpace() const override; - public Q_SLOTS: - virtual void startRendering() override; - virtual void stopRendering () override; + void onNewFrame(const QByteArray& frame); - private: - QScopedPointer<DirectRendererPrivate> d_ptr; - Q_DECLARE_PRIVATE(DirectRenderer) +public Q_SLOTS: + virtual void startRendering() override; + virtual void stopRendering () override; + +private: + QScopedPointer<DirectRendererPrivate> d_ptr; + Q_DECLARE_PRIVATE(DirectRenderer) }; diff --git a/src/private/shmrenderer.cpp b/src/private/shmrenderer.cpp index 13e7d63af4fd02f354c79135e98e3972687a3d59..7a422ac4b16d542aba6543f32babb15c3c130c45 100644 --- a/src/private/shmrenderer.cpp +++ b/src/private/shmrenderer.cpp @@ -1,6 +1,7 @@ /**************************************************************************** * Copyright (C) 2012-2015 by Savoir-Faire Linux * * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * @@ -20,7 +21,6 @@ #include <QtCore/QDebug> #include <QtCore/QMutex> #include <QtCore/QThread> -#include <QtCore/QTime> #include <sys/ipc.h> #include <sys/sem.h> @@ -36,28 +36,35 @@ #endif #include <QtCore/QTimer> +#include <chrono> + #include "private/videorenderermanager.h" #include "video/resolution.h" #include "private/videorenderer_p.h" +// Uncomment following line to output in console the FPS value //#define DEBUG_FPS -#ifdef DEBUG_FPS -#include <chrono> -#endif -///Shared memory object -struct SHMHeader { - sem_t notification; - sem_t mutex; +/* Shared memory object + * Implementation note: double-buffering + * Shared memory is divided in two regions, each representing one frame. + * First byte of each frame is warranted to by aligned on 16 bytes. + * One region is marked readable: this region can be safely read. + * The other region is writeable: only the producer can use it. + */ - unsigned m_BufferGen; - int m_BufferSize; - /* The header will be aligned on 16-byte boundaries */ - char padding[8]; +struct SHMHeader { + sem_t mutex ; /*!< Lock it before any operations on following fields. */ + sem_t frameGenMutex; /*!< unlocked by producer when frameGen modified */ + unsigned frameGen ; /*!< monotonically incremented when a producer changes readOffset */ + unsigned frameSize ; /*!< size in bytes of 1 frame */ + unsigned mapSize ; /*!< size to map if you need to see all data */ + unsigned readOffset ; /*!< offset of readable frame in data */ + unsigned writeOffset ; /*!< offset of writable frame in data */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-pedantic" - char m_Data[]; + char data[]; /*!< the whole shared memory */ #pragma GCC diagnostic pop }; @@ -66,312 +73,287 @@ namespace Video { class ShmRendererPrivate : public QObject { Q_OBJECT -public: - ShmRendererPrivate(Video::ShmRenderer* parent); - - //Attributes - QString m_ShmPath ; - int fd ; - SHMHeader* m_pShmArea ; - signed int m_ShmAreaLen ; - uint m_BufferGen ; - QTimer* m_pTimer ; - int m_fpsC ; - int m_Fps ; - QTime m_CurrentTime; - -#ifdef DEBUG_FPS - unsigned m_frameCount; - std::chrono::time_point<std::chrono::system_clock> m_lastFrameDebug; -#endif - //Constants - static const int TIMEOUT_SEC = 1; // 1 second - - //Helpers - timespec createTimeout(); - bool shmLock (); - void shmUnlock (); - bool renderToBitmap(); +public: + ShmRendererPrivate(ShmRenderer* parent); + + //Types + using TimePoint = std::chrono::time_point<std::chrono::system_clock>; + + // Attributes + QString m_ShmPath ; + int m_fd ; + SHMHeader* m_pShmArea ; + unsigned m_ShmAreaLen ; + uint m_FrameGen ; + int m_fpsC ; + int m_Fps ; + TimePoint m_lastFrameDebug; + + // Constants + constexpr static const int FPS_RATE_SEC = 1 ; + constexpr static const int FRAME_CHECK_RATE_HZ = 120; + + // Helpers + timespec createTimeout( ); + bool shmLock ( ); + void shmUnlock ( ); + bool getNewFrame ( bool wait ); + bool remapShm ( ); private: Video::ShmRenderer* q_ptr; - -private Q_SLOTS: - void timedEvents(); }; -} - -Video::ShmRendererPrivate::ShmRendererPrivate(Video::ShmRenderer* parent) : QObject(parent), q_ptr(parent), - fd(-1),m_fpsC(0),m_Fps(0), - m_pShmArea((SHMHeader*)MAP_FAILED), m_ShmAreaLen(0), m_BufferGen(0), - m_pTimer(nullptr) +ShmRendererPrivate::ShmRendererPrivate(ShmRenderer* parent) + : QObject ( parent ) + , q_ptr ( parent ) + , m_fd ( -1 ) + , m_fpsC ( 0 ) + , m_Fps ( 0 ) + , m_pShmArea ( (SHMHeader*)MAP_FAILED ) + , m_ShmAreaLen( 0 ) + , m_FrameGen ( 0 ) #ifdef DEBUG_FPS - , m_frameCount(0) - , m_lastFrameDebug(std::chrono::system_clock::now()) + , m_frameCount( 0 ) + , m_lastFrameDebug(std::chrono::system_clock::now() ) #endif { } -///Constructor -Video::ShmRenderer::ShmRenderer(const QByteArray& id, const QString& shmPath, const QSize& res): Renderer(id, res), d_ptr(new ShmRendererPrivate(this)) +/// Constructor +ShmRenderer::ShmRenderer(const QByteArray& id, const QString& shmPath, const QSize& res) + : Renderer(id, res) + , d_ptr(new ShmRendererPrivate(this)) { d_ptr->m_ShmPath = shmPath; setObjectName("Video::Renderer:"+id); } -///Destructor -Video::ShmRenderer::~ShmRenderer() +/// Destructor +ShmRenderer::~ShmRenderer() { stopShm(); - //delete m_pShmArea; } -///Get the data from shared memory and transform it into a QByteArray -bool Video::ShmRendererPrivate::renderToBitmap() +/// Wait new frame data from shared memory and save pointer +bool ShmRendererPrivate::getNewFrame(bool wait) { - QMutexLocker locker {q_ptr->mutex()}; - -#ifdef Q_OS_LINUX - if (!q_ptr->isRendering()) - return false; - if (!shmLock()) return false; - if (m_BufferGen == m_pShmArea->m_BufferGen) { - // wait for a new buffer - do { - shmUnlock(); - auto err = sem_trywait(&m_pShmArea->notification); - if (!err) - break; + if (m_FrameGen == m_pShmArea->frameGen) { + shmUnlock(); - // Fatal error? - if (errno != EAGAIN) - return false; + if (not wait) + return false; - // wait a little bit that deamon does its work - usleep(10); // must be less than the maximal framerate possible + // wait for a new frame, max 33ms + static const struct timespec timeout = {0, 33000000}; + if (::sem_timedwait(&m_pShmArea->frameGenMutex, &timeout) < 0) + return false; - // stopRendering called? - if (!q_ptr->isRendering()) - return false; - } while (m_BufferGen == m_pShmArea->m_BufferGen); + if (!shmLock()) + return false; - if (!shmLock()) - return false; } - if (!q_ptr->resizeShm()) { + // valid frame to render (daemon may have stopped)? + if (! m_pShmArea->frameSize) { + shmUnlock(); + return false; + } + + // map frame data + if (!remapShm()) { qDebug() << "Could not resize shared memory"; - shmUnlock(); return false; } - if (static_cast<Video::Renderer*>(q_ptr)->d_ptr->otherFrame().size() != m_pShmArea->m_BufferSize) - static_cast<Video::Renderer*>(q_ptr)->d_ptr->otherFrame().resize(m_pShmArea->m_BufferSize); - memcpy(static_cast<Video::Renderer*>(q_ptr)->d_ptr->otherFrame().data(),m_pShmArea->m_Data,m_pShmArea->m_BufferSize); - m_BufferGen = m_pShmArea->m_BufferGen; - static_cast<Video::Renderer*>(q_ptr)->d_ptr->updateFrameIndex(); + q_ptr->Video::Renderer::d_ptr->m_pFrame = (char*)(m_pShmArea->data + m_pShmArea->readOffset); + m_FrameGen = m_pShmArea->frameGen; + q_ptr->Video::Renderer::d_ptr->m_FrameSize = m_pShmArea->frameSize; + shmUnlock(); + ++m_fpsC; + + // Compute the FPS shown to the client + auto currentTime = std::chrono::system_clock::now(); + const std::chrono::duration<double> seconds = currentTime - m_lastFrameDebug; + if (seconds.count() >= FPS_RATE_SEC) { + m_Fps = m_fpsC / seconds.count(); + m_fpsC = 0; + m_lastFrameDebug = currentTime; #ifdef DEBUG_FPS - auto currentTime = std::chrono::system_clock::now(); - const std::chrono::duration<double> seconds = currentTime - m_lastFrameDebug; - ++m_frameCount; - if (seconds.count() > 1) { - qDebug() << this << ": FPS " << (m_frameCount / seconds.count()); - m_frameCount = 0; - m_lastFrameDebug = currentTime; - } + qDebug() << this << ": FPS " << m_fps; #endif + } + emit q_ptr->frameUpdated(); return true; -#else - return false; -#endif } -///Connect to the shared memory -bool Video::ShmRenderer::startShm() +/// Remap the shared memory +/// Shared memory in unlocked state if returns false (resize failed). +bool ShmRendererPrivate::remapShm() { - if (d_ptr->fd != -1) { + // This loop handles case where deamon resize shared memory + // during time we unlock it for remapping. + while (m_ShmAreaLen != m_pShmArea->mapSize) { + auto mapSize = m_pShmArea->mapSize; + shmUnlock(); + + if (::munmap(m_pShmArea, m_ShmAreaLen)) { + qDebug() << "Could not unmap shared area: " << strerror(errno); + return false; + } + + m_pShmArea = (SHMHeader*) ::mmap(nullptr, mapSize, PROT_READ | PROT_WRITE, + MAP_SHARED, m_fd, 0); + + if (m_pShmArea == MAP_FAILED) { + qDebug() << "Could not remap shared area: " << strerror(errno); + return false; + } + + if (!shmLock()) + return false; + + m_ShmAreaLen = mapSize; + } + + return true; +} + +/// Connect to the shared memory +bool ShmRenderer::startShm() +{ + if (d_ptr->m_fd != -1) { qDebug() << "fd must be -1"; return false; } - d_ptr->fd = shm_open(d_ptr->m_ShmPath.toLatin1(), O_RDWR, 0); - if (d_ptr->fd < 0) { - qDebug() << "could not open shm area " << d_ptr->m_ShmPath << ", shm_open failed:" << strerror(errno); + d_ptr->m_fd = ::shm_open(d_ptr->m_ShmPath.toLatin1(), O_RDWR, 0); + + if (d_ptr->m_fd < 0) { + qDebug() << "could not open shm area" << d_ptr->m_ShmPath + << ", shm_open failed:" << strerror(errno); return false; } - d_ptr->m_ShmAreaLen = sizeof(SHMHeader); - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - d_ptr->m_pShmArea = (SHMHeader*) mmap(NULL, d_ptr->m_ShmAreaLen, PROT_READ | PROT_WRITE, MAP_SHARED, d_ptr->fd, 0); - #pragma GCC diagnostic pop + + // Map only header data + const auto mapSize = sizeof(SHMHeader); + d_ptr->m_pShmArea = (SHMHeader*) ::mmap(nullptr, mapSize, + PROT_READ | PROT_WRITE, + MAP_SHARED, d_ptr->m_fd, 0 + ); + if (d_ptr->m_pShmArea == MAP_FAILED) { - qDebug() << "Could not map shm area, mmap failed"; + qDebug() << "Could not remap shared area"; return false; } - emit started(); - return true; -} - -///Disconnect from the shared memory -void Video::ShmRenderer::stopShm() -{ - if (d_ptr->fd >= 0) - close(d_ptr->fd); - d_ptr->fd = -1; - if (d_ptr->m_pShmArea != MAP_FAILED) - munmap(d_ptr->m_pShmArea, d_ptr->m_ShmAreaLen); - d_ptr->m_ShmAreaLen = 0; - d_ptr->m_pShmArea = (SHMHeader*) MAP_FAILED; + d_ptr->m_ShmAreaLen = mapSize; + return true; } -///Resize the shared memory -bool Video::ShmRenderer::resizeShm() +/// Disconnect from the shared memory +void ShmRenderer::stopShm() { - while (( (unsigned int) sizeof(SHMHeader) + (unsigned int) d_ptr->m_pShmArea->m_BufferSize) > (unsigned int) d_ptr->m_ShmAreaLen) { - const size_t new_size = sizeof(SHMHeader) + d_ptr->m_pShmArea->m_BufferSize; - - d_ptr->shmUnlock(); - if (munmap(d_ptr->m_pShmArea, d_ptr->m_ShmAreaLen)) { - qDebug() << "Could not unmap shared area:" << strerror(errno); - return false; - } + if (d_ptr->m_fd < 0) + return; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - d_ptr->m_pShmArea = (SHMHeader*) mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, d_ptr->fd, 0); - #pragma GCC diagnostic pop - d_ptr->m_ShmAreaLen = new_size; + ::close(d_ptr->m_fd); + d_ptr->m_fd = -1; - if (!d_ptr->m_pShmArea) { - d_ptr->m_pShmArea = nullptr; - qDebug() << "Could not remap shared area"; - return false; - } + if (d_ptr->m_pShmArea == MAP_FAILED) + return; - d_ptr->m_ShmAreaLen = new_size; - if (!d_ptr->shmLock()) - return true; - } - return true; + ::munmap(d_ptr->m_pShmArea, d_ptr->m_ShmAreaLen); + d_ptr->m_ShmAreaLen = 0; + d_ptr->m_pShmArea = (SHMHeader*) MAP_FAILED; } -///Lock the memory while the copy is being made -bool Video::ShmRendererPrivate::shmLock() +/// Lock the memory while the copy is being made +bool ShmRendererPrivate::shmLock() { -#ifdef Q_OS_LINUX - return sem_trywait(&m_pShmArea->mutex) >= 0; -#else - return false; -#endif + return ::sem_wait(&m_pShmArea->mutex) >= 0; } -///Remove the lock, allow a new frame to be drawn -void Video::ShmRendererPrivate::shmUnlock() +/// Remove the lock, allow a new frame to be drawn +void ShmRendererPrivate::shmUnlock() { -#ifdef Q_OS_LINUX - sem_post(&m_pShmArea->mutex); -#endif + ::sem_post(&m_pShmArea->mutex); } - /***************************************************************************** * * * Slots * * * ****************************************************************************/ -///Update the buffer -void Video::ShmRendererPrivate::timedEvents() -{ - if (renderToBitmap()) { - //Compute the FPS shown to the client - if (m_CurrentTime.second() != QTime::currentTime().second()) { - m_Fps = m_fpsC; - m_fpsC=0; - m_CurrentTime = QTime::currentTime(); - } - m_fpsC++; - - emit q_ptr->frameUpdated(); - } - /*else { - qDebug() << "Frame dropped"; - usleep(rand()%1000); //Be sure it can come back in sync - }*/ -} - -///Start the rendering loop -void Video::ShmRenderer::startRendering() +/// Start the rendering loop +void ShmRenderer::startRendering() { QMutexLocker locker {mutex()}; - if (!startShm()) { - qDebug() << "Cannot start rendering on " << d_ptr->m_ShmPath; + if (!startShm()) return; - } - - if (!d_ptr->m_pTimer) { - d_ptr->m_pTimer = new QTimer(nullptr); -// m_pTimer->moveToThread(thread()); - connect(d_ptr->m_pTimer,SIGNAL(timeout()),d_ptr.data(),SLOT(timedEvents())); - d_ptr->m_pTimer->setInterval(30); - } - - if (!d_ptr->m_pTimer->isActive()) { - qDebug() << "Is running" << thread()->isRunning(); - d_ptr->m_pTimer->start(); - } - else - qDebug() << "Timer already started!"; - - setRendering(true); + Video::Renderer::d_ptr->m_isRendering = true; + emit started(); } -///Stop the rendering loop -void Video::ShmRenderer::stopRendering() +/// Stop the rendering loop +void ShmRenderer::stopRendering() { - setRendering(false); - QMutexLocker locker {mutex()}; - qDebug() << "Stopping rendering on" << this; - if (d_ptr->m_pTimer) - d_ptr->m_pTimer->stop(); + Video::Renderer::d_ptr->m_isRendering = false; + emit stopped(); stopShm(); } - /***************************************************************************** * * * Getters * * * ****************************************************************************/ -///Get the current frame rate of this renderer -int Video::ShmRenderer::fps() const +/// Get the current frame rate of this renderer +int ShmRenderer::fps() const { return d_ptr->m_Fps; } +/// Get frame data pointer from shared memory +const QByteArray& ShmRenderer::currentFrame() const +{ + if (!isRendering()) + return Renderer::currentFrame(); + + QMutexLocker lk {mutex()}; + d_ptr->getNewFrame(false); + return Renderer::currentFrame(); +} + +Video::Renderer::ColorSpace ShmRenderer::colorSpace() const +{ + return Video::Renderer::ColorSpace::BGRA; +} + /***************************************************************************** * * * Setters * * * ****************************************************************************/ -void Video::ShmRenderer::setShmPath(const QString& path) +void ShmRenderer::setShmPath(const QString& path) { d_ptr->m_ShmPath = path; } +} // namespace Video + #include <shmrenderer.moc> diff --git a/src/private/shmrenderer.h b/src/private/shmrenderer.h index 39bb2669c44a6ca3eb662471a107c779bfb928da..63e042d209db3533dddd353ae8996752baaa376b 100644 --- a/src/private/shmrenderer.h +++ b/src/private/shmrenderer.h @@ -42,32 +42,32 @@ class LIB_EXPORT ShmRenderer : public Renderer { Q_OBJECT #pragma GCC diagnostic pop - public: - //Constructor - ShmRenderer (const QByteArray& id, const QString& shmPath, const QSize& res); - virtual ~ShmRenderer(); + friend class VideoRendererManagerPrivate ; - //Mutators - bool resizeShm(); - void stopShm (); - bool startShm (); +public: + //Constructor + ShmRenderer (const QByteArray& id, const QString& shmPath, const QSize& res); + virtual ~ShmRenderer(); - //Getters - virtual int fps () const ; + //Mutators + void stopShm (); + bool startShm (); - //Setters - void setShmPath (const QString& path); - - private: - QScopedPointer<ShmRendererPrivate> d_ptr; - Q_DECLARE_PRIVATE(ShmRenderer) - - public Q_SLOTS: - void startRendering(); - void stopRendering (); + //Getters + int fps() const; + virtual const QByteArray& currentFrame() const override; + virtual ColorSpace colorSpace () const override; + //Setters + void setShmPath(const QString& path); +private: + QScopedPointer<ShmRendererPrivate> d_ptr; + Q_DECLARE_PRIVATE(ShmRenderer) +public Q_SLOTS: + void startRendering(); + void stopRendering (); }; } diff --git a/src/private/videorenderer_p.h b/src/private/videorenderer_p.h index 6770d5e57ec07b296a3e90936fb309d6d364446c..27d574ee569cc5b4f885b76abc8207a76d7cf214 100644 --- a/src/private/videorenderer_p.h +++ b/src/private/videorenderer_p.h @@ -38,15 +38,12 @@ public: //Attributes std::atomic_bool m_isRendering; - QByteArray m_Frame[2] ; - bool m_FrameIdx ; QMutex* m_pMutex ; QString m_Id ; QSize m_pSize ; - - //Helpers - QByteArray& otherFrame () ; - void updateFrameIndex () ; + char* m_pFrame ; + QByteArray m_Content ; + unsigned int m_FrameSize ; private: Video::Renderer* q_ptr; diff --git a/src/private/videorenderermanager.cpp b/src/private/videorenderermanager.cpp index 602404cf64f4c15f00eebb867e0cfa097c654c98..309beb52f7a5410a26da006a3c5f9bd6d6b1b113 100644 --- a/src/private/videorenderermanager.cpp +++ b/src/private/videorenderermanager.cpp @@ -36,6 +36,7 @@ #include <video/resolution.h> #include "private/videorate_p.h" #include "private/call_p.h" +#include "private/videorenderer_p.h" #ifdef ENABLE_LIBWRAP #include "private/directrenderer.h" diff --git a/src/private/videorenderermanager.h b/src/private/videorenderermanager.h index 9e0edb325a7d0bac176ea65ef86aa971160f16d4..2cf14aedb4ec1599aba3fa61ec0c913936f5bbb1 100644 --- a/src/private/videorenderermanager.h +++ b/src/private/videorenderermanager.h @@ -37,7 +37,8 @@ struct SHMHeader; class VideoRendererManagerPrivate; ///VideoModel: Video event dispatcher -class VideoRendererManager : public QObject { +class VideoRendererManager : public QObject +{ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" Q_OBJECT diff --git a/src/video/renderer.cpp b/src/video/renderer.cpp index d6ae913a60010fc6d8b6a4e108789ee2cfec4615..e67668e196bf0f8631c78d04f96ebba7d292fcf3 100644 --- a/src/video/renderer.cpp +++ b/src/video/renderer.cpp @@ -23,20 +23,24 @@ //Qt #include <QtCore/QMutex> -Video::RendererPrivate::RendererPrivate(Video::Renderer* parent) : QObject(parent), q_ptr(parent), -m_pMutex(new QMutex()), m_FrameIdx(false) +Video::RendererPrivate::RendererPrivate(Video::Renderer* parent) + : QObject(parent), q_ptr(parent) + , m_pMutex(new QMutex()),m_pFrame(nullptr),m_FrameSize(0),m_isRendering(false) { } Video::Renderer::Renderer(const QByteArray& id, const QSize& res) : d_ptr(new RendererPrivate(this)) { setObjectName("Renderer:"+id); - d_ptr->m_pSize = res; - d_ptr->m_Id = id; + d_ptr->m_FrameSize = res.width() * res.height() * 4; + d_ptr->m_pSize = res; + d_ptr->m_Id = id; } Video::Renderer::~Renderer() -{} +{ + delete d_ptr; +} /***************************************************************************** * * @@ -44,24 +48,12 @@ Video::Renderer::~Renderer() * * ****************************************************************************/ +///Return if the rendering is currently active or not bool Video::Renderer::isRendering() const { return d_ptr->m_isRendering; } -QByteArray& Video::RendererPrivate::otherFrame() -{ - static QByteArray empty; - return q_ptr->isRendering()?m_Frame[!m_FrameIdx]:empty; -} - -///Return the current framerate -const QByteArray& Video::Renderer::currentFrame() const -{ - static QByteArray empty; - return isRendering()?d_ptr->m_Frame[d_ptr->m_FrameIdx]:empty; -} - ///Get mutex, in case renderer and views are not in the same thread QMutex* Video::Renderer::mutex() const { @@ -74,26 +66,22 @@ QSize Video::Renderer::size() const return d_ptr->m_pSize; } +const QByteArray& Video::Renderer::currentFrame() const +{ + if (d_ptr->m_pFrame && d_ptr->m_FrameSize) + d_ptr->m_Content.setRawData(d_ptr->m_pFrame,d_ptr->m_FrameSize); + return d_ptr->m_Content; +} + /***************************************************************************** * * * Setters * * * ****************************************************************************/ -///Return the current resolution -void Video::Renderer::setRendering(bool rendering) const -{ - d_ptr->m_isRendering = rendering; -} - void Video::Renderer::setSize(const QSize& size) const { d_ptr->m_pSize = size; } -void Video::RendererPrivate::updateFrameIndex() -{ - m_FrameIdx = !m_FrameIdx; -} - #include <renderer.moc> diff --git a/src/video/renderer.h b/src/video/renderer.h index aa5f6548551fa8cd2ba90ee45abbf85ac9b76854..a2db70f00f71b6b4b569360659f9d7107833e5cd 100644 --- a/src/video/renderer.h +++ b/src/video/renderer.h @@ -33,6 +33,7 @@ namespace Video { class RendererPrivate; class ShmRendererPrivate; +class ShmRenderer; class DirectRendererPrivate; class DirectRenderer; @@ -43,17 +44,30 @@ class DirectRenderer; * * Each platform transparently provide its own implementation. */ -class LIB_EXPORT Renderer : public QObject { +class LIB_EXPORT Renderer : public QObject +{ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" -Q_OBJECT + Q_OBJECT #pragma GCC diagnostic pop -friend class Video::ShmRendererPrivate; -friend class Video::DirectRendererPrivate; -friend class Video::DirectRenderer; + friend class Video::ShmRendererPrivate ; + friend class Video::ShmRenderer ; + friend class Video::DirectRendererPrivate; + friend class Video::DirectRenderer ; + friend class VideoRendererManagerPrivate ; public: + + /** + * Each platform may have its preferred color space. To be able to use a + * client on multiple platforms, they need to check the colorspace. + */ + enum class ColorSpace { + BGRA , /*!< 32bit BLUE GREEN RED ALPHA */ + RGBA , /*!< 32bit ALPHA GREEN RED BLUE */ + }; + //Constructor Renderer (const QByteArray& id, const QSize& res); virtual ~Renderer(); @@ -63,14 +77,12 @@ public: virtual const QByteArray& currentFrame () const; virtual QSize size () const; virtual QMutex* mutex () const; + virtual ColorSpace colorSpace () const = 0; - //Setters - void setRendering(bool rendering) const; - void setSize(const QSize& size) const; + void setSize(const QSize& size) const; Q_SIGNALS: - ///Emitted when a new frame is ready - void frameUpdated(); + void frameUpdated(); // Emitted when a new frame is ready void stopped (); void started (); @@ -78,9 +90,8 @@ public Q_SLOTS: virtual void startRendering() = 0; virtual void stopRendering () = 0; - private: - QScopedPointer<RendererPrivate> d_ptr; + RendererPrivate* d_ptr; Q_DECLARE_PRIVATE(Renderer) };