blob: c3c3f1642eba407720ca094f845ee3ee611d479f [file] [log] [blame]
/*
* Copyright (C) 2019-2020 by Savoir-faire Linux
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "api/avmodel.h"
#include "api/lrc.h"
#include <QImage>
#include <QMutex>
#include <QObject>
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<uint8_t> buffer_;
/*
* The frame's paint ready QImage.
*/
std::unique_ptr<QImage> 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<FrameWrapper> previewFrameWrapper_;
/*
* Distant for each call/conf/conversation.
*/
std::map<QString, std::unique_ptr<FrameWrapper>> distantFrameWrapperMap_;
std::map<QString, RenderConnections> distantConnectionMap_;
/*
* Convenience ref to avmodel.
*/
AVModel &avModel_;
};
Q_DECLARE_METATYPE(RenderManager *)