diff --git a/src/api/newvideo.h b/src/api/newvideo.h index 7af16f7f4f21879848e2d84d2c26b0b40651a44a..fc0f3a7f9a10303e79d8a54d20d20aae7be65a8c 100644 --- a/src/api/newvideo.h +++ b/src/api/newvideo.h @@ -105,20 +105,12 @@ public: const bool useAVFrame = false); ~Renderer(); - /** - * Start the renderer in its own thread - */ - void initThread(); /** * Update size and shmPath of a renderer * @param res new resolution "wxh" * @param shmPath new shmPath */ void update(const QString& res, const QString& shmPath); - /** - * Stop renderer and thread - */ - void quit(); // Getters /** @@ -147,14 +139,6 @@ public: QSize size() const; // TODO convert into std format! // Utils - /** - * Start rendering - */ - void startRendering(); - /** - * Stop rendering - */ - void stopRendering(); /** * set to true to receive AVFrames from render */ @@ -166,6 +150,17 @@ Q_SIGNALS: * @param id */ void frameUpdated(const QString& id); + void started(const QString& id); + void stopped(const QString& id); + + /** + * Start rendering + */ + void startRendering(); + /** + * Stop rendering + */ + void stopRendering(); private: std::unique_ptr<RendererPimpl> pimpl_; diff --git a/src/avmodel.cpp b/src/avmodel.cpp index 29ca1d60c94eebc3ecf36df5c2f765493df746e6..d27e50484e98275d5474576c55f8d0e1f6f902fc 100644 --- a/src/avmodel.cpp +++ b/src/avmodel.cpp @@ -62,8 +62,6 @@ public: std::mutex renderers_mtx_; std::map<QString, std::unique_ptr<video::Renderer>> renderers_; - // store if a renderers is for a finished call - std::map<QString, bool> finishedRenderers_; bool useAVFrame_ = false; QString currentVideoCaptureDevice_ {}; @@ -81,6 +79,20 @@ public: */ QString getDevice(int type) const; + /** + * Add video::Renderer to renderers_ and start it + * @param id + * @param settings + * @param shmPath + */ + void addRenderer(const QString& id, video::Settings settings, const QString& shmPath = {}); + + /** + * Remove renderer from renderers_ + * @param id + */ + void removeRenderer(const QString& id); + public Q_SLOTS: /** * Listen from CallbacksHandler when a renderer starts @@ -96,13 +108,6 @@ public Q_SLOTS: * @param shmPath */ void stoppedDecoding(const QString& id, const QString& shmPath); - /** - * Listen from CallbacksHandler when a call got a new state - * @param id - * @param state the new state - * @param code unused - */ - void slotCallStateChanged(const QString& id, const QString& state, int code); /** * Detect when the current frame is updated * @param id @@ -145,8 +150,8 @@ AVModel::AVModel(const CallbacksHandler& callbacksHandler) AVModel::~AVModel() { std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_); - for (auto r = pimpl_->renderers_.cbegin(); r != pimpl_->renderers_.cend(); ++r) { - (*r).second->quit(); + for (auto r = pimpl_->renderers_.begin(); r != pimpl_->renderers_.end(); ++r) { + (*r).second.reset(); } } @@ -508,36 +513,13 @@ AVModel::useAVFrame(bool useAVFrame) void AVModel::startPreview() { - std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_); - auto search = pimpl_->renderers_.find(video::PREVIEW_RENDERER_ID); - if (search == pimpl_->renderers_.end() || !pimpl_->renderers_[video::PREVIEW_RENDERER_ID]) { - qWarning() << "Can't find preview renderer!"; - return; - } VideoManager::instance().startCamera(); - pimpl_->renderers_[video::PREVIEW_RENDERER_ID]->startRendering(); } void AVModel::stopPreview() { - std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_); - auto search = pimpl_->renderers_.find(video::PREVIEW_RENDERER_ID); - if (search == pimpl_->renderers_.end() || !pimpl_->renderers_[video::PREVIEW_RENDERER_ID]) { - qWarning() << "Can't find preview renderer!"; - return; - } - // If an active call does not have video muted, don't stop the camera - // stopCamera() calls switchInput(""), which disables the camera - bool previewShouldBeStopped = true; - for (auto it = pimpl_->renderers_.cbegin(); it != pimpl_->renderers_.cend(); ++it) { - if (it->second->getId() != video::PREVIEW_RENDERER_ID) - // If rendering, don't stop preview - previewShouldBeStopped &= !it->second->isRendering(); - } - if (previewShouldBeStopped) - VideoManager::instance().stopCamera(); - pimpl_->renderers_[video::PREVIEW_RENDERER_ID]->stopRendering(); + VideoManager::instance().stopCamera(); } const video::Renderer& @@ -653,27 +635,21 @@ AVModel::clearCurrentVideoCaptureDevice() } AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHandler) - : linked_(linked) - , callbacksHandler(callbacksHandler) + : callbacksHandler(callbacksHandler) + , linked_(linked) { std::srand(std::time(nullptr)); - // add preview renderer - try { - renderers_.insert( - std::make_pair(video::PREVIEW_RENDERER_ID, - std::make_unique<video::Renderer>(video::PREVIEW_RENDERER_ID, - linked_.getDeviceSettings( - linked_.getDefaultDevice()), - "", - useAVFrame_))); - } catch (const std::out_of_range& e) { - qWarning() << "Couldn't setup video input renderer: " << e.what(); - } #ifndef ENABLE_LIBWRAP SIZE_RENDERER = renderers_.size(); #endif connect(&callbacksHandler, &CallbacksHandler::deviceEvent, this, &AVModelPimpl::slotDeviceEvent); connect(&callbacksHandler, &CallbacksHandler::audioMeter, this, &AVModelPimpl::slotAudioMeter); + connect(&callbacksHandler, + &CallbacksHandler::recordPlaybackStopped, + this, + &AVModelPimpl::slotRecordPlaybackStopped); + + // render connections connect(&callbacksHandler, &CallbacksHandler::startedDecoding, this, @@ -682,18 +658,6 @@ AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHan &CallbacksHandler::stoppedDecoding, this, &AVModelPimpl::stoppedDecoding); - connect(&callbacksHandler, - &CallbacksHandler::callStateChanged, - this, - &AVModelPimpl::slotCallStateChanged); - connect(&*renderers_[video::PREVIEW_RENDERER_ID], - &api::video::Renderer::frameUpdated, - this, - &AVModelPimpl::slotFrameUpdated); - connect(&callbacksHandler, - &CallbacksHandler::recordPlaybackStopped, - this, - &AVModelPimpl::slotRecordPlaybackStopped); auto startedPreview = false; auto restartRenderers = [&](const QStringList& callList) { @@ -712,6 +676,7 @@ AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHan restartRenderers(CallManager::instance().getConferenceList()); if (startedPreview) restartRenderers({"local"}); + currentVideoCaptureDevice_ = VideoManager::instance().getDefaultDevice(); } QString @@ -744,99 +709,16 @@ AVModelPimpl::getRecordingPath() const void AVModelPimpl::startedDecoding(const QString& id, const QString& shmPath, int width, int height) { - const QString res = toQString(width) + "x" + toQString(height); - { - std::lock_guard<std::mutex> lk(renderers_mtx_); - auto search = renderers_.find(id); - - if (search == renderers_.end()) { - video::Settings settings; - settings.size = res; - renderers_.insert(std::make_pair(id, - std::make_unique<video::Renderer>(id, - settings, - shmPath, - useAVFrame_))); - finishedRenderers_.insert(std::make_pair(id, false)); -#ifndef ENABLE_LIBWRAP - SIZE_RENDERER = renderers_.size(); -#endif - renderers_.at(id)->initThread(); - connect(&*renderers_[id], - &api::video::Renderer::frameUpdated, - this, - &AVModelPimpl::slotFrameUpdated); - } else { - (*search).second->update(res, shmPath); - } - renderers_.at(id)->startRendering(); - } - emit linked_.rendererStarted(id); + video::Settings settings; + settings.size = toQString(width) + "x" + toQString(height); + addRenderer(id, settings, shmPath); } void AVModelPimpl::stoppedDecoding(const QString& id, const QString& shmPath) { Q_UNUSED(shmPath) - { - std::lock_guard<std::mutex> lk(renderers_mtx_); - auto search = renderers_.find(id); - if (search == renderers_.end()) { - qWarning() << "Cannot stop decoding, renderer " << id << "not found"; - return; // nothing to do - } - - (*search).second->stopRendering(); - qDebug() << "Video stopped for call" << id; - (*search).second->quit(); - if (id != video::PREVIEW_RENDERER_ID) { - auto searchFinished = finishedRenderers_.find(id); - if (searchFinished == finishedRenderers_.end()) { - qWarning() << "Finished flag: " << id << " not found"; - return; // nothing to do - } - if (searchFinished->second) { - disconnect(&*search->second, - &api::video::Renderer::frameUpdated, - this, - &AVModelPimpl::slotFrameUpdated); - renderers_.erase(search); -#ifndef ENABLE_LIBWRAP - SIZE_RENDERER = renderers_.size(); -#endif - finishedRenderers_.erase(id); - } - } - } - emit linked_.rendererStopped(id); -} - -void -AVModelPimpl::slotCallStateChanged(const QString& id, const QString& state, int code) -{ - Q_UNUSED(code) - if (call::to_status(state) != call::Status::ENDED) - return; - std::lock_guard<std::mutex> lk(renderers_mtx_); - auto search = renderers_.find(id); - auto searchFinished = finishedRenderers_.find(id); - if (search == renderers_.end() || searchFinished == finishedRenderers_.end()) { - qWarning() << "Renderer " << id << "not found"; - return; // nothing to do - } - if (!search->second->isRendering()) { - disconnect(&*search->second, - &api::video::Renderer::frameUpdated, - this, - &AVModelPimpl::slotFrameUpdated); - renderers_.erase(search); -#ifndef ENABLE_LIBWRAP - SIZE_RENDERER = renderers_.size(); -#endif - finishedRenderers_.erase(id); - } else { - finishedRenderers_.at(id) = true; - } + removeRenderer(id); } #ifndef ENABLE_LIBWRAP @@ -906,6 +788,65 @@ AVModelPimpl::getDevice(int type) const return result; } +void +AVModelPimpl::addRenderer(const QString& id, video::Settings settings, const QString& shmPath) +{ + { + std::lock_guard<std::mutex> lk(renderers_mtx_); + auto search = renderers_.find(id); + if (search == renderers_.end()) { + renderers_ + .emplace(id, std::make_unique<video::Renderer>(id, settings, shmPath, useAVFrame_)); + renderers_.at(id)->startRendering(); + } else { + if (search->second) { + search->second->update(settings.size, shmPath); + } else { + search->second.reset(new video::Renderer(id, settings, shmPath, useAVFrame_)); + renderers_.at(id)->startRendering(); + } + } + connect( + renderers_.at(id).get(), + &video::Renderer::started, + this, + [this](const QString& id) { emit linked_.rendererStarted(id); }, + Qt::UniqueConnection); + connect(renderers_.at(id).get(), + &video::Renderer::frameUpdated, + this, + &AVModelPimpl::slotFrameUpdated, + Qt::UniqueConnection); + } +} + +void +AVModelPimpl::removeRenderer(const QString& id) +{ + { + std::lock_guard<std::mutex> lk(renderers_mtx_); + auto search = renderers_.find(id); + if (search == renderers_.end()) { + qWarning() << "Cannot remove renderer. " << id << "not found"; + return; + } + disconnect(search->second.get(), + &video::Renderer::frameUpdated, + this, + &AVModelPimpl::slotFrameUpdated); + connect( + search->second.get(), + &video::Renderer::stopped, + this, + [this](const QString& id) { + renderers_.erase(id); + emit linked_.rendererStopped(id); + }, + Qt::DirectConnection); + search->second.reset(); + } +} + void AVModelPimpl::slotFrameUpdated(const QString& id) { diff --git a/src/directrenderer.cpp b/src/directrenderer.cpp index c7a421949d8f75579bdf02820cd5f1e0d5d57fd0..a47d6b0ee677c0eb171e679bb46456a9bcd25617 100644 --- a/src/directrenderer.cpp +++ b/src/directrenderer.cpp @@ -87,7 +87,12 @@ Video::DirectRenderer::DirectRenderer(const QString& id, const QSize& res, bool } /// Destructor -Video::DirectRenderer::~DirectRenderer() {} +Video::DirectRenderer::~DirectRenderer() +{ + stopRendering(); + + d_ptr.reset(); +} void Video::DirectRenderer::startRendering() diff --git a/src/newvideo.cpp b/src/newvideo.cpp index 2c94ef74e80a02d8f4217d70f29c39c4a20bc571..32c08aaf03dabe4f743f3d4e770a13b30820dacd 100644 --- a/src/newvideo.cpp +++ b/src/newvideo.cpp @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ -// LRC #include "api/newvideo.h" + #include "dbus/videomanager.h" #ifdef ENABLE_LIBWRAP #include "directrenderer.h" @@ -25,12 +25,10 @@ #include "shmrenderer.h" #endif -// std -#include <mutex> - -// Qt #include <QSize> +#include <mutex> + namespace lrc { using namespace api::video; @@ -45,7 +43,7 @@ public: const bool useAVFrame); ~RendererPimpl(); - Renderer& linked; + Renderer& linked_; QString id_; Settings videoSettings_; @@ -53,14 +51,12 @@ public: bool usingAVFrame_; /** - * Convert a string (wxh) to a QSize + * Convert a string (WxH) to a QSize * @param res the string to convert * @return the QSize object */ static QSize stringToQSize(const QString& res); - std::mutex rendering_mtx_; - #ifdef ENABLE_LIBWRAP std::unique_ptr<Video::DirectRenderer> renderer; #else @@ -87,23 +83,15 @@ Renderer::Renderer(const QString& id, Renderer::~Renderer() { - stopRendering(); -} - -void -Renderer::initThread() -{ - if (!pimpl_->renderer) - return; #ifdef ENABLE_LIBWRAP if (pimpl_->usingAVFrame_) { - VideoManager::instance().registerAVSinkTarget(pimpl_->id_, pimpl_->renderer->avTarget()); + VideoManager::instance().registerAVSinkTarget(pimpl_->id_, {}); } else { - VideoManager::instance().registerSinkTarget(pimpl_->id_, pimpl_->renderer->target()); + VideoManager::instance().registerSinkTarget(pimpl_->id_, {}); } -#endif - if (!pimpl_->thread_.isRunning()) - pimpl_->thread_.start(); +#endif // ENABLE_LIBWRAP + + pimpl_.reset(); } void @@ -130,7 +118,6 @@ Renderer::update(const QString& res, const QString& shmPath) bool Renderer::isRendering() const { - std::lock_guard<std::mutex> lk(pimpl_->rendering_mtx_); if (pimpl_->renderer) return pimpl_->renderer->isRendering(); return false; @@ -176,36 +163,7 @@ Renderer::currentAVFrame() const QSize Renderer::size() const { - if (pimpl_->renderer) - return pimpl_->renderer->size(); - return QSize(); -} - -void -Renderer::quit() -{ - pimpl_->thread_.quit(); - pimpl_->thread_.wait(); -} - -void -Renderer::startRendering() -{ - if (pimpl_->renderer) { - std::lock_guard<std::mutex> lk(pimpl_->rendering_mtx_); - if (pimpl_->renderer->isRendering()) - return; - pimpl_->renderer->startRendering(); - } -} - -void -Renderer::stopRendering() -{ - if (pimpl_->renderer) { - std::lock_guard<std::mutex> lk(pimpl_->rendering_mtx_); - pimpl_->renderer->stopRendering(); - } + return pimpl_->renderer->size(); } } // namespace video @@ -216,7 +174,7 @@ RendererPimpl::RendererPimpl(Renderer& linked, Settings videoSettings, const QString& shmPath, bool useAVFrame) - : linked(linked) + : linked_(linked) , id_(id) , videoSettings_(videoSettings) , usingAVFrame_(useAVFrame) @@ -229,10 +187,47 @@ RendererPimpl::RendererPimpl(Renderer& linked, #endif renderer->moveToThread(&thread_); - connect(&*renderer, &Video::Renderer::frameUpdated, this, &RendererPimpl::slotFrameUpdated); + connect(&thread_, &QThread::finished, [this] { renderer.reset(); }); + + connect(&linked, + &Renderer::startRendering, + renderer.get(), + &Video::Renderer::startRendering, + Qt::QueuedConnection); + + connect(renderer.get(), &Video::Renderer::frameUpdated, [this] { + emit linked_.frameUpdated(id_); + }); + + connect( + renderer.get(), + &Video::Renderer::started, + this, + [this] { emit linked_.started(id_); }, + Qt::DirectConnection); + connect( + renderer.get(), + &Video::Renderer::stopped, + this, + [this] { emit linked_.stopped(id_); }, + Qt::DirectConnection); + +#ifdef ENABLE_LIBWRAP + if (usingAVFrame_) { + VideoManager::instance().registerAVSinkTarget(id_, renderer->avTarget()); + } else { + VideoManager::instance().registerSinkTarget(id_, renderer->target()); + } +#endif + + thread_.start(); } -RendererPimpl::~RendererPimpl() {} +RendererPimpl::~RendererPimpl() +{ + thread_.quit(); + thread_.wait(); +} QSize RendererPimpl::stringToQSize(const QString& res) @@ -246,12 +241,6 @@ RendererPimpl::stringToQSize(const QString& res) return QSize(width, height); } -void -RendererPimpl::slotFrameUpdated() -{ - emit linked.frameUpdated(id_); -} - } // end of namespace lrc #include "api/moc_newvideo.cpp" diff --git a/src/shmrenderer.cpp b/src/shmrenderer.cpp index c2dc7e364ce0941b4a381048959c37857c313bef..d4bb282dc74dbffdf085188c3b27b5b524126314 100644 --- a/src/shmrenderer.cpp +++ b/src/shmrenderer.cpp @@ -135,10 +135,6 @@ ShmRenderer::ShmRenderer(const QString& id, const QString& shmPath, const QSize& /// Destructor ShmRenderer::~ShmRenderer() { - if (d_ptr->m_pTimer) { - d_ptr->m_pTimer->stop(); - d_ptr->m_pTimer = nullptr; - } stopShm(); } @@ -274,18 +270,23 @@ ShmRenderer::stopShm() if (d_ptr->m_fd < 0) return; + Video::Renderer::d_ptr->m_isRendering = false; + if (d_ptr->m_pTimer) { d_ptr->m_pTimer->stop(); d_ptr->m_pTimer = nullptr; } - // reset the frame so it doesn't point to an old value - Video::Renderer::d_ptr->m_pFrame.reset(); - // Emit the signal before closing the file, this lower the risk of invalid // memory access emit stopped(); + { + QMutexLocker lk {mutex()}; + // reset the frame so it doesn't point to an old value + Video::Renderer::d_ptr->m_pFrame.reset(); + } + ::close(d_ptr->m_fd); d_ptr->m_fd = -1; @@ -323,7 +324,7 @@ ShmRenderer::startRendering() { QMutexLocker locker {mutex()}; - if (!startShm()) + if (!startShm() || Video::Renderer::d_ptr->m_isRendering) return; Video::Renderer::d_ptr->m_isRendering = true; @@ -339,20 +340,10 @@ ShmRenderer::startRendering() emit started(); } -/// Stop the rendering loop +/// Done on destroy instead void ShmRenderer::stopRendering() -{ - QMutexLocker locker {mutex()}; - Video::Renderer::d_ptr->m_isRendering = false; - - if (d_ptr->m_pTimer) { - d_ptr->m_pTimer->stop(); - d_ptr->m_pTimer = nullptr; - } - - stopShm(); -} +{} /***************************************************************************** * * diff --git a/src/shmrenderer.h b/src/shmrenderer.h index 6f3b4d1f5f56fa0b98450671aaf0da633ca5ed8d..05ed9b893e54359715baa963146d7808a75a115d 100644 --- a/src/shmrenderer.h +++ b/src/shmrenderer.h @@ -64,7 +64,7 @@ private: public Q_SLOTS: void startRendering() override; - void stopRendering() override; + void stopRendering() override; // Unused }; } // namespace Video diff --git a/src/video/renderer.h b/src/video/renderer.h index 67505c42fdf2e621a982069f1907fb66334bd69c..f562dcd2342e68edb4db3fccc20314866b713878 100644 --- a/src/video/renderer.h +++ b/src/video/renderer.h @@ -74,7 +74,6 @@ class LIB_EXPORT Renderer : public QObject friend class Video::ShmRenderer; friend class Video::DirectRendererPrivate; friend class Video::DirectRenderer; - friend class VideoRendererManagerPrivate; public: /**