/* * Copyright (C) 2019-2020 by Savoir-faire Linux * Author: Andreas Traczyk * Author: Mingrui Zhang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program 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 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 . */ #pragma once #include "api/avmodel.h" #include "api/lrc.h" #include #include #include using namespace lrc::api; /* * This class acts as a QImage rendering sink and manages * signal/slot connections to it's underlying (AVModel) renderer * corresponding to the object's renderer id. * A QImage pointer is provisioned and updated once rendering * starts. */ struct RenderConnections { QMetaObject::Connection started, stopped, updated; }; class FrameWrapper final : public QObject { Q_OBJECT; public: FrameWrapper(AVModel &avModel, const QString &id = video::PREVIEW_RENDERER_ID); ~FrameWrapper(); /* * Reconnect the started rendering connection for this object. */ void connectStartRendering(); /* * Get a pointer to the renderer and reconnect the update/stopped * rendering connections for this object. * @return whether the start succeeded or not */ bool startRendering(); /* * Get the most recently rendered frame as a QImage. * @return the rendered image of this object's id */ QImage *getFrame(); /* * Check if the object is updating actively. */ bool isRendering(); signals: /* * Emitted once in slotRenderingStarted. * @param id of the renderer */ void renderingStarted(const QString &id); /* * Emitted each time a frame is ready to be displayed. * @param id of the renderer */ void frameUpdated(const QString &id); /* * Emitted once in slotRenderingStopped. * @param id of the renderer */ void renderingStopped(const QString &id); private slots: /* * Used to listen to AVModel::rendererStarted. * @param id of the renderer */ void slotRenderingStarted(const QString &id = video::PREVIEW_RENDERER_ID); /* * Used to listen to AVModel::frameUpdated. * @param id of the renderer */ void slotFrameUpdated(const QString &id = video::PREVIEW_RENDERER_ID); /* * Used to listen to AVModel::renderingStopped. * @param id of the renderer */ void slotRenderingStopped(const QString &id = video::PREVIEW_RENDERER_ID); private: /* * The id of the renderer. */ QString id_; /* * A pointer to the lrc renderer object. */ video::Renderer *renderer_; /* * A local copy of the renderer's current frame. */ video::Frame frame_; /* * A the frame's storage data used to set the image. */ std::vector buffer_; /* * The frame's paint ready QImage. */ std::unique_ptr image_; /* * Used to protect the buffer during QImage creation routine. */ QMutex mutex_; /* * True if the object is rendering */ std::atomic_bool isRendering_; /* * Convenience ref to avmodel */ AVModel &avModel_; /* * Connections to the underlying renderer signals in avmodel */ RenderConnections renderConnections_; }; /** * RenderManager filters signals and ecapsulates preview and distant * frame wrappers, providing access to QImages for each and simplified * start/stop mechanisms for renderers. It should contain as much * renderer control logic as possible and prevent ui widgets from directly * interfacing the rendering logic. */ class RenderManager final : public QObject { Q_OBJECT; public: explicit RenderManager(AVModel &avModel); ~RenderManager(); /* * Check if the preview is active. */ bool isPreviewing(); /* * Get the most recently rendered preview frame as a QImage. * @return the rendered preview image */ QImage *getPreviewFrame(); /* * Start capturing and rendering preview frames. * @param force if the capture device should be started * @param async */ void startPreviewing(bool force = false, bool async = true); /* * Stop capturing. * @param async */ void stopPreviewing(bool async = true); /* * Get the most recently rendered distant frame for a given id * as a QImage. * @return the rendered preview image */ QImage *getFrame(const QString &id); /* * Add and connect a distant renderer for a given id * to a FrameWrapper object * @param id */ void addDistantRenderer(const QString &id); /* * Disconnect and remove a FrameWrapper object connected to a * distant renderer for a given id * @param id */ void removeDistantRenderer(const QString &id); signals: /* * Emitted when the size of the video capture device list changes. */ void videoDeviceListChanged(); /* * Emitted when the preview is started. */ void previewRenderingStarted(); /* * Emitted when the preview has a new frame ready. */ void previewFrameUpdated(); /* * Emitted when the preview is stopped. */ void previewRenderingStopped(); /* * Emitted when a distant renderer is started for a given id. */ void distantRenderingStarted(const QString &id); /* * Emitted when a distant renderer has a new frame ready for a given id. */ void distantFrameUpdated(const QString &id); /* * Emitted when a distant renderer is stopped for a given id. */ void distantRenderingStopped(const QString &id); private slots: /* * Used to listen to AVModel::deviceEvent. */ void slotDeviceEvent(); private: /* * Used to classify capture device events. */ enum class DeviceEvent { Added, RemovedCurrent, None }; /* * Used to track the capture device count. */ int deviceListSize_; /* * One preview frame. */ std::unique_ptr previewFrameWrapper_; /* * Distant for each call/conf/conversation. */ std::map> distantFrameWrapperMap_; std::map distantConnectionMap_; /* * Convenience ref to avmodel. */ AVModel &avModel_; }; Q_DECLARE_METATYPE(RenderManager *)