Skip to content
Snippets Groups Projects
Commit a357a7f6 authored by Guillaume Roguez's avatar Guillaume Roguez
Browse files

video: rendering refactoring

This patch is a re-write of all video rendering related classes:
  - support of daemon double-buffering for shm renderer
  - zero-copy strategy

These modifications bring rendering overhead removal and architecture
simplification.

Refs #70057
parents 0c847df8 41da96a3
Branches
No related tags found
No related merge requests found
...@@ -28,6 +28,7 @@ ADD_DEFINITIONS("-std=c++1y") ...@@ -28,6 +28,7 @@ ADD_DEFINITIONS("-std=c++1y")
ADD_DEFINITIONS( ADD_DEFINITIONS(
${QT_DEFINITIONS} ${QT_DEFINITIONS}
-fexceptions -fexceptions
-O2
) )
PROJECT(ringclient) PROJECT(ringclient)
......
...@@ -40,17 +40,13 @@ class DirectRendererPrivate : public QObject ...@@ -40,17 +40,13 @@ class DirectRendererPrivate : public QObject
Q_OBJECT Q_OBJECT
public: public:
DirectRendererPrivate(Video::DirectRenderer* parent); DirectRendererPrivate(Video::DirectRenderer* parent);
//Attributes
private: 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() ...@@ -67,29 +63,30 @@ Video::DirectRenderer::~DirectRenderer()
void Video::DirectRenderer::startRendering() void Video::DirectRenderer::startRendering()
{ {
qWarning() << "STARTING RENDERING"; qWarning() << "STARTING RENDERING";
setRendering(true); Video::Renderer::d_ptr->m_isRendering = true;
emit started(); emit started();
} }
void Video::DirectRenderer::stopRendering () void Video::DirectRenderer::stopRendering ()
{ {
qWarning() << "STOPPING RENDERING"; qWarning() << "STOPPING RENDERING";
setRendering(false); Video::Renderer::d_ptr->m_isRendering = false;
emit stopped(); emit stopped();
} }
void Video::DirectRenderer::onNewFrame(const QByteArray& frame) void Video::DirectRenderer::onNewFrame(const QByteArray& frame)
{ {
// qDebug("Frame received by DirectRenderer, size: w %d, h %d", size().width(), size().height());
if (!isRendering()) { if (!isRendering()) {
return; 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); Video::Renderer::d_ptr->m_pFrame = const_cast<char*>(frame.data());
::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(); emit frameUpdated();
} }
Video::Renderer::ColorSpace Video::DirectRenderer::colorSpace() const
{
return Video::Renderer::ColorSpace::RGBA;
}
#include <directrenderer.moc> #include <directrenderer.moc>
...@@ -48,6 +48,9 @@ class LIB_EXPORT DirectRenderer : public Renderer { ...@@ -48,6 +48,9 @@ class LIB_EXPORT DirectRenderer : public Renderer {
DirectRenderer (const QByteArray& id, const QSize& res); DirectRenderer (const QByteArray& id, const QSize& res);
virtual ~DirectRenderer(); virtual ~DirectRenderer();
//Getter
virtual ColorSpace colorSpace() const override;
void onNewFrame(const QByteArray& frame); void onNewFrame(const QByteArray& frame);
public Q_SLOTS: public Q_SLOTS:
......
/**************************************************************************** /****************************************************************************
* Copyright (C) 2012-2015 by Savoir-Faire Linux * * Copyright (C) 2012-2015 by Savoir-Faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * * 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 * * This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public * * modify it under the terms of the GNU Lesser General Public *
...@@ -20,7 +21,6 @@ ...@@ -20,7 +21,6 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <QtCore/QTime>
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/sem.h> #include <sys/sem.h>
...@@ -36,28 +36,35 @@ ...@@ -36,28 +36,35 @@
#endif #endif
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <chrono>
#include "private/videorenderermanager.h" #include "private/videorenderermanager.h"
#include "video/resolution.h" #include "video/resolution.h"
#include "private/videorenderer_p.h" #include "private/videorenderer_p.h"
// Uncomment following line to output in console the FPS value
//#define DEBUG_FPS //#define DEBUG_FPS
#ifdef DEBUG_FPS
#include <chrono>
#endif
///Shared memory object /* Shared memory object
struct SHMHeader { * Implementation note: double-buffering
sem_t notification; * Shared memory is divided in two regions, each representing one frame.
sem_t mutex; * 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; struct SHMHeader {
int m_BufferSize; sem_t mutex ; /*!< Lock it before any operations on following fields. */
/* The header will be aligned on 16-byte boundaries */ sem_t frameGenMutex; /*!< unlocked by producer when frameGen modified */
char padding[8]; 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 push
#pragma GCC diagnostic ignored "-pedantic" #pragma GCC diagnostic ignored "-pedantic"
char m_Data[]; char data[]; /*!< the whole shared memory */
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
}; };
...@@ -66,47 +73,47 @@ namespace Video { ...@@ -66,47 +73,47 @@ namespace Video {
class ShmRendererPrivate : public QObject class ShmRendererPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
ShmRendererPrivate(Video::ShmRenderer* parent); ShmRendererPrivate(ShmRenderer* parent);
//Types
using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
// Attributes // Attributes
QString m_ShmPath ; QString m_ShmPath ;
int fd ; int m_fd ;
SHMHeader* m_pShmArea ; SHMHeader* m_pShmArea ;
signed int m_ShmAreaLen ; unsigned m_ShmAreaLen ;
uint m_BufferGen ; uint m_FrameGen ;
QTimer* m_pTimer ;
int m_fpsC ; int m_fpsC ;
int m_Fps ; int m_Fps ;
QTime m_CurrentTime; TimePoint m_lastFrameDebug;
#ifdef DEBUG_FPS
unsigned m_frameCount;
std::chrono::time_point<std::chrono::system_clock> m_lastFrameDebug;
#endif
// Constants // Constants
static const int TIMEOUT_SEC = 1; // 1 second constexpr static const int FPS_RATE_SEC = 1 ;
constexpr static const int FRAME_CHECK_RATE_HZ = 120;
// Helpers // Helpers
timespec createTimeout( ); timespec createTimeout( );
bool shmLock ( ); bool shmLock ( );
void shmUnlock ( ); void shmUnlock ( );
bool renderToBitmap(); bool getNewFrame ( bool wait );
bool remapShm ( );
private: private:
Video::ShmRenderer* q_ptr; Video::ShmRenderer* q_ptr;
private Q_SLOTS:
void timedEvents();
}; };
} ShmRendererPrivate::ShmRendererPrivate(ShmRenderer* parent)
: QObject ( parent )
Video::ShmRendererPrivate::ShmRendererPrivate(Video::ShmRenderer* parent) : QObject(parent), q_ptr(parent), , q_ptr ( parent )
fd(-1),m_fpsC(0),m_Fps(0), , m_fd ( -1 )
m_pShmArea((SHMHeader*)MAP_FAILED), m_ShmAreaLen(0), m_BufferGen(0), , m_fpsC ( 0 )
m_pTimer(nullptr) , m_Fps ( 0 )
, m_pShmArea ( (SHMHeader*)MAP_FAILED )
, m_ShmAreaLen( 0 )
, m_FrameGen ( 0 )
#ifdef DEBUG_FPS #ifdef DEBUG_FPS
, m_frameCount( 0 ) , m_frameCount( 0 )
, m_lastFrameDebug(std::chrono::system_clock::now() ) , m_lastFrameDebug(std::chrono::system_clock::now() )
...@@ -115,242 +122,199 @@ Video::ShmRendererPrivate::ShmRendererPrivate(Video::ShmRenderer* parent) : QObj ...@@ -115,242 +122,199 @@ Video::ShmRendererPrivate::ShmRendererPrivate(Video::ShmRenderer* parent) : QObj
} }
/// Constructor /// Constructor
Video::ShmRenderer::ShmRenderer(const QByteArray& id, const QString& shmPath, const QSize& res): Renderer(id, res), d_ptr(new ShmRendererPrivate(this)) ShmRenderer::ShmRenderer(const QByteArray& id, const QString& shmPath, const QSize& res)
: Renderer(id, res)
, d_ptr(new ShmRendererPrivate(this))
{ {
d_ptr->m_ShmPath = shmPath; d_ptr->m_ShmPath = shmPath;
setObjectName("Video::Renderer:"+id); setObjectName("Video::Renderer:"+id);
} }
/// Destructor /// Destructor
Video::ShmRenderer::~ShmRenderer() ShmRenderer::~ShmRenderer()
{ {
stopShm(); stopShm();
//delete m_pShmArea;
} }
///Get the data from shared memory and transform it into a QByteArray /// Wait new frame data from shared memory and save pointer
bool Video::ShmRendererPrivate::renderToBitmap() bool ShmRendererPrivate::getNewFrame(bool wait)
{ {
QMutexLocker locker {q_ptr->mutex()};
#ifdef Q_OS_LINUX
if (!q_ptr->isRendering())
return false;
if (!shmLock()) if (!shmLock())
return false; return false;
if (m_BufferGen == m_pShmArea->m_BufferGen) { if (m_FrameGen == m_pShmArea->frameGen) {
// wait for a new buffer
do {
shmUnlock(); shmUnlock();
auto err = sem_trywait(&m_pShmArea->notification);
if (!err)
break;
// Fatal error? if (not wait)
if (errno != EAGAIN)
return false; return false;
// wait a little bit that deamon does its work // wait for a new frame, max 33ms
usleep(10); // must be less than the maximal framerate possible static const struct timespec timeout = {0, 33000000};
if (::sem_timedwait(&m_pShmArea->frameGenMutex, &timeout) < 0)
// stopRendering called?
if (!q_ptr->isRendering())
return false; return false;
} while (m_BufferGen == m_pShmArea->m_BufferGen);
if (!shmLock()) if (!shmLock())
return false; return false;
} }
if (!q_ptr->resizeShm()) { // valid frame to render (daemon may have stopped)?
qDebug() << "Could not resize shared memory"; if (! m_pShmArea->frameSize) {
shmUnlock(); shmUnlock();
return false; return false;
} }
if (static_cast<Video::Renderer*>(q_ptr)->d_ptr->otherFrame().size() != m_pShmArea->m_BufferSize) // map frame data
static_cast<Video::Renderer*>(q_ptr)->d_ptr->otherFrame().resize(m_pShmArea->m_BufferSize); if (!remapShm()) {
memcpy(static_cast<Video::Renderer*>(q_ptr)->d_ptr->otherFrame().data(),m_pShmArea->m_Data,m_pShmArea->m_BufferSize); qDebug() << "Could not resize shared memory";
m_BufferGen = m_pShmArea->m_BufferGen; return false;
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(); shmUnlock();
#ifdef DEBUG_FPS ++m_fpsC;
// Compute the FPS shown to the client
auto currentTime = std::chrono::system_clock::now(); auto currentTime = std::chrono::system_clock::now();
const std::chrono::duration<double> seconds = currentTime - m_lastFrameDebug; const std::chrono::duration<double> seconds = currentTime - m_lastFrameDebug;
++m_frameCount; if (seconds.count() >= FPS_RATE_SEC) {
if (seconds.count() > 1) { m_Fps = m_fpsC / seconds.count();
qDebug() << this << ": FPS " << (m_frameCount / seconds.count()); m_fpsC = 0;
m_frameCount = 0;
m_lastFrameDebug = currentTime; m_lastFrameDebug = currentTime;
} #ifdef DEBUG_FPS
qDebug() << this << ": FPS " << m_fps;
#endif #endif
}
emit q_ptr->frameUpdated();
return true; return true;
#else
return false;
#endif
} }
///Connect to the shared memory /// Remap the shared memory
bool Video::ShmRenderer::startShm() /// 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
qDebug() << "fd must be -1"; // 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; return false;
} }
d_ptr->fd = shm_open(d_ptr->m_ShmPath.toLatin1(), O_RDWR, 0); m_pShmArea = (SHMHeader*) ::mmap(nullptr, mapSize, PROT_READ | PROT_WRITE,
if (d_ptr->fd < 0) { MAP_SHARED, m_fd, 0);
qDebug() << "could not open shm area " << d_ptr->m_ShmPath << ", shm_open failed:" << strerror(errno);
if (m_pShmArea == MAP_FAILED) {
qDebug() << "Could not remap shared area: " << strerror(errno);
return false; return false;
} }
d_ptr->m_ShmAreaLen = sizeof(SHMHeader);
#pragma GCC diagnostic push if (!shmLock())
#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
if (d_ptr->m_pShmArea == MAP_FAILED) {
qDebug() << "Could not map shm area, mmap failed";
return false; return false;
m_ShmAreaLen = mapSize;
} }
emit started();
return true; return true;
} }
///Disconnect from the shared memory /// Connect to the shared memory
void Video::ShmRenderer::stopShm() bool ShmRenderer::startShm()
{ {
if (d_ptr->fd >= 0) if (d_ptr->m_fd != -1) {
close(d_ptr->fd); qDebug() << "fd must be -1";
d_ptr->fd = -1; return false;
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;
} }
///Resize the shared memory d_ptr->m_fd = ::shm_open(d_ptr->m_ShmPath.toLatin1(), O_RDWR, 0);
bool Video::ShmRenderer::resizeShm()
{
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 (d_ptr->m_fd < 0) {
if (munmap(d_ptr->m_pShmArea, d_ptr->m_ShmAreaLen)) { qDebug() << "could not open shm area" << d_ptr->m_ShmPath
qDebug() << "Could not unmap shared area:" << strerror(errno); << ", shm_open failed:" << strerror(errno);
return false; return false;
} }
#pragma GCC diagnostic push // Map only header data
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" const auto mapSize = sizeof(SHMHeader);
d_ptr->m_pShmArea = (SHMHeader*) mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, d_ptr->fd, 0); d_ptr->m_pShmArea = (SHMHeader*) ::mmap(nullptr, mapSize,
#pragma GCC diagnostic pop PROT_READ | PROT_WRITE,
d_ptr->m_ShmAreaLen = new_size; MAP_SHARED, d_ptr->m_fd, 0
);
if (!d_ptr->m_pShmArea) { if (d_ptr->m_pShmArea == MAP_FAILED) {
d_ptr->m_pShmArea = nullptr;
qDebug() << "Could not remap shared area"; qDebug() << "Could not remap shared area";
return false; return false;
} }
d_ptr->m_ShmAreaLen = new_size; d_ptr->m_ShmAreaLen = mapSize;
if (!d_ptr->shmLock())
return true; return true;
} }
return true;
/// Disconnect from the shared memory
void ShmRenderer::stopShm()
{
if (d_ptr->m_fd < 0)
return;
::close(d_ptr->m_fd);
d_ptr->m_fd = -1;
if (d_ptr->m_pShmArea == MAP_FAILED)
return;
::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 /// Lock the memory while the copy is being made
bool Video::ShmRendererPrivate::shmLock() bool ShmRendererPrivate::shmLock()
{ {
#ifdef Q_OS_LINUX return ::sem_wait(&m_pShmArea->mutex) >= 0;
return sem_trywait(&m_pShmArea->mutex) >= 0;
#else
return false;
#endif
} }
/// Remove the lock, allow a new frame to be drawn /// Remove the lock, allow a new frame to be drawn
void Video::ShmRendererPrivate::shmUnlock() void ShmRendererPrivate::shmUnlock()
{ {
#ifdef Q_OS_LINUX ::sem_post(&m_pShmArea->mutex);
sem_post(&m_pShmArea->mutex);
#endif
} }
/***************************************************************************** /*****************************************************************************
* * * *
* Slots * * 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 /// Start the rendering loop
void Video::ShmRenderer::startRendering() void ShmRenderer::startRendering()
{ {
QMutexLocker locker {mutex()}; QMutexLocker locker {mutex()};
if (!startShm()) { if (!startShm())
qDebug() << "Cannot start rendering on " << d_ptr->m_ShmPath;
return; 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 /// Stop the rendering loop
void Video::ShmRenderer::stopRendering() void ShmRenderer::stopRendering()
{ {
setRendering(false);
QMutexLocker locker {mutex()}; QMutexLocker locker {mutex()};
qDebug() << "Stopping rendering on" << this; Video::Renderer::d_ptr->m_isRendering = false;
if (d_ptr->m_pTimer)
d_ptr->m_pTimer->stop();
emit stopped(); emit stopped();
stopShm(); stopShm();
} }
/***************************************************************************** /*****************************************************************************
* * * *
* Getters * * Getters *
...@@ -358,20 +322,38 @@ void Video::ShmRenderer::stopRendering() ...@@ -358,20 +322,38 @@ void Video::ShmRenderer::stopRendering()
****************************************************************************/ ****************************************************************************/
/// Get the current frame rate of this renderer /// Get the current frame rate of this renderer
int Video::ShmRenderer::fps() const int ShmRenderer::fps() const
{ {
return d_ptr->m_Fps; 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 * * Setters *
* * * *
****************************************************************************/ ****************************************************************************/
void Video::ShmRenderer::setShmPath(const QString& path) void ShmRenderer::setShmPath(const QString& path)
{ {
d_ptr->m_ShmPath = path; d_ptr->m_ShmPath = path;
} }
} // namespace Video
#include <shmrenderer.moc> #include <shmrenderer.moc>
...@@ -42,18 +42,21 @@ class LIB_EXPORT ShmRenderer : public Renderer { ...@@ -42,18 +42,21 @@ class LIB_EXPORT ShmRenderer : public Renderer {
Q_OBJECT Q_OBJECT
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
friend class VideoRendererManagerPrivate ;
public: public:
//Constructor //Constructor
ShmRenderer (const QByteArray& id, const QString& shmPath, const QSize& res); ShmRenderer (const QByteArray& id, const QString& shmPath, const QSize& res);
virtual ~ShmRenderer(); virtual ~ShmRenderer();
//Mutators //Mutators
bool resizeShm();
void stopShm (); void stopShm ();
bool startShm (); bool startShm ();
//Getters //Getters
virtual int fps () const ; int fps() const;
virtual const QByteArray& currentFrame() const override;
virtual ColorSpace colorSpace () const override;
//Setters //Setters
void setShmPath(const QString& path); void setShmPath(const QString& path);
...@@ -65,9 +68,6 @@ class LIB_EXPORT ShmRenderer : public Renderer { ...@@ -65,9 +68,6 @@ class LIB_EXPORT ShmRenderer : public Renderer {
public Q_SLOTS: public Q_SLOTS:
void startRendering(); void startRendering();
void stopRendering (); void stopRendering ();
}; };
} }
......
...@@ -38,15 +38,12 @@ public: ...@@ -38,15 +38,12 @@ public:
//Attributes //Attributes
std::atomic_bool m_isRendering; std::atomic_bool m_isRendering;
QByteArray m_Frame[2] ;
bool m_FrameIdx ;
QMutex* m_pMutex ; QMutex* m_pMutex ;
QString m_Id ; QString m_Id ;
QSize m_pSize ; QSize m_pSize ;
char* m_pFrame ;
//Helpers QByteArray m_Content ;
QByteArray& otherFrame () ; unsigned int m_FrameSize ;
void updateFrameIndex () ;
private: private:
Video::Renderer* q_ptr; Video::Renderer* q_ptr;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <video/resolution.h> #include <video/resolution.h>
#include "private/videorate_p.h" #include "private/videorate_p.h"
#include "private/call_p.h" #include "private/call_p.h"
#include "private/videorenderer_p.h"
#ifdef ENABLE_LIBWRAP #ifdef ENABLE_LIBWRAP
#include "private/directrenderer.h" #include "private/directrenderer.h"
......
...@@ -37,7 +37,8 @@ struct SHMHeader; ...@@ -37,7 +37,8 @@ struct SHMHeader;
class VideoRendererManagerPrivate; class VideoRendererManagerPrivate;
///VideoModel: Video event dispatcher ///VideoModel: Video event dispatcher
class VideoRendererManager : public QObject { class VideoRendererManager : public QObject
{
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
Q_OBJECT Q_OBJECT
......
...@@ -23,20 +23,24 @@ ...@@ -23,20 +23,24 @@
//Qt //Qt
#include <QtCore/QMutex> #include <QtCore/QMutex>
Video::RendererPrivate::RendererPrivate(Video::Renderer* parent) : QObject(parent), q_ptr(parent), Video::RendererPrivate::RendererPrivate(Video::Renderer* parent)
m_pMutex(new QMutex()), m_FrameIdx(false) : 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)) Video::Renderer::Renderer(const QByteArray& id, const QSize& res) : d_ptr(new RendererPrivate(this))
{ {
setObjectName("Renderer:"+id); setObjectName("Renderer:"+id);
d_ptr->m_FrameSize = res.width() * res.height() * 4;
d_ptr->m_pSize = res; d_ptr->m_pSize = res;
d_ptr->m_Id = id; d_ptr->m_Id = id;
} }
Video::Renderer::~Renderer() Video::Renderer::~Renderer()
{} {
delete d_ptr;
}
/***************************************************************************** /*****************************************************************************
* * * *
...@@ -44,24 +48,12 @@ Video::Renderer::~Renderer() ...@@ -44,24 +48,12 @@ Video::Renderer::~Renderer()
* * * *
****************************************************************************/ ****************************************************************************/
///Return if the rendering is currently active or not
bool Video::Renderer::isRendering() const bool Video::Renderer::isRendering() const
{ {
return d_ptr->m_isRendering; 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 ///Get mutex, in case renderer and views are not in the same thread
QMutex* Video::Renderer::mutex() const QMutex* Video::Renderer::mutex() const
{ {
...@@ -74,26 +66,22 @@ QSize Video::Renderer::size() const ...@@ -74,26 +66,22 @@ QSize Video::Renderer::size() const
return d_ptr->m_pSize; 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 * * 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 void Video::Renderer::setSize(const QSize& size) const
{ {
d_ptr->m_pSize = size; d_ptr->m_pSize = size;
} }
void Video::RendererPrivate::updateFrameIndex()
{
m_FrameIdx = !m_FrameIdx;
}
#include <renderer.moc> #include <renderer.moc>
...@@ -33,6 +33,7 @@ namespace Video { ...@@ -33,6 +33,7 @@ namespace Video {
class RendererPrivate; class RendererPrivate;
class ShmRendererPrivate; class ShmRendererPrivate;
class ShmRenderer;
class DirectRendererPrivate; class DirectRendererPrivate;
class DirectRenderer; class DirectRenderer;
...@@ -43,17 +44,30 @@ class DirectRenderer; ...@@ -43,17 +44,30 @@ class DirectRenderer;
* *
* Each platform transparently provide its own implementation. * 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 push
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
Q_OBJECT Q_OBJECT
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
friend class Video::ShmRendererPrivate ; friend class Video::ShmRendererPrivate ;
friend class Video::ShmRenderer ;
friend class Video::DirectRendererPrivate; friend class Video::DirectRendererPrivate;
friend class Video::DirectRenderer ; friend class Video::DirectRenderer ;
friend class VideoRendererManagerPrivate ;
public: 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 //Constructor
Renderer (const QByteArray& id, const QSize& res); Renderer (const QByteArray& id, const QSize& res);
virtual ~Renderer(); virtual ~Renderer();
...@@ -63,14 +77,12 @@ public: ...@@ -63,14 +77,12 @@ public:
virtual const QByteArray& currentFrame () const; virtual const QByteArray& currentFrame () const;
virtual QSize size () const; virtual QSize size () const;
virtual QMutex* mutex () 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: Q_SIGNALS:
///Emitted when a new frame is ready void frameUpdated(); // Emitted when a new frame is ready
void frameUpdated();
void stopped (); void stopped ();
void started (); void started ();
...@@ -78,9 +90,8 @@ public Q_SLOTS: ...@@ -78,9 +90,8 @@ public Q_SLOTS:
virtual void startRendering() = 0; virtual void startRendering() = 0;
virtual void stopRendering () = 0; virtual void stopRendering () = 0;
private: private:
QScopedPointer<RendererPrivate> d_ptr; RendererPrivate* d_ptr;
Q_DECLARE_PRIVATE(Renderer) Q_DECLARE_PRIVATE(Renderer)
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment