diff --git a/CMakeLists.txt b/CMakeLists.txt index 775097eb677f132e4face9fe5e14e2db756aa496..24f6e8505c6e60a004747f84e17bbe5c7820f7f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,7 +275,6 @@ ENDIF() SET( libringclient_LIB_SRCS #Data objects src/uri.cpp - src/video/renderer.cpp #Models src/contactmodel.cpp @@ -292,9 +291,6 @@ SET( libringclient_LIB_SRCS src/callbackshandler.cpp src/behaviorcontroller.cpp src/datatransfermodel.cpp - src/newvideo.cpp - src/shmrenderer.cpp - src/directrenderer.cpp src/messagelistmodel.cpp #Communication @@ -327,8 +323,6 @@ SET( libringclient_LIB_HDRS src/smartinfohub.h src/vcard.h src/namedirectory.h - src/shmrenderer.h - src/directrenderer.h src/messagelistmodel.h ) @@ -353,7 +347,7 @@ SET(libringclient_api_LIB_HDRS src/api/behaviorcontroller.h src/api/datatransfermodel.h src/api/datatransfer.h - src/api/newvideo.h + src/api/video.h ) SET(libringclient_WEB_chatview @@ -375,11 +369,6 @@ SET(libringclient_WEB_chatview src/web-chatview/web.gresource.xml ) -SET(libringclient_video_LIB_HDRS - src/video/renderer.h - #The renderer implementations are not exported on purpose -) - SET(libringclient_interface_LIB_HDRS src/interfaces/pixmapmanipulatori.h src/interfaces/dbuserrorhandleri.h @@ -390,6 +379,17 @@ SET( libringclient_extra_LIB_HDRS src/containerview.h ) +# video +list(APPEND libringclient_video_LIB_HDRS src/renderer.h) +list(APPEND libringclient_LIB_SRCS src/renderer.cpp) +if(ENABLE_LIBWRAP) + list(APPEND libringclient_video_LIB_HDRS src/directrenderer.h) + list(APPEND libringclient_LIB_SRCS src/directrenderer.cpp) +else() + list(APPEND libringclient_video_LIB_HDRS src/shmrenderer.h) + list(APPEND libringclient_LIB_SRCS src/shmrenderer.cpp) +endif() + IF(${ENABLE_LIBWRAP} MATCHES true OR ${ENABLE_TEST} MATCHES true) # done this way because of bug in cmake 2.8 # (not necessary in 3.0+) @@ -497,7 +497,6 @@ ENDIF() SET(libringclient_PRIVATE_HDRS src/private/namedirectory_p.h src/private/smartInfoHub_p.h - src/private/videorenderer_p.h ) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH true) @@ -537,6 +536,17 @@ IF(NOT ${ENABLE_STATIC} MATCHES false) ) ENDIF() +# For avframe dependency on Windows/macOS. +if(NOT DEFINED LIBAV_INCLUDE_PATH) + set(LIBJAMI_CONTRIB_DIR "${PROJECT_SOURCE_DIR}/../daemon/contrib/") + if(WIN32) + set(LIBAV_INCLUDE_PATH ${LIBJAMI_CONTRIB_DIR}/build/ffmpeg/Build/win32/x64/include/) + else() + set(LIBAV_INCLUDE_PATH ${LIBJAMI_CONTRIB_DIR}/native/ffmpeg) + endif() +endif() +include_directories(${LIBAV_INCLUDE_PATH}) + if (ENABLE_SHARED) message(STATUS "Configuring as shared lib") add_library(ringclient SHARED ${libringclient_LIB_SRCS} ${libringclient_api_LIB_HDRS} ${LIB_HEADER_MOC} ) diff --git a/src/api/avmodel.h b/src/api/avmodel.h index 26ff74bc92a208a59585ecad3a83d76f65bc39fc..f76d1682c0575577433a64301de1a4ed4ab38313 100644 --- a/src/api/avmodel.h +++ b/src/api/avmodel.h @@ -1,35 +1,33 @@ -/**************************************************************************** - * Copyright (C) 2018-2022 Savoir-faire Linux Inc. * - * Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com> * - * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ +/* + * Copyright (C) 2018-2022 Savoir-faire Linux Inc. + * Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com> + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #pragma once -// std +#include "api/video.h" +#include "typedefs.h" + +#include <QObject> + #include <memory> #include <string> #include <vector> -// Qt -#include <qobject.h> - -// LRC -#include "api/newvideo.h" -#include "typedefs.h" - namespace lrc { class CallbacksHandler; @@ -246,23 +244,12 @@ public: * @param resource */ Q_INVOKABLE void stopPreview(const QString& resource); - /** - * Get a renderer from a call - * @param id the callid or "local" - * @return the linked renderer - * @throw std::out_of_range if not found - */ - const video::Renderer& getRenderer(const QString& id) const; /** * Get the list of available windows ids * X11: a id is of the form 0x0000000 * @return map with windows names and ids */ const QVariantMap getListWindows() const; - /** - * set to true to receive AVFrames from render - */ - void useAVFrame(bool useAVFrame); /** * set current using device * @param device name @@ -277,22 +264,18 @@ public: * clear current using device */ void clearCurrentVideoCaptureDevice(); - /** - * Add video::Renderer to renderers_ and start it + * Add Renderer to renderers_ and start it * @param id * @param settings * @param shmPath */ - void addRenderer(const QString& id, - const video::Settings& settings, - const QString& shmPath = {}); + void addRenderer(const QString& id, const QSize& res, const QString& shmPath = {}); - /** - * Remove renderer from renderers_ - * @param id - */ - void removeRenderer(const QString& id); + bool hasRenderer(const QString& id); + QSize getRendererSize(const QString& id); + video::Frame getRendererFrame(const QString& id); + bool useDirectRenderer() const; Q_SIGNALS: /** @@ -305,6 +288,11 @@ Q_SIGNALS: * @param id of the renderer */ void rendererStopped(const QString& id); + /** + * Emitted when a new frame is requested + * @param id + */ + void frameBufferRequested(const QString& id, AVFrame* frame); /** * Emitted when a new frame is ready * @param id diff --git a/src/api/newcallmodel.h b/src/api/newcallmodel.h index b7bdf539983c8f60f1fae47614bbc0a8fa05e613..6c786f11486aaaf9b3136033d3e1716d6182de5f 100644 --- a/src/api/newcallmodel.h +++ b/src/api/newcallmodel.h @@ -21,7 +21,7 @@ #include "api/behaviorcontroller.h" #include "api/call.h" #include "api/account.h" -#include "api/newvideo.h" +#include "api/video.h" #include "typedefs.h" #include <QObject> @@ -29,10 +29,6 @@ #include <memory> #include <map> -namespace Video { -class Renderer; -} - namespace lrc { class CallbacksHandler; diff --git a/src/api/newvideo.h b/src/api/newvideo.h deleted file mode 100644 index f076c715e385d687f6c08d0b682a4a4f401f2cd7..0000000000000000000000000000000000000000 --- a/src/api/newvideo.h +++ /dev/null @@ -1,173 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2018-2022 Savoir-faire Linux Inc. * - * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#pragma once - -// Std -#include <map> -#include <memory> -#include <string> -#include <vector> - -// Qt -#include <qobject.h> - -// Lrc -#include "typedefs.h" - -// Qt -#include <QObject> -#include <QThread> - -struct AVFrame; - -namespace lrc { - -class RendererPimpl; - -namespace api { - -namespace video { -Q_NAMESPACE -Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") - -constexpr static const char PREVIEW_RENDERER_ID[] = "local"; - -using Channel = QString; -using Resolution = QString; -using Framerate = float; -using FrameratesList = QVector<Framerate>; -using ResRateList = QVector<QPair<Resolution, FrameratesList>>; -using Capabilities = QMap<Channel, ResRateList>; - -/** - * This class is used by Renderer class to expose video data frame - * that could be owned by instances of this class or shared. - * If an instance carries data, "storage.size()" is greater than 0 - * and equals to "size", "ptr" is equals to "storage.data()". - * If shared data is carried, only "ptr" and "size" are set. - */ -struct Frame -{ - uint8_t* ptr {nullptr}; - std::size_t size {0}; - std::vector<uint8_t> storage {}; - // Next variables are currently used with DirectRenderer only - unsigned int height {0}; - unsigned int width {0}; -}; - -enum class DeviceType { CAMERA, DISPLAY, FILE, INVALID }; -Q_ENUM_NS(DeviceType) - -/** - * This class describes the current rendered device - */ -struct RenderedDevice -{ - QString name; - DeviceType type = DeviceType::INVALID; -}; - -/** - * This class describes current video settings - */ -struct Settings -{ - Channel channel = ""; - QString name = ""; - QString id = ""; - Framerate rate = 0; - Resolution size = ""; -}; - -class LIB_EXPORT Renderer : public QObject -{ - Q_OBJECT -public: - Renderer(const QString& id, - Settings videoSettings, - const QString& shmPath = "", - const bool useAVFrame = false); - ~Renderer(); - - /** - * Update size and shmPath of a renderer - * @param res new resolution "wxh" - * @param shmPath new shmPath - */ - void update(const QString& res, const QString& shmPath); - - // Getters - /** - * @return if renderer is rendering - */ - bool isRendering() const; - /** - * @return renderer's id - */ - QString getId() const; - /** - * @return current rendered frame - */ - Frame currentFrame() const; - -#if defined(ENABLE_LIBWRAP) - /** - * @return current avframe - */ - std::unique_ptr<AVFrame, void (*)(AVFrame*)> currentAVFrame() const; -#endif - - /** - * @return current size - */ - QSize size() const; // TODO convert into std format! - - // Utils - /** - * set to true to receive AVFrames from render - */ - void useAVFrame(bool useAVFrame); - - bool useDirectRenderer() const; - -Q_SIGNALS: - /** - * Emitted when a new frame is ready - * @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_; -}; - -} // namespace video -} // namespace api -} // namespace lrc diff --git a/src/api/video.h b/src/api/video.h new file mode 100644 index 0000000000000000000000000000000000000000..5d44c0241fd2b08277d274e0ffd4e8d457af89c4 --- /dev/null +++ b/src/api/video.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018-2022 Savoir-faire Linux Inc. + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "typedefs.h" + +#include <QObject> +#include <QPair> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +extern "C" { +#include <libavutil/frame.h> +} + +namespace lrc { +namespace api { +namespace video { +Q_NAMESPACE +Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") + +constexpr static const char PREVIEW_RENDERER_ID[] = "local"; + +using Channel = QString; +using Resolution = QString; +using Framerate = float; +using FrameratesList = QVector<Framerate>; +using ResRateList = QVector<QPair<Resolution, FrameratesList>>; +using Capabilities = QMap<Channel, ResRateList>; + +// This class is used to expose video data frame(currently only +// by the ShmRenderer class). +struct Frame +{ + // Used by SHM renderer. + uint8_t* ptr {nullptr}; + size_t size {0}; +}; + +enum class DeviceType { CAMERA, DISPLAY, FILE, INVALID }; +Q_ENUM_NS(DeviceType) + +// This class describes the current video input device. +struct RenderedDevice +{ + QString name; + DeviceType type = DeviceType::INVALID; +}; + +// This class describes current video settings +struct Settings +{ + Channel channel = ""; + QString name = ""; + QString id = ""; + Framerate rate = 0; + Resolution size = ""; +}; +} // namespace video +} // namespace api +} // namespace lrc diff --git a/src/avmodel.cpp b/src/avmodel.cpp index ebf5eeb281b8cf3d6c905bc67029a47cf5d54b11..3c70d6e28abebbf92707db211882b294ead5f6bb 100644 --- a/src/avmodel.cpp +++ b/src/avmodel.cpp @@ -1,24 +1,45 @@ -/**************************************************************************** - * Copyright (C) 2018-2022 Savoir-faire Linux Inc. * - * Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com> * - * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ +/* + * Copyright (C) 2018-2022 Savoir-faire Linux Inc. + * Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com> + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #include "api/avmodel.h" -// Std +#include "api/video.h" +#include "api/call.h" +#include "api/lrc.h" +#ifdef ENABLE_LIBWRAP +#include "directrenderer.h" +#else +#include "shmrenderer.h" +#endif +#include "callbackshandler.h" +#include "dbus/callmanager.h" +#include "dbus/configurationmanager.h" +#include "dbus/videomanager.h" +#include "authority/storagehelper.h" + +#include <media_const.h> + +#include <QtCore/QStandardPaths> +#include <QtCore/QDir> +#include <QUrl> +#include <QSize> + #include <algorithm> // std::sort #include <chrono> #include <csignal> @@ -29,23 +50,6 @@ #include <string> #include <sstream> -// Qt -#include <QtCore/QStandardPaths> -#include <QtCore/QDir> -#include <QUrl> - -// Ring daemon -#include <media_const.h> - -// LRC -#include "api/call.h" -#include "api/lrc.h" -#include "callbackshandler.h" -#include "dbus/callmanager.h" -#include "dbus/configurationmanager.h" -#include "dbus/videomanager.h" -#include "authority/storagehelper.h" - #if defined(Q_OS_UNIX) && !defined(__APPLE__) #include <xcb/xcb.h> #endif @@ -53,6 +57,8 @@ namespace lrc { using namespace api; +using namespace api::video; +using namespace lrc::video; class AVModelPimpl : public QObject { @@ -66,8 +72,7 @@ public: AVModel& linked_; std::mutex renderers_mtx_; - std::map<QString, std::unique_ptr<video::Renderer>> renderers_; - bool useAVFrame_ = false; + std::map<QString, std::unique_ptr<Renderer>> renderers_; QString currentVideoCaptureDevice_ {}; #ifndef ENABLE_LIBWRAP @@ -87,12 +92,10 @@ public: /** * Add video::Renderer to renderers_ and start it * @param id - * @param settings + * @param size * @param shmPath */ - void addRenderer(const QString& id, - const video::Settings& settings, - const QString& shmPath = {}); + void addRenderer(const QString& id, const QSize& res, const QString& shmPath = {}); /** * Remove renderer from renderers_ @@ -100,6 +103,10 @@ public: */ void removeRenderer(const QString& id); + bool hasRenderer(const QString& id); + QSize getRendererSize(const QString& id); + Frame getRendererFrame(const QString& id); + public Q_SLOTS: /** * Listen from CallbacksHandler when a renderer starts @@ -115,11 +122,6 @@ public Q_SLOTS: * @param shmPath */ void onDecodingStopped(const QString& id, const QString& shmPath); - /** - * Detect when the current frame is updated - * @param id - */ - void slotFrameUpdated(const QString& id); /** * Detect when a video device is plugged or unplugged */ @@ -228,7 +230,7 @@ AVModel::setDefaultDevice(const QString& deviceId) VideoManager::instance().setDefaultDevice(deviceId); } -video::Settings +Settings AVModel::getDeviceSettings(const QString& deviceId) const { if (deviceId.isEmpty()) { @@ -247,7 +249,7 @@ AVModel::getDeviceSettings(const QString& deviceId) const return result; } -video::Capabilities +Capabilities AVModel::getDeviceCapabilities(const QString& deviceId) const { // Channel x Resolution x Framerate @@ -296,8 +298,7 @@ AVModel::setDeviceSettings(video::Settings& settings) // doing this during a call will cause re-invite, this is unwanted std::unique_lock<std::mutex> lk(pimpl_->renderers_mtx_); auto it = pimpl_->renderers_.find(video::PREVIEW_RENDERER_ID); - if (it != pimpl_->renderers_.end() && it->second && it->second->isRendering() - && pimpl_->renderers_.size() == 1) { + if (it != pimpl_->renderers_.end() && it->second && pimpl_->renderers_.size() == 1) { lk.unlock(); stopPreview(video::PREVIEW_RENDERER_ID); startPreview(video::PREVIEW_RENDERER_ID); @@ -513,16 +514,6 @@ AVModel::setRecordQuality(const int& rec) const ConfigurationManager::instance().setRecordQuality(rec); } -void -AVModel::useAVFrame(bool useAVFrame) -{ - pimpl_->useAVFrame_ = useAVFrame; - std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_); - for (auto it = pimpl_->renderers_.cbegin(); it != pimpl_->renderers_.cend(); ++it) { - it->second->useAVFrame(pimpl_->useAVFrame_); - } -} - QString AVModel::startPreview(const QString& resource) { @@ -535,17 +526,6 @@ AVModel::stopPreview(const QString& resource) VideoManager::instance().closeVideoInput(resource); } -const video::Renderer& -AVModel::getRenderer(const QString& id) const -{ - std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_); - auto search = pimpl_->renderers_.find(id); - if (search == pimpl_->renderers_.end() || !search->second) { - throw std::out_of_range("Can't find renderer " + id.toStdString()); - } - return *search->second; -} - #if defined(Q_OS_UNIX) && !defined(__APPLE__) static xcb_atom_t getAtom(xcb_connection_t* c, const std::string& atomName) @@ -660,15 +640,37 @@ AVModel::clearCurrentVideoCaptureDevice() } void -AVModel::addRenderer(const QString& id, const video::Settings& settings, const QString& shmPath) +AVModel::addRenderer(const QString& id, const QSize& res, const QString& shmPath) { - pimpl_->addRenderer(id, settings, shmPath); + pimpl_->addRenderer(id, res, shmPath); } -void -AVModel::removeRenderer(const QString& id) +bool +AVModel::hasRenderer(const QString& id) +{ + return pimpl_->hasRenderer(id); +} + +QSize +AVModel::getRendererSize(const QString& id) +{ + return pimpl_->getRendererSize(id); +} + +Frame +AVModel::getRendererFrame(const QString& id) +{ + return pimpl_->getRendererFrame(id); +} + +bool +AVModel::useDirectRenderer() const { - pimpl_->removeRenderer(id); +#ifdef ENABLE_LIBWRAP + return true; +#else + return false; +#endif } AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHandler) @@ -752,9 +754,7 @@ AVModelPimpl::onDecodingStarted(const QString& id, const QString& shmPath, int w { if (id != "" && id != "local" && !id.contains("://")) // Else managed by callmodel return; - video::Settings settings; - settings.size = toQString(width) + "x" + toQString(height); - addRenderer(id, settings, shmPath); + addRenderer(id, QSize(width, height), shmPath); } void @@ -765,13 +765,12 @@ AVModelPimpl::onDecodingStopped(const QString& id, const QString& shmPath) } #ifndef ENABLE_LIBWRAP - void AVModelPimpl::stopCameraAndQuit(int) { if (SIZE_RENDERER == 1) { // This will stop the preview if needed (not in a call). - VideoManager::instance().closeVideoInput(video::PREVIEW_RENDERER_ID); + VideoManager::instance().closeVideoInput(PREVIEW_RENDERER_ID); // HACK: this sleep is just here to let the camera stop and // avoid immediate raise std::this_thread::sleep_for(std::chrono::milliseconds(50)); @@ -780,7 +779,6 @@ AVModelPimpl::stopCameraAndQuit(int) } #endif - QString AVModelPimpl::getDevice(int type) const { @@ -805,9 +803,9 @@ AVModelPimpl::getDevice(int type) const // Should not happen, but cannot retrieve current ringtone device return ""; } - auto deviceIdx = currentDevicesIdx[type].toUInt(); + auto deviceIdx = currentDevicesIdx[type].toInt(); for (const auto& dev : devices) { - uint32_t idx; + int idx {-1}; switch (type) { case 1: // INPUT idx = ConfigurationManager::instance().getAudioInputDeviceIndex(dev); @@ -831,35 +829,66 @@ AVModelPimpl::getDevice(int type) const return result; } +static std::unique_ptr<Renderer> +createRenderer(const QString& id, const QSize& res, const QString& shmPath = {}) +{ +#ifdef ENABLE_LIBWRAP + Q_UNUSED(shmPath) + return std::make_unique<DirectRenderer>(id, res); +#else + return std::make_unique<ShmRenderer>(id, res, shmPath); +#endif +} + void -AVModelPimpl::addRenderer(const QString& id, const video::Settings& settings, const QString& shmPath) +AVModelPimpl::addRenderer(const QString& id, const QSize& res, const QString& shmPath) { { + auto connectRenderer = [this](Renderer* renderer, const QString& id) { + connect( + renderer, + &Renderer::started, + this, + [this, id] { Q_EMIT linked_.rendererStarted(id); }, + Qt::QueuedConnection); + connect( + renderer, + &Renderer::frameBufferRequested, + this, + [this, id](AVFrame* frame) { Q_EMIT linked_.frameBufferRequested(id, frame); }, + Qt::DirectConnection); + connect( + renderer, + &Renderer::frameUpdated, + this, + [this, id] { Q_EMIT linked_.frameUpdated(id); }, + Qt::DirectConnection); + connect( + renderer, + &Renderer::stopped, + this, + [this, id] { Q_EMIT linked_.rendererStopped(id); }, + Qt::DirectConnection); + }; 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(); + Renderer* renderer {nullptr}; + auto it = renderers_.find(id); + if (it == renderers_.end()) { + renderers_.emplace(id, createRenderer(id, res, shmPath)); + renderer = renderers_.at(id).get(); + connectRenderer(renderer, id); + renderer->startRendering(); } else { - if (search->second) { - search->second->update(settings.size, shmPath); + renderer = it->second.get(); + if (renderer) { + renderer->update(res, shmPath); } else { - search->second.reset(new video::Renderer(id, settings, shmPath, useAVFrame_)); - renderers_.at(id)->startRendering(); + it->second.reset(createRenderer(id, res, shmPath).get()); + renderer = it->second.get(); + connectRenderer(renderer, id); + renderer->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); } } @@ -867,31 +896,41 @@ void AVModelPimpl::removeRenderer(const QString& id) { std::lock_guard<std::mutex> lk(renderers_mtx_); - auto search = renderers_.find(id); - if (search == renderers_.end()) { + auto it = renderers_.find(id); + if (it == 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(); + renderers_.erase(id); } -void -AVModelPimpl::slotFrameUpdated(const QString& id) +bool +AVModelPimpl::hasRenderer(const QString& id) +{ + std::lock_guard<std::mutex> lk(renderers_mtx_); + return renderers_.find(id) != renderers_.end(); +} + +QSize +AVModelPimpl::getRendererSize(const QString& id) { - emit linked_.frameUpdated(id); + std::lock_guard<std::mutex> lk(renderers_mtx_); + auto it = renderers_.find(id); + if (it != renderers_.end()) { + return it->second->size(); + } + return {}; +} + +Frame +AVModelPimpl::getRendererFrame(const QString& id) +{ + std::lock_guard<std::mutex> lk(renderers_mtx_); + auto it = renderers_.find(id); + if (it != renderers_.end()) { + return it->second->currentFrame(); + } + return {}; } void diff --git a/src/directrenderer.cpp b/src/directrenderer.cpp index 0a3e4702a47f7345c6d5262900746aa8e32fc991..7c77298a08feca5dc72cdee38d6e9b2df34f9ee4 100644 --- a/src/directrenderer.cpp +++ b/src/directrenderer.cpp @@ -1,222 +1,130 @@ -/**************************************************************************** - * Copyright (C) 2012-2022 Savoir-faire Linux Inc. * - * Author : Alexandre Lision <alexandre.lision@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 * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#ifdef ENABLE_LIBWRAP - -#include "directrenderer.h" - -#include <QtCore/QDebug> -#include <QtCore/QMutex> -#include <QtCore/QThread> -#include <QtCore/QTime> -#include <QtCore/QTimer> - -#include <cstring> - -#ifndef CLOCK_REALTIME -#define CLOCK_REALTIME 0 -#endif - -#include "private/videorenderer_p.h" -#include "videomanager_interface.h" - -extern "C" { -struct AVFrame; -auto AVFrameDeleter = [](AVFrame* p) { -}; -} - -namespace Video { -class DirectRendererPrivate : public QObject -{ - Q_OBJECT -public: - DirectRendererPrivate(Video::DirectRenderer* parent, bool useAVFrame); - DRing::SinkTarget::FrameBufferPtr requestFrameBuffer(std::size_t bytes); - void onNewFrame(DRing::SinkTarget::FrameBufferPtr buf); - void onNewAVFrame(std::unique_ptr<DRing::VideoFrame> frame); - void configureTarget(bool useAVFrame); - - DRing::SinkTarget target; - DRing::AVSinkTarget av_target; - mutable QMutex directmutex; - mutable DRing::SinkTarget::FrameBufferPtr daemonFramePtr_; - std::unique_ptr<AVFrame, void (*)(AVFrame*)> avframe; - -private: - Video::DirectRenderer* q_ptr; -}; - -} // namespace Video - -Video::DirectRendererPrivate::DirectRendererPrivate(Video::DirectRenderer* parent, bool useAVFrame) - : QObject(parent) - , q_ptr(parent) - , avframe {nullptr, AVFrameDeleter} -{ - using namespace std::placeholders; - if (useAVFrame) { - av_target.push = std::bind(&Video::DirectRendererPrivate::onNewAVFrame, this, _1); - return; - } - target.pull = std::bind(&Video::DirectRendererPrivate::requestFrameBuffer, this, _1); - target.push = std::bind(&Video::DirectRendererPrivate::onNewFrame, this, _1); -} - -/// Constructor -Video::DirectRenderer::DirectRenderer(const QString& id, const QSize& res, bool useAVFrame) - : Renderer(id, res) - , d_ptr(std::make_unique<DirectRendererPrivate>(this, useAVFrame)) -{ - setObjectName("Video::DirectRenderer:" + id); -} - -/// Destructor -Video::DirectRenderer::~DirectRenderer() -{ - QMutexLocker lk(mutex()); - stopRendering(); - - d_ptr.reset(); -} - -void -Video::DirectRenderer::startRendering() -{ - Video::Renderer::d_ptr->m_isRendering = true; - emit started(); -} -void -Video::DirectRenderer::stopRendering() -{ - Video::Renderer::d_ptr->m_isRendering = false; - emit stopped(); -} -void -Video::DirectRenderer::configureTarget(bool useAVFrame) -{ - d_ptr->configureTarget(useAVFrame); -} - -DRing::SinkTarget::FrameBufferPtr -Video::DirectRendererPrivate::requestFrameBuffer(std::size_t bytes) -{ - QMutexLocker lk(q_ptr->mutex()); - if (not daemonFramePtr_) - daemonFramePtr_.reset(new DRing::FrameBuffer); - daemonFramePtr_->storage.resize(bytes); - daemonFramePtr_->ptr = daemonFramePtr_->storage.data(); - daemonFramePtr_->ptrSize = bytes; - return std::move(daemonFramePtr_); -} - -void -Video::DirectRendererPrivate::configureTarget(bool useAVFrame) -{ - using namespace std::placeholders; - if (useAVFrame) { - target.pull = nullptr; - target.push = nullptr; - av_target.push = std::bind(&Video::DirectRendererPrivate::onNewAVFrame, this, _1); - return; - } - target.pull = std::bind(&Video::DirectRendererPrivate::requestFrameBuffer, this, _1); - target.push = std::bind(&Video::DirectRendererPrivate::onNewFrame, this, _1); - av_target.push = nullptr; -} - -void -Video::DirectRendererPrivate::onNewFrame(DRing::SinkTarget::FrameBufferPtr buf) -{ - if (not q_ptr->isRendering()) - return; - - { - QMutexLocker lk(q_ptr->mutex()); - daemonFramePtr_ = std::move(buf); - } - - emit q_ptr->frameUpdated(); -} - -void -Video::DirectRendererPrivate::onNewAVFrame(std::unique_ptr<DRing::VideoFrame> frame) -{ - if (not q_ptr->isRendering()) - return; - { - QMutexLocker lk(q_ptr->mutex()); - avframe = std::move(frame->getFrame()); - } - emit q_ptr->frameUpdated(); -} - -std::unique_ptr<AVFrame, void (*)(AVFrame*)> -Video::DirectRenderer::currentAVFrame() const -{ - if (not isRendering()) - return {nullptr, AVFrameDeleter}; - QMutexLocker lock(mutex()); - return std::move(d_ptr->avframe); -} - -lrc::api::video::Frame -Video::DirectRenderer::currentFrame() const -{ - if (not isRendering()) - return {}; - - QMutexLocker lock(mutex()); - if (not d_ptr->daemonFramePtr_) - return {}; - - lrc::api::video::Frame frame; - frame.storage = std::move(d_ptr->daemonFramePtr_->storage); - frame.ptr = frame.storage.data(); - frame.size = frame.storage.size(); - frame.height = d_ptr->daemonFramePtr_->height; - frame.width = d_ptr->daemonFramePtr_->width; - - return std::move(frame); -} - -const DRing::SinkTarget& -Video::DirectRenderer::target() const -{ - return d_ptr->target; -} - -const DRing::AVSinkTarget& -Video::DirectRenderer::avTarget() const -{ - return d_ptr->av_target; -} - -Video::Renderer::ColorSpace -Video::DirectRenderer::colorSpace() const -{ -#ifdef Q_OS_DARWIN - return Video::Renderer::ColorSpace::RGBA; -#else - return Video::Renderer::ColorSpace::BGRA; -#endif -} - -#include <directrenderer.moc> - -#endif +/* + * Copyright (C) 2012-2022 Savoir-faire Linux Inc. + * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com> + * Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> + * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "directrenderer.h" + +#include "dbus/videomanager.h" +#include "videomanager_interface.h" + +#include <QMutex> + +namespace lrc { +namespace video { + +using namespace lrc::api::video; + +struct DirectRenderer::Impl : public QObject +{ + Q_OBJECT +public: + Impl(DirectRenderer* parent) + : QObject(nullptr) + , parent_(parent) + { + configureTarget(); + VideoManager::instance().registerSinkTarget(parent_->id(), target); + }; + ~Impl() + { + parent_->stopRendering(); + VideoManager::instance().registerSinkTarget(parent_->id(), {}); + } + + // sink target callbacks + void configureTarget() + { + using namespace std::placeholders; + target.pull = std::bind(&Impl::pullCallback, this, _1); + target.push = std::bind(&Impl::pushCallback, this, _1); + }; + + DRing::SinkTarget::FrameBufferPtr pullCallback(std::size_t bytes) + { + QMutexLocker lk(&mutex); + if (!frameBufferPtr) { + frameBufferPtr.reset(new DRing::FrameBuffer); + frameBufferPtr->avframe.reset(av_frame_alloc()); + } + + // A response to this signal should be used to provide client + // allocated buffer specs via the AVFrame structure. + // Important: Subscription to this signal MUST be synchronous(Qt::DirectConnection). + Q_EMIT parent_->frameBufferRequested(frameBufferPtr->avframe.get()); + + return std::move(frameBufferPtr); + }; + + void pushCallback(DRing::SinkTarget::FrameBufferPtr buf) + { + { + QMutexLocker lk(&mutex); + frameBufferPtr = std::move(buf); + } + + Q_EMIT parent_->frameUpdated(); + }; + +private: + DirectRenderer* parent_; + +public: + DRing::SinkTarget target; + QMutex mutex; + DRing::SinkTarget::FrameBufferPtr frameBufferPtr; +}; + +DirectRenderer::DirectRenderer(const QString& id, const QSize& res) + : Renderer(id, res) + , pimpl_(std::make_unique<DirectRenderer::Impl>(this)) +{} + +DirectRenderer::~DirectRenderer() {} + +void +DirectRenderer::startRendering() +{ + Q_EMIT started(); +} + +void +DirectRenderer::stopRendering() +{ + Q_EMIT stopped(); +} + +void +DirectRenderer::update(const QSize& res, const QString&) +{ + Renderer::update(res); + + VideoManager::instance().registerSinkTarget(id(), pimpl_->target); +} + +Frame +DirectRenderer::currentFrame() const +{ + return {}; +} + +} // namespace video +} // namespace lrc + +#include "moc_directrenderer.cpp" +#include "directrenderer.moc" diff --git a/src/directrenderer.h b/src/directrenderer.h index 54722d1bcfdd92fde70d5d1921ca5fd41b5c520a..dfcd026590123c9d23b717d4f7c27d5270ee4330 100644 --- a/src/directrenderer.h +++ b/src/directrenderer.h @@ -1,67 +1,49 @@ -/**************************************************************************** - * Copyright (C) 2012-2022 Savoir-faire Linux Inc. * - * Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#pragma once +/* + * Copyright (C) 2012-2022 Savoir-faire Linux Inc. + * Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> + * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ -#ifdef ENABLE_LIBWRAP +#pragma once -// Base -#include <QtCore/QObject> +#include "renderer.h" #include "typedefs.h" -#include "video/renderer.h" -#include "videomanager_interface.h" - -// Qt -class QMutex; -class QTimer; -class QThread; -namespace Video { -class DirectRendererPrivate; +namespace lrc { +namespace video { -/// Manage shared memory and convert it to QByteArray -class LIB_EXPORT DirectRenderer final : public Renderer +class DirectRenderer final : public Renderer { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" Q_OBJECT -#pragma GCC diagnostic pop - public: - // Constructor - DirectRenderer(const QString& id, const QSize& res, bool useAVFrame); - virtual ~DirectRenderer(); + DirectRenderer(const QString& id, const QSize& res); + ~DirectRenderer(); - // Getter - const DRing::SinkTarget& target() const; - const DRing::AVSinkTarget& avTarget() const; - virtual ColorSpace colorSpace() const override; - virtual lrc::api::video::Frame currentFrame() const override; - virtual std::unique_ptr<AVFrame, void (*)(AVFrame*)> currentAVFrame() const override; - void configureTarget(bool useAVFrame); + // Renderer interface. + void update(const QSize& res, const QString& shmPath) override; + lrc::api::video::Frame currentFrame() const override; public Q_SLOTS: - virtual void startRendering() override; - virtual void stopRendering() override; + void startRendering() override; + void stopRendering() override; private: - std::unique_ptr<DirectRendererPrivate> d_ptr; + struct Impl; + std::unique_ptr<Impl> pimpl_; }; -} // namespace Video - -#endif +} // namespace video +} // namespace lrc diff --git a/src/newcallmodel.cpp b/src/newcallmodel.cpp index 4e0188ef9d39dea82c1d6c28423caf747e6eac78..3bd8cb3ee1b4af421c49110265169500c647b817 100644 --- a/src/newcallmodel.cpp +++ b/src/newcallmodel.cpp @@ -33,7 +33,7 @@ #include "dbus/callmanager.h" #include "dbus/videomanager.h" #include "vcard.h" -#include "video/renderer.h" +#include "renderer.h" #include "typedefs.h" #include "uri.h" @@ -45,6 +45,7 @@ #include <QObject> #include <QString> #include <QUrl> +#include <QSize> // std #include <chrono> @@ -118,6 +119,7 @@ using namespace api; class NewCallModelPimpl : public QObject { + Q_OBJECT public: NewCallModelPimpl(const NewCallModel& linked, Lrc& lrc, @@ -773,7 +775,7 @@ NewCallModel::getPendingConferencees() return pimpl_->pendingConferencees_; } -video::RenderedDevice +api::video::RenderedDevice NewCallModel::getCurrentRenderedDevice(const QString& call_id) const { video::RenderedDevice result; @@ -1591,16 +1593,18 @@ NewCallModelPimpl::remoteRecordingChanged(const QString& callId, } void -NewCallModelPimpl::onDecodingStarted(const QString& id, const QString& shmPath, int width, int height) +NewCallModelPimpl::onDecodingStarted(const QString& id, + const QString& shmPath, + int width, + int height) { auto it = calls.find(id); if (it == calls.end()) return; - video::Settings settings; - settings.size = toQString(width) + "x" + toQString(height); - lrc.getAVModel().addRenderer(id, settings, shmPath); + lrc.getAVModel().addRenderer(id, QSize(width, height), shmPath); } } // namespace lrc #include "api/moc_newcallmodel.cpp" +#include "newcallmodel.moc" diff --git a/src/newvideo.cpp b/src/newvideo.cpp deleted file mode 100644 index b48fde0638ba82d624c2767cfeff70e7334e1fde..0000000000000000000000000000000000000000 --- a/src/newvideo.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2018-2022 Savoir-faire Linux Inc. * - * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ - -#include "api/newvideo.h" - -#include "dbus/videomanager.h" -#ifdef ENABLE_LIBWRAP -#include "directrenderer.h" -#else -#include "shmrenderer.h" -#endif - -#include <QSize> - -#include <mutex> - -namespace lrc { - -using namespace api::video; - -class RendererPimpl : public QObject -{ -public: - RendererPimpl(Renderer& linked, - const QString& id, - Settings videoSettings, - const QString& shmPath, - const bool useAVFrame); - ~RendererPimpl(); - - Renderer& linked_; - - QString id_; - Settings videoSettings_; - QThread thread_; - bool usingAVFrame_; - - /** - * Convert a string (WxH) to a QSize - * @param res the string to convert - * @return the QSize object - */ - static QSize stringToQSize(const QString& res); - -#ifdef ENABLE_LIBWRAP - std::unique_ptr<Video::DirectRenderer> renderer; -#else - std::unique_ptr<Video::ShmRenderer> renderer; -#endif - -public Q_SLOTS: - /** - * Detect when the current frame is updated - */ - void slotFrameUpdated(); -}; - -namespace api { - -namespace video { - -Renderer::Renderer(const QString& id, - Settings videoSettings, - const QString& shmPath, - const bool useAVFrame) - : pimpl_(std::make_unique<RendererPimpl>(*this, id, videoSettings, shmPath, useAVFrame)) -{} - -Renderer::~Renderer() -{ -#ifdef ENABLE_LIBWRAP - if (pimpl_->usingAVFrame_) { - VideoManager::instance().registerAVSinkTarget(pimpl_->id_, {}); - } else { - VideoManager::instance().registerSinkTarget(pimpl_->id_, {}); - } -#else - VideoManager::instance().startShmSink(pimpl_->id_, false); -#endif // ENABLE_LIBWRAP - - pimpl_.reset(); -} - -void -Renderer::update(const QString& res, const QString& shmPath) -{ - if (!pimpl_->thread_.isRunning()) - pimpl_->thread_.start(); - - // res = "WIDTHxHEIGHT" - QSize size = RendererPimpl::stringToQSize(res); - pimpl_->renderer->setSize(size); - -#ifdef ENABLE_LIBWRAP - Q_UNUSED(shmPath) - if (pimpl_->usingAVFrame_) { - VideoManager::instance().registerAVSinkTarget(pimpl_->id_, pimpl_->renderer->avTarget()); - } else { - VideoManager::instance().registerSinkTarget(pimpl_->id_, pimpl_->renderer->target()); - } -#else // ENABLE_LIBWRAP - pimpl_->renderer->setShmPath(shmPath); - VideoManager::instance().startShmSink(pimpl_->id_, true); -#endif -} - -bool -Renderer::isRendering() const -{ - if (pimpl_->renderer) - return pimpl_->renderer->isRendering(); - return false; -} - -void -Renderer::useAVFrame(bool useAVFrame) -{ - pimpl_->usingAVFrame_ = useAVFrame; -#ifdef ENABLE_LIBWRAP - pimpl_->renderer->configureTarget(useAVFrame); -#endif -} - -bool -Renderer::useDirectRenderer() const -{ -#ifdef ENABLE_LIBWRAP - return true; -#else - return false; -#endif -} - -QString -Renderer::getId() const -{ - return pimpl_->id_; -} - -Frame -Renderer::currentFrame() const -{ - // TODO(sblin) remove Video::Frame when deleting old models. - auto frame = pimpl_->renderer->currentFrame(); - Frame result; - result.ptr = frame.ptr; - result.size = frame.size; - result.storage = frame.storage; - result.height = frame.height; - result.width = frame.width; - return result; -} - -#if defined(ENABLE_LIBWRAP) -std::unique_ptr<AVFrame, void (*)(AVFrame*)> -Renderer::currentAVFrame() const -{ - return pimpl_->renderer->currentAVFrame(); -} -#endif - -QSize -Renderer::size() const -{ - return pimpl_->renderer->size(); -} - -} // namespace video -} // namespace api - -RendererPimpl::RendererPimpl(Renderer& linked, - const QString& id, - Settings videoSettings, - const QString& shmPath, - bool useAVFrame) - : linked_(linked) - , id_(id) - , videoSettings_(videoSettings) - , usingAVFrame_(useAVFrame) -{ - QSize size = stringToQSize(videoSettings.size); -#ifdef ENABLE_LIBWRAP - Q_UNUSED(shmPath) - renderer = std::make_unique<Video::DirectRenderer>(id, size, usingAVFrame_); -#else // ENABLE_LIBWRAP - renderer = std::make_unique<Video::ShmRenderer>(id, shmPath, size); -#endif - renderer->moveToThread(&thread_); - - 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()); - } -#else - VideoManager::instance().startShmSink(id_, true); -#endif - - thread_.start(); -} - -RendererPimpl::~RendererPimpl() -{ - thread_.quit(); - thread_.wait(); -} - -QSize -RendererPimpl::stringToQSize(const QString& res) -{ - QString sizeStr = res; - auto sizeSplited = sizeStr.split('x'); - if (sizeSplited.size() != 2) - return {}; - auto width = sizeSplited.at(0).toInt(); - auto height = sizeSplited.at(1).toInt(); - return QSize(width, height); -} - -} // end of namespace lrc - -#include "api/moc_newvideo.cpp" diff --git a/src/private/videorenderer_p.h b/src/private/videorenderer_p.h deleted file mode 100644 index c247d4f16b5c87252a6a0bbba43b58496c7ce000..0000000000000000000000000000000000000000 --- a/src/private/videorenderer_p.h +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2022 Savoir-faire Linux Inc. * - * 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 * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#pragma once - -// Qt -#include <QtCore/QObject> -#include <QtCore/QSize> - -#include "api/newvideo.h" - -// Std -#include <atomic> -#include <memory> - -class QMutex; - -namespace Video { - -class Renderer; - -class RendererPrivate final : public QObject -{ - Q_OBJECT -public: - RendererPrivate(Video::Renderer* parent); - - // Attributes - std::atomic_bool m_isRendering; - QMutex* m_pMutex; - QString m_Id; - QSize m_pSize; - std::shared_ptr<lrc::api::video::Frame> m_pFrame; // frame given by daemon for direct rendering -private: - Video::Renderer* q_ptr; -}; - -} // namespace Video diff --git a/src/renderer.cpp b/src/renderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a2065fd133cf170b092b78ad6e82b0f59f191fe --- /dev/null +++ b/src/renderer.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018-2022 Savoir-faire Linux Inc. + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "renderer.h" + +#include <QSize> +#include <QMutex> + +namespace lrc { +namespace video { + +using namespace lrc::api::video; + +Renderer::Renderer(const QString& id, const QSize& res) + : id_(id) + , size_(res) + , QObject(nullptr) +{} + +Renderer::~Renderer() {} + +QString +Renderer::id() const +{ + return id_; +} + +QSize +Renderer::size() const +{ + return size_; +} + +void +Renderer::update(const QSize& size, const QString&) +{ + size_ = size; +} + +} // namespace video +} // namespace lrc diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000000000000000000000000000000000000..9e91bc29fdf01cd7f266be8311fd3a830d1d3349 --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018-2022 Savoir-faire Linux Inc. + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "api/video.h" +#include "typedefs.h" + +#include <QObject> +#include <QSize> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +namespace lrc { +namespace video { + +class Renderer : public QObject +{ + Q_OBJECT +public: + Renderer(const QString& id, const QSize& res); + virtual ~Renderer(); + + /** + * @return renderer's id + */ + QString id() const; + + /** + * @return current renderer dimensions + */ + QSize size() const; + + /** + * Update size and shmPath of a renderer + * @param size new renderer dimensions + * @param shmPath new shmPath + */ + virtual void update(const QSize& size, const QString& shmPath = {}); + + /** + * @return current rendered frame + */ + virtual lrc::api::video::Frame currentFrame() const = 0; + +public Q_SLOTS: + virtual void startRendering() = 0; + virtual void stopRendering() = 0; + +Q_SIGNALS: + void frameUpdated(); + void stopped(); + void started(); + void frameBufferRequested(AVFrame* avFrame); + +private: + QString id_; + QSize size_; +}; + +} // namespace video +} // namespace lrc diff --git a/src/shmrenderer.cpp b/src/shmrenderer.cpp index 2a007722f17ab006011c5e7394471ae8d09a1fb0..ab7f9e175a40cdec43116edd9f3268259a7a3587 100644 --- a/src/shmrenderer.cpp +++ b/src/shmrenderer.cpp @@ -1,28 +1,30 @@ -/**************************************************************************** - * Copyright (C) 2012-2022 Savoir-faire Linux Inc. * - * 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 * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#ifndef ENABLE_LIBWRAP +/* + * Copyright (C) 2012-2022 Savoir-faire Linux Inc. + * 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include "shmrenderer.h" -#include <QtCore/QDebug> -#include <QtCore/QMutex> -#include <QtCore/QThread> +#include "dbus/videomanager.h" +#include "videomanager_interface.h" + +#include <QDebug> +#include <QMutex> +#include <QThread> #include <sys/ipc.h> #include <sys/sem.h> @@ -37,10 +39,15 @@ #define CLOCK_REALTIME 0 #endif -#include <QtCore/QTimer> +#include <QTimer> + #include <chrono> -#include "private/videorenderer_p.h" +namespace lrc { + +using namespace api::video; + +namespace video { // Uncomment following line to output in console the FPS value //#define DEBUG_FPS @@ -69,330 +76,274 @@ struct SHMHeader #pragma GCC diagnostic pop }; -namespace Video { - -class ShmRendererPrivate final : public QObject +struct ShmRenderer::Impl final : public QObject { Q_OBJECT - 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; - QTimer* m_pTimer; + Impl(ShmRenderer* parent) + : QObject(nullptr) + , parent_(parent) + , fd(-1) + , shmArea((SHMHeader*) MAP_FAILED) + , shmAreaLen(0) + , frameGen(0) + , fpsC(0) + , fps(0) + , timer(new QTimer(this)) +#ifdef DEBUG_FPS + , frameCount(0) + , lastFrameDebug(std::chrono::system_clock::now()) +#endif + { + timer->setInterval(33); + connect(timer, &QTimer::timeout, [this]() { Q_EMIT parent_->frameUpdated(); }); + VideoManager::instance().startShmSink(parent_->id(), true); + + parent_->moveToThread(&thread); + connect(&thread, &QThread::finished, [this] { parent_->stopRendering(); }); + thread.start(); + }; + ~Impl() + { + thread.quit(); + thread.wait(); + } // 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(); + // Lock the memory while the copy is being made + bool shmLock() { return ::sem_wait(&shmArea->mutex) >= 0; }; -private: - Video::ShmRenderer* q_ptr; -}; + // Remove the lock, allow a new frame to be drawn + void shmUnlock() { ::sem_post(&shmArea->mutex); }; -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) - , m_pTimer(nullptr) -#ifdef DEBUG_FPS - , m_frameCount(0) - , m_lastFrameDebug(std::chrono::system_clock::now()) -#endif -{} + // Wait for new frame data from shared memory and save pointer. + bool getNewFrame(bool wait) + { + if (!shmLock()) + return false; -/// Constructor -ShmRenderer::ShmRenderer(const QString& id, const QString& shmPath, const QSize& res) - : Renderer(id, res) - , d_ptr(std::make_unique<ShmRendererPrivate>(this)) -{ - d_ptr->m_ShmPath = shmPath; - setObjectName("Video::Renderer:" + id); -} + if (frameGen == shmArea->frameGen) { + shmUnlock(); -/// Destructor -ShmRenderer::~ShmRenderer() -{ - stopShm(); -} + if (not wait) + return false; -/// Wait new frame data from shared memory and save pointer -bool -ShmRendererPrivate::getNewFrame(bool wait) -{ - if (!shmLock()) - return false; + // wait for a new frame, max 33ms + static const struct timespec timeout = {0, 33000000}; + if (::sem_timedwait(&shmArea->frameGenMutex, &timeout) < 0) + return false; - if (m_FrameGen == m_pShmArea->frameGen) { - shmUnlock(); + if (!shmLock()) + return false; + } - if (not wait) + // valid frame to render (daemon may have stopped)? + if (!shmArea->frameSize) { + shmUnlock(); return false; + } - // wait for a new frame, max 33ms - static const struct timespec timeout = {0, 33000000}; - if (::sem_timedwait(&m_pShmArea->frameGenMutex, &timeout) < 0) + // map frame data + if (!remapShm()) { + qDebug() << "Could not resize shared memory"; return false; + } - if (!shmLock()) - return false; - } + if (not frame) + frame.reset(new lrc::api::video::Frame); + frame->ptr = shmArea->data + shmArea->readOffset; + frame->size = shmArea->frameSize; + frameGen = shmArea->frameGen; - // 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"; - return false; - } + ++fpsC; - auto& frame_ptr = q_ptr->Video::Renderer::d_ptr->m_pFrame; - if (not frame_ptr) - frame_ptr.reset(new lrc::api::video::Frame); - frame_ptr->storage.clear(); - frame_ptr->ptr = m_pShmArea->data + m_pShmArea->readOffset; - frame_ptr->size = m_pShmArea->frameSize; - m_FrameGen = m_pShmArea->frameGen; - - 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 = (int) (m_fpsC / seconds.count()); - m_fpsC = 0; - m_lastFrameDebug = currentTime; + // Compute the FPS shown to the client + auto currentTime = std::chrono::system_clock::now(); + const std::chrono::duration<double> seconds = currentTime - lastFrameDebug; + if (seconds.count() >= FPS_RATE_SEC) { + fps = (int) (fpsC / seconds.count()); + fpsC = 0; + lastFrameDebug = currentTime; #ifdef DEBUG_FPS - qDebug() << this << ": FPS " << m_fps; + qDebug() << this << ": FPS " << fps; #endif - } + } - return true; -} + return true; + }; -/// Remap the shared memory -/// Shared memory in unlocked state if returns false (resize failed). -bool -ShmRendererPrivate::remapShm() -{ - // This loop handles case where daemon resize shared memory - // during time we unlock it for remapping. - while (m_ShmAreaLen != m_pShmArea->mapSize) { - auto mapSize = m_pShmArea->mapSize; - shmUnlock(); + // Remap the shared memory. + // Shared memory is in an unlocked state if returns false (resize failed). + bool remapShm() + { + // This loop handles case where daemon resize shared memory + // during time we unlock it for remapping. + while (shmAreaLen != shmArea->mapSize) { + auto mapSize = shmArea->mapSize; + shmUnlock(); - if (::munmap(m_pShmArea, m_ShmAreaLen)) { - qDebug() << "Could not unmap shared area: " << strerror(errno); - return false; - } + if (::munmap(shmArea, 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); + shmArea + = (SHMHeader*) ::mmap(nullptr, mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (m_pShmArea == MAP_FAILED) { - qDebug() << "Could not remap shared area: " << strerror(errno); - return false; + if (shmArea == MAP_FAILED) { + qDebug() << "Could not remap shared area: " << strerror(errno); + return false; + } + + if (!shmLock()) + return false; + + shmAreaLen = mapSize; } - if (!shmLock()) - return false; + return true; + }; - m_ShmAreaLen = mapSize; - } +private: + ShmRenderer* parent_; - return true; +public: + QString path; + int fd; + SHMHeader* shmArea; + unsigned shmAreaLen; + uint frameGen; + + int fpsC; + int fps; + std::chrono::time_point<std::chrono::system_clock> lastFrameDebug; + + QTimer* timer; + QMutex mutex; + QThread thread; + std::shared_ptr<lrc::api::video::Frame> frame; +}; + +ShmRenderer::ShmRenderer(const QString& id, const QSize& res, const QString& shmPath) + : Renderer(id, res) + , pimpl_(std::make_unique<ShmRenderer::Impl>(this)) +{ + pimpl_->path = shmPath; +} + +ShmRenderer::~ShmRenderer() +{ + VideoManager::instance().startShmSink(id(), false); + stopShm(); +} + +void +ShmRenderer::update(const QSize& res, const QString& shmPath) +{ + Renderer::update(res); + + if (!pimpl_->thread.isRunning()) + pimpl_->thread.start(); + + pimpl_->path = shmPath; + VideoManager::instance().startShmSink(id(), true); +} + +Frame +ShmRenderer::currentFrame() const +{ + QMutexLocker lk {&pimpl_->mutex}; + if (pimpl_->getNewFrame(false)) { + if (auto frame_ptr = pimpl_->frame) + return std::move(*frame_ptr); + } + return {}; } -/// Connect to the shared memory bool ShmRenderer::startShm() { - if (d_ptr->m_fd != -1) { + if (pimpl_->fd != -1) { qWarning() << "fd must be -1"; return false; } - d_ptr->m_fd = ::shm_open(d_ptr->m_ShmPath.toLatin1(), O_RDWR, 0); + pimpl_->fd = ::shm_open(pimpl_->path.toLatin1(), O_RDWR, 0); - if (d_ptr->m_fd < 0) { - qWarning() << "could not open shm area" << d_ptr->m_ShmPath + if (pimpl_->fd < 0) { + qWarning() << "could not open shm area" << pimpl_->path << ", shm_open failed:" << strerror(errno); return false; } // 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); + pimpl_->shmArea + = (SHMHeader*) ::mmap(nullptr, mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, pimpl_->fd, 0); - if (d_ptr->m_pShmArea == MAP_FAILED) { + if (pimpl_->shmArea == MAP_FAILED) { qWarning() << "Could not remap shared area"; return false; } - d_ptr->m_ShmAreaLen = mapSize; + pimpl_->shmAreaLen = mapSize; return true; } -/// Disconnect from the shared memory void ShmRenderer::stopShm() { - if (d_ptr->m_fd < 0) + if (pimpl_->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; - } + pimpl_->timer->stop(); // Emit the signal before closing the file, this lower the risk of invalid // memory access - emit stopped(); + Q_EMIT stopped(); { - QMutexLocker lk {mutex()}; + QMutexLocker lk(&pimpl_->mutex); // reset the frame so it doesn't point to an old value - Video::Renderer::d_ptr->m_pFrame.reset(); + pimpl_->frame.reset(); } - ::close(d_ptr->m_fd); - d_ptr->m_fd = -1; + ::close(pimpl_->fd); + pimpl_->fd = -1; - if (d_ptr->m_pShmArea == MAP_FAILED) + if (pimpl_->shmArea == 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 -bool -ShmRendererPrivate::shmLock() -{ - return ::sem_wait(&m_pShmArea->mutex) >= 0; -} - -/// Remove the lock, allow a new frame to be drawn -void -ShmRendererPrivate::shmUnlock() -{ - ::sem_post(&m_pShmArea->mutex); + ::munmap(pimpl_->shmArea, pimpl_->shmAreaLen); + pimpl_->shmAreaLen = 0; + pimpl_->shmArea = (SHMHeader*) MAP_FAILED; } -/***************************************************************************** - * * - * Slots * - * * - ****************************************************************************/ - -/// Start the rendering loop void ShmRenderer::startRendering() { - QMutexLocker locker {mutex()}; + QMutexLocker lk(&pimpl_->mutex); - if (!startShm() || Video::Renderer::d_ptr->m_isRendering) + if (!startShm()) return; - Video::Renderer::d_ptr->m_isRendering = true; - - if (!d_ptr->m_pTimer) { - d_ptr->m_pTimer = new QTimer(this); - d_ptr->m_pTimer->setInterval(33); - connect(d_ptr->m_pTimer, &QTimer::timeout, [this]() { emit this->frameUpdated(); }); - } - // FIXME This is a temporary hack as frameUpdated() is no longer emitted - d_ptr->m_pTimer->start(); + pimpl_->timer->start(); - emit started(); + Q_EMIT started(); } -/// Done on destroy instead +// Done on destroy instead void ShmRenderer::stopRendering() {} -/***************************************************************************** - * * - * Getters * - * * - ****************************************************************************/ +} // namespace video +} // namespace lrc -/// Get the current frame rate of this renderer -int -ShmRenderer::fps() const -{ - return d_ptr->m_Fps; -} - -/// Get frame data pointer from shared memory -lrc::api::video::Frame -ShmRenderer::currentFrame() const -{ - if (not isRendering()) - return {}; - - QMutexLocker lk {mutex()}; - if (d_ptr->getNewFrame(false)) { - if (auto frame_ptr = Video::Renderer::d_ptr->m_pFrame) - return std::move(*frame_ptr); - } - return {}; -} - -Video::Renderer::ColorSpace -ShmRenderer::colorSpace() const -{ - return Video::Renderer::ColorSpace::BGRA; -} - -/***************************************************************************** - * * - * Setters * - * * - ****************************************************************************/ - -void -ShmRenderer::setShmPath(const QString& path) -{ - d_ptr->m_ShmPath = path; -} - -} // namespace Video - -#include <shmrenderer.moc> - -#endif +#include "moc_shmrenderer.cpp" +#include "shmrenderer.moc" diff --git a/src/shmrenderer.h b/src/shmrenderer.h index 56445b367420b096d48f6f5515f988e03e77d201..7880432a1c5829ee217ea877b1691e15f2bdf109 100644 --- a/src/shmrenderer.h +++ b/src/shmrenderer.h @@ -1,72 +1,51 @@ -/**************************************************************************** - * Copyright (C) 2012-2022 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#pragma once +/* + * Copyright (C) 2012-2022 Savoir-faire Linux Inc. + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ -#ifndef ENABLE_LIBWRAP +#pragma once -// Base -#include "video/renderer.h" +#include "renderer.h" #include "typedefs.h" -#include "api/newvideo.h" - -// Qt -class QMutex; - -// Private -struct SHMHeader; -struct AVFrame; -namespace Video { -class ShmRendererPrivate; +namespace lrc { +namespace video { -/// Manage shared memory and convert it to QByteArray -class LIB_EXPORT ShmRenderer final : public Renderer +class ShmRenderer final : public Renderer { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" Q_OBJECT -#pragma GCC diagnostic pop - public: - // Constructor - ShmRenderer(const QString& id, const QString& shmPath, const QSize& res); - virtual ~ShmRenderer(); + ShmRenderer(const QString& id, const QSize& res, const QString& shmPath); + ~ShmRenderer(); + + // Renderer interface. + void update(const QSize& res, const QString& shmPath) override; + lrc::api::video::Frame currentFrame() const override; - // Mutators void stopShm(); bool startShm(); - // Getters - int fps() const; - virtual lrc::api::video::Frame currentFrame() const override; - virtual ColorSpace colorSpace() const override; - - // Setters - void setShmPath(const QString& path); - -private: - std::unique_ptr<ShmRendererPrivate> d_ptr; - public Q_SLOTS: void startRendering() override; - void stopRendering() override; // Unused -}; + void stopRendering() override; -} // namespace Video +private: + struct Impl; + std::unique_ptr<Impl> pimpl_; +}; -#endif +} // namespace video +} // namespace lrc diff --git a/src/video/renderer.cpp b/src/video/renderer.cpp deleted file mode 100644 index cfe96fd4183ea8edf0c82867d46720f26b00c1d0..0000000000000000000000000000000000000000 --- a/src/video/renderer.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2022 Savoir-faire Linux Inc. * - * Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#include "renderer.h" - -// Ring -#include "private/videorenderer_p.h" - -// Qt -#include <QtCore/QMutex> - -Video::RendererPrivate::RendererPrivate(Video::Renderer* parent) - : QObject(parent) - , m_isRendering(false) - , m_pMutex(new QMutex()) - , q_ptr(parent) -{} - -Video::Renderer::Renderer(const QString& id, const QSize& res) - : d_ptr(new RendererPrivate(this)) -{ - setObjectName("Renderer:" + id); - d_ptr->m_pSize = res; - d_ptr->m_Id = id; -} - -Video::Renderer::~Renderer() -{ - delete d_ptr; -} - -/***************************************************************************** - * * - * Getters * - * * - ****************************************************************************/ - -/// Return if the rendering is currently active or not -bool -Video::Renderer::isRendering() const -{ - return d_ptr->m_isRendering; -} - -/// Get mutex, in case renderer and views are not in the same thread -QMutex* -Video::Renderer::mutex() const -{ - return d_ptr->m_pMutex; -} - -/// Return the current resolution -QSize -Video::Renderer::size() const -{ - return d_ptr->m_pSize; -} - -/***************************************************************************** - * * - * Setters * - * * - ****************************************************************************/ - -void -Video::Renderer::setSize(const QSize& size) const -{ - d_ptr->m_pSize = size; -} diff --git a/src/video/renderer.h b/src/video/renderer.h deleted file mode 100644 index cc297b70783872c2352b9fe22417154fe01387d2..0000000000000000000000000000000000000000 --- a/src/video/renderer.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2022 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ -#pragma once - -// Base -#include <QtCore/QObject> -#include "api/newvideo.h" -#include <typedefs.h> - -// Std -#include <memory> -#include <vector> -#include <cstdint> - -// Qt -class QMutex; -struct AVFrame; - -namespace Video { - -class RendererPrivate; -class ShmRendererPrivate; -class ShmRenderer; -class DirectRendererPrivate; -class DirectRenderer; - -/** - * This class is used by Renderer class to expose video data frame - * that could be owned by instances of this class or shared. - * If an instance carries data, "storage.size()" is greater than 0 - * and equals to "size", "ptr" is equals to "storage.data()". - * If shared data is carried, only "ptr" and "size" are set. - */ -struct Frame -{ - uint8_t* ptr {nullptr}; - std::size_t size {0}; - std::vector<uint8_t> storage {}; - // Next variables are currently used with DirectRenderer only - unsigned int height {0}; - unsigned int width {0}; -}; - -/** - * This class provide a rendering object to be used by clients - * to get the video content. This object is not intended to be - * extended outside of the LibRingClient. - * - * Each platform transparently provide its own implementation. - */ -class LIB_EXPORT Renderer : public QObject -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT -#pragma GCC diagnostic pop - - friend class Video::ShmRendererPrivate; - friend class Video::ShmRenderer; - friend class Video::DirectRendererPrivate; - friend class Video::DirectRenderer; - -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 QString& id, const QSize& res); - virtual ~Renderer(); - - // Getters - virtual bool isRendering() const; - virtual lrc::api::video::Frame currentFrame() const = 0; - virtual QSize size() const; - virtual QMutex* mutex() const; - virtual ColorSpace colorSpace() const = 0; -#if defined(ENABLE_LIBWRAP) - virtual std::unique_ptr<AVFrame, void (*)(AVFrame*)> currentAVFrame() const = 0; -#endif - void setSize(const QSize& size) const; - -Q_SIGNALS: - void frameUpdated(); // Emitted when a new frame is ready - void stopped(); - void started(); - -public Q_SLOTS: - virtual void startRendering() = 0; - virtual void stopRendering() = 0; - -private: - RendererPrivate* d_ptr; - Q_DECLARE_PRIVATE(Renderer) -}; - -} // namespace Video