blob: c3c3f1642eba407720ca094f845ee3ee611d479f [file] [log] [blame]
Sébastien Blin1f915762020-08-03 13:27:42 -04001/*
2 * Copyright (C) 2019-2020 by Savoir-faire Linux
3 * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
4 * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include "api/avmodel.h"
23#include "api/lrc.h"
24
25#include <QImage>
26#include <QMutex>
27#include <QObject>
28
29using namespace lrc::api;
30
31/*
32 * This class acts as a QImage rendering sink and manages
33 * signal/slot connections to it's underlying (AVModel) renderer
34 * corresponding to the object's renderer id.
35 * A QImage pointer is provisioned and updated once rendering
36 * starts.
37 */
38
39struct RenderConnections
40{
41 QMetaObject::Connection started, stopped, updated;
42};
43
44class FrameWrapper final : public QObject
45{
46 Q_OBJECT;
47
48public:
49 FrameWrapper(AVModel &avModel, const QString &id = video::PREVIEW_RENDERER_ID);
50 ~FrameWrapper();
51
52 /*
53 * Reconnect the started rendering connection for this object.
54 */
55 void connectStartRendering();
56
57 /*
58 * Get a pointer to the renderer and reconnect the update/stopped
59 * rendering connections for this object.
60 * @return whether the start succeeded or not
61 */
62 bool startRendering();
63
64 /*
65 * Get the most recently rendered frame as a QImage.
66 * @return the rendered image of this object's id
67 */
68 QImage *getFrame();
69
70 /*
71 * Check if the object is updating actively.
72 */
73 bool isRendering();
74
75signals:
76 /*
77 * Emitted once in slotRenderingStarted.
78 * @param id of the renderer
79 */
80 void renderingStarted(const QString &id);
81 /*
82 * Emitted each time a frame is ready to be displayed.
83 * @param id of the renderer
84 */
85 void frameUpdated(const QString &id);
86 /*
87 * Emitted once in slotRenderingStopped.
88 * @param id of the renderer
89 */
90 void renderingStopped(const QString &id);
91
92private slots:
93 /*
94 * Used to listen to AVModel::rendererStarted.
95 * @param id of the renderer
96 */
97 void slotRenderingStarted(const QString &id = video::PREVIEW_RENDERER_ID);
98 /*
99 * Used to listen to AVModel::frameUpdated.
100 * @param id of the renderer
101 */
102 void slotFrameUpdated(const QString &id = video::PREVIEW_RENDERER_ID);
103 /*
104 * Used to listen to AVModel::renderingStopped.
105 * @param id of the renderer
106 */
107 void slotRenderingStopped(const QString &id = video::PREVIEW_RENDERER_ID);
108
109private:
110 /*
111 * The id of the renderer.
112 */
113 QString id_;
114
115 /*
116 * A pointer to the lrc renderer object.
117 */
118 video::Renderer *renderer_;
119
120 /*
121 * A local copy of the renderer's current frame.
122 */
123 video::Frame frame_;
124
125 /*
126 * A the frame's storage data used to set the image.
127 */
128 std::vector<uint8_t> buffer_;
129
130 /*
131 * The frame's paint ready QImage.
132 */
133 std::unique_ptr<QImage> image_;
134
135 /*
136 * Used to protect the buffer during QImage creation routine.
137 */
138 QMutex mutex_;
139
140 /*
141 * True if the object is rendering
142 */
143 std::atomic_bool isRendering_;
144
145 /*
146 * Convenience ref to avmodel
147 */
148 AVModel &avModel_;
149
150 /*
151 * Connections to the underlying renderer signals in avmodel
152 */
153 RenderConnections renderConnections_;
154};
155
156/**
157 * RenderManager filters signals and ecapsulates preview and distant
158 * frame wrappers, providing access to QImages for each and simplified
159 * start/stop mechanisms for renderers. It should contain as much
160 * renderer control logic as possible and prevent ui widgets from directly
161 * interfacing the rendering logic.
162 */
163class RenderManager final : public QObject
164{
165 Q_OBJECT;
166
167public:
168 explicit RenderManager(AVModel &avModel);
169 ~RenderManager();
170
171 /*
172 * Check if the preview is active.
173 */
174 bool isPreviewing();
175 /*
176 * Get the most recently rendered preview frame as a QImage.
177 * @return the rendered preview image
178 */
179 QImage *getPreviewFrame();
180 /*
181 * Start capturing and rendering preview frames.
182 * @param force if the capture device should be started
183 * @param async
184 */
185 void startPreviewing(bool force = false, bool async = true);
186 /*
187 * Stop capturing.
188 * @param async
189 */
190 void stopPreviewing(bool async = true);
191
192 /*
193 * Get the most recently rendered distant frame for a given id
194 * as a QImage.
195 * @return the rendered preview image
196 */
197 QImage *getFrame(const QString &id);
198 /*
199 * Add and connect a distant renderer for a given id
200 * to a FrameWrapper object
201 * @param id
202 */
203 void addDistantRenderer(const QString &id);
204 /*
205 * Disconnect and remove a FrameWrapper object connected to a
206 * distant renderer for a given id
207 * @param id
208 */
209 void removeDistantRenderer(const QString &id);
210
211signals:
212 /*
213 * Emitted when the size of the video capture device list changes.
214 */
215 void videoDeviceListChanged();
216
217 /*
218 * Emitted when the preview is started.
219 */
220 void previewRenderingStarted();
221
222 /*
223 * Emitted when the preview has a new frame ready.
224 */
225 void previewFrameUpdated();
226
227 /*
228 * Emitted when the preview is stopped.
229 */
230 void previewRenderingStopped();
231
232 /*
233 * Emitted when a distant renderer is started for a given id.
234 */
235 void distantRenderingStarted(const QString &id);
236
237 /*
238 * Emitted when a distant renderer has a new frame ready for a given id.
239 */
240 void distantFrameUpdated(const QString &id);
241
242 /*
243 * Emitted when a distant renderer is stopped for a given id.
244 */
245 void distantRenderingStopped(const QString &id);
246
247private slots:
248 /*
249 * Used to listen to AVModel::deviceEvent.
250 */
251 void slotDeviceEvent();
252
253private:
254 /*
255 * Used to classify capture device events.
256 */
257 enum class DeviceEvent { Added, RemovedCurrent, None };
258
259 /*
260 * Used to track the capture device count.
261 */
262 int deviceListSize_;
263
264 /*
265 * One preview frame.
266 */
267 std::unique_ptr<FrameWrapper> previewFrameWrapper_;
268
269 /*
270 * Distant for each call/conf/conversation.
271 */
272 std::map<QString, std::unique_ptr<FrameWrapper>> distantFrameWrapperMap_;
273 std::map<QString, RenderConnections> distantConnectionMap_;
274
275 /*
276 * Convenience ref to avmodel.
277 */
278 AVModel &avModel_;
279};
Sébastien Blin1f915762020-08-03 13:27:42 -0400280Q_DECLARE_METATYPE(RenderManager *)