1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40
41/*!
42 \class QVideoProbe
43 \inmodule QtMultimedia
44
45 \ingroup multimedia
46 \ingroup multimedia_video
47
48 \brief The QVideoProbe class allows you to monitor video frames being played or recorded.
49
50 \code
51 QMediaPlayer *player = new QMediaPlayer();
52 QVideoProbe *probe = new QVideoProbe;
53
54 connect(probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
55
56 probe->setSource(player); // Returns true, hopefully.
57
58 player->setVideoOutput(myVideoSurface);
59 player->setMedia(QUrl::fromLocalFile("observation.mp4"));
60 player->play(); // Start receiving frames as they get presented to myVideoSurface
61 \endcode
62
63 This same approach works with the QCamera object as well, to receive viewfinder or video
64 frames as they are captured.
65
66 \sa QAudioProbe, QMediaPlayer, QCamera
67*/
68
69#include "qvideoprobe.h"
70#include "qmediavideoprobecontrol.h"
71#include "qmediaservice.h"
72#include "qmediarecorder.h"
73#include "qsharedpointer.h"
74#include "qpointer.h"
75
76QT_BEGIN_NAMESPACE
77
78class QVideoProbePrivate {
79public:
80 QPointer<QMediaObject> source;
81 QPointer<QMediaVideoProbeControl> probee;
82};
83
84/*!
85 Creates a new QVideoProbe class with \a parent. After setting the
86 source to monitor with \l setSource(), the \l videoFrameProbed()
87 signal will be emitted when video frames are flowing in the
88 source media object.
89 */
90QVideoProbe::QVideoProbe(QObject *parent)
91 : QObject(parent)
92 , d(new QVideoProbePrivate)
93{
94
95}
96
97/*!
98 Destroys this probe and disconnects from any
99 media object.
100 */
101QVideoProbe::~QVideoProbe()
102{
103 if (d->source) {
104 // Disconnect
105 if (d->probee) {
106 disconnect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
107 disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
108 }
109 d->source.data()->service()->releaseControl(d->probee.data());
110 }
111}
112
113/*!
114 Sets the media object to monitor to \a source.
115
116 If \a source is zero, this probe will be deactivated
117 and this function wil return true.
118
119 If the media object does not support monitoring
120 video, this function will return false.
121
122 Any previously monitored objects will no longer be monitored.
123 Passing in the same object will be ignored, but
124 monitoring will continue.
125 */
126bool QVideoProbe::setSource(QMediaObject *source)
127{
128 // Need to:
129 // 1) disconnect from current source if necessary
130 // 2) see if new one has the probe control
131 // 3) connect if so
132
133 // in case source was destroyed but probe control is still valid
134 if (!d->source && d->probee) {
135 disconnect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
136 disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
137 d->probee.clear();
138 }
139
140 if (source != d->source.data()) {
141 if (d->source) {
142 Q_ASSERT(d->probee);
143 disconnect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
144 disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
145 d->source.data()->service()->releaseControl(d->probee.data());
146 d->source.clear();
147 d->probee.clear();
148 }
149
150 if (source) {
151 QMediaService *service = source->service();
152 if (service) {
153 d->probee = service->requestControl<QMediaVideoProbeControl*>();
154 }
155
156 if (d->probee) {
157 connect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
158 connect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
159 d->source = source;
160 }
161 }
162 }
163
164 return (!source || d->probee != nullptr);
165}
166
167/*!
168 Starts monitoring the given \a mediaRecorder.
169
170 If there is no mediaObject associated with \a mediaRecorder, or if it is
171 zero, this probe will be deactivated and this function wil return true.
172
173 If the media recorder instance does not support monitoring
174 video, this function will return false.
175
176 Any previously monitored objects will no longer be monitored.
177 Passing in the same object will be ignored, but
178 monitoring will continue.
179 */
180bool QVideoProbe::setSource(QMediaRecorder *mediaRecorder)
181{
182 QMediaObject *source = mediaRecorder ? mediaRecorder->mediaObject() : nullptr;
183 bool result = setSource(source);
184
185 if (!mediaRecorder)
186 return true;
187
188 if (mediaRecorder && !source)
189 return false;
190
191 return result;
192}
193
194/*!
195 Returns true if this probe is monitoring something, or false otherwise.
196
197 The source being monitored does not need to be active.
198 */
199bool QVideoProbe::isActive() const
200{
201 return d->probee != nullptr;
202}
203
204/*!
205 \fn QVideoProbe::videoFrameProbed(const QVideoFrame &frame)
206
207 This signal should be emitted when a video \a frame is processed in the
208 media service.
209*/
210
211/*!
212 \fn QVideoProbe::flush()
213
214 This signal should be emitted when it is required to release all frames.
215 Application must release all outstanding references to video frames.
216*/
217
218QT_END_NAMESPACE
219