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 | //TESTED_COMPONENT=src/multimedia |
41 | |
42 | #include "qabstractvideosurface.h" |
43 | |
44 | #include "qvideosurfaceformat.h" |
45 | |
46 | #include <QtCore/qvariant.h> |
47 | #include <QDebug> |
48 | |
49 | QT_BEGIN_NAMESPACE |
50 | |
51 | static void qRegisterAbstractVideoSurfaceMetaTypes() |
52 | { |
53 | qRegisterMetaType<QAbstractVideoSurface::Error>(); |
54 | } |
55 | |
56 | Q_CONSTRUCTOR_FUNCTION(qRegisterAbstractVideoSurfaceMetaTypes) |
57 | |
58 | |
59 | class QAbstractVideoSurfacePrivate { |
60 | public: |
61 | QAbstractVideoSurfacePrivate() |
62 | : error(QAbstractVideoSurface::NoError), |
63 | active(false) |
64 | { |
65 | } |
66 | |
67 | public: |
68 | QVideoSurfaceFormat surfaceFormat; |
69 | QAbstractVideoSurface::Error error; |
70 | QSize nativeResolution; |
71 | bool active; |
72 | }; |
73 | |
74 | /*! |
75 | \class QAbstractVideoSurface |
76 | \brief The QAbstractVideoSurface class is a base class for video presentation surfaces. |
77 | \inmodule QtMultimedia |
78 | |
79 | \ingroup multimedia |
80 | \ingroup multimedia_video |
81 | |
82 | The QAbstractVideoSurface class defines the standard interface that video producers use to |
83 | inter-operate with video presentation surfaces. You can subclass this interface to receive |
84 | video frames from sources like \l {QMediaPlayer}{decoded media} or \l {QCamera}{cameras} to |
85 | perform your own processing. |
86 | |
87 | A video surface presents a continuous stream of identically formatted QVideoFrame instances, where the format |
88 | of each frame is compatible with a stream format supplied when starting a presentation. Each frame |
89 | may have timestamp information that can be used by the surface to decide when to display that |
90 | frame. |
91 | |
92 | A list of pixel formats a surface can present is given by the supportedPixelFormats() function, |
93 | and the isFormatSupported() function will test if a video surface format is supported. If a |
94 | format is not supported the nearestFormat() function may be able to suggest a similar format. |
95 | For example, if a surface supports fixed set of resolutions it may suggest the smallest |
96 | supported resolution that contains the proposed resolution. |
97 | |
98 | The start() function takes a supported format and enables a video surface. Once started a |
99 | surface will begin displaying the frames it receives in the present() function. Surfaces may |
100 | hold a reference to the buffer of a presented video frame until a new frame is presented or |
101 | streaming is stopped. In addition, a video surface may hold a reference to a video frame |
102 | until the \l {QVideoFrame::endTime()}{end timestamp} has passed. The stop() function will |
103 | disable a surface and release any video buffers it holds references to. |
104 | |
105 | \section2 Implementing a subclass of QAbstractVideoSurface |
106 | |
107 | When implementing a subclass of this interface, there are only a handful of functions to |
108 | implement, broken down into two classes: |
109 | |
110 | \list |
111 | \li Format related |
112 | \li Presentation related |
113 | \endlist |
114 | |
115 | For format related functionality, you just have to describe the pixel formats that you |
116 | support (and the nearestFormat() function). For presentation related functionality, you |
117 | have to implement the present() function, and the start() and stop() functions. |
118 | |
119 | \note You must call the base class implementation of start() and stop() in your implementation. |
120 | */ |
121 | |
122 | /*! |
123 | \enum QAbstractVideoSurface::Error |
124 | This enum describes the errors that may be returned by the error() function. |
125 | |
126 | \value NoError No error occurred. |
127 | \value UnsupportedFormatError A video format was not supported. |
128 | \value IncorrectFormatError A video frame was not compatible with the format of the surface. |
129 | \value StoppedError The surface has not been started. |
130 | \value ResourceError The surface could not allocate some resource. |
131 | */ |
132 | |
133 | /*! |
134 | Constructs a video surface with the given \a parent. |
135 | */ |
136 | QAbstractVideoSurface::QAbstractVideoSurface(QObject *parent) |
137 | : QObject(parent), |
138 | d_ptr(new QAbstractVideoSurfacePrivate) |
139 | { |
140 | } |
141 | |
142 | /*! |
143 | Destroys a video surface. |
144 | */ |
145 | QAbstractVideoSurface::~QAbstractVideoSurface() |
146 | { |
147 | } |
148 | |
149 | /*! |
150 | \fn QAbstractVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const |
151 | |
152 | Returns a list of pixel formats a video surface can present for a given handle \a type. |
153 | |
154 | The pixel formats returned for the QAbstractVideoBuffer::NoHandle type are valid for any buffer |
155 | that can be mapped in read-only mode. |
156 | |
157 | Types that are first in the list can be assumed to be faster to render. |
158 | */ |
159 | |
160 | /*! |
161 | Tests a video surface \a format to determine if a surface can accept it. |
162 | |
163 | Returns true if the format is supported by the surface, and false otherwise. |
164 | */ |
165 | bool QAbstractVideoSurface::isFormatSupported(const QVideoSurfaceFormat &format) const |
166 | { |
167 | return supportedPixelFormats(type: format.handleType()).contains(t: format.pixelFormat()); |
168 | } |
169 | |
170 | /*! |
171 | Returns a supported video surface format that is similar to \a format. |
172 | |
173 | A similar surface format is one that has the same \l {QVideoSurfaceFormat::pixelFormat()}{pixel |
174 | format} and \l {QVideoSurfaceFormat::handleType()}{handle type} but may differ in some of the other |
175 | properties. For example, if there are restrictions on the \l {QVideoSurfaceFormat::frameSize()} |
176 | {frame sizes} a video surface can accept it may suggest a format with a larger frame size and |
177 | a \l {QVideoSurfaceFormat::viewport()}{viewport} the size of the original frame size. |
178 | |
179 | If the format is already supported it will be returned unchanged, or if there is no similar |
180 | supported format an invalid format will be returned. |
181 | */ |
182 | QVideoSurfaceFormat QAbstractVideoSurface::nearestFormat(const QVideoSurfaceFormat &format) const |
183 | { |
184 | return isFormatSupported(format) |
185 | ? format |
186 | : QVideoSurfaceFormat(); |
187 | } |
188 | |
189 | /*! |
190 | \fn QAbstractVideoSurface::supportedFormatsChanged() |
191 | |
192 | Signals that the set of formats supported by a video surface has changed. |
193 | |
194 | \sa supportedPixelFormats(), isFormatSupported() |
195 | */ |
196 | |
197 | /*! |
198 | Returns the format of a video surface. |
199 | */ |
200 | QVideoSurfaceFormat QAbstractVideoSurface::surfaceFormat() const |
201 | { |
202 | Q_D(const QAbstractVideoSurface); |
203 | return d->surfaceFormat; |
204 | } |
205 | |
206 | /*! |
207 | \fn QAbstractVideoSurface::surfaceFormatChanged(const QVideoSurfaceFormat &format) |
208 | |
209 | Signals that the configured \a format of a video surface has changed. |
210 | |
211 | \sa surfaceFormat(), start() |
212 | */ |
213 | |
214 | /*! |
215 | Starts a video surface presenting \a format frames. |
216 | |
217 | Returns true if the surface was started, and false if an error occurred. |
218 | |
219 | \note You must call the base class implementation of start() at the end of your implementation. |
220 | \sa isActive(), stop() |
221 | */ |
222 | bool QAbstractVideoSurface::start(const QVideoSurfaceFormat &format) |
223 | { |
224 | Q_D(QAbstractVideoSurface); |
225 | bool wasActive = d->active; |
226 | |
227 | d->active = true; |
228 | d->surfaceFormat = format; |
229 | d->error = NoError; |
230 | |
231 | emit surfaceFormatChanged(format); |
232 | |
233 | if (!wasActive) |
234 | emit activeChanged(active: true); |
235 | |
236 | return true; |
237 | } |
238 | |
239 | /*! |
240 | Stops a video surface presenting frames and releases any resources acquired in start(). |
241 | |
242 | \note You must call the base class implementation of stop() at the start of your implementation. |
243 | \sa isActive(), start() |
244 | */ |
245 | void QAbstractVideoSurface::stop() |
246 | { |
247 | Q_D(QAbstractVideoSurface); |
248 | if (d->active) { |
249 | d->surfaceFormat = QVideoSurfaceFormat(); |
250 | d->active = false; |
251 | |
252 | emit activeChanged(active: false); |
253 | emit surfaceFormatChanged(format: surfaceFormat()); |
254 | } |
255 | } |
256 | |
257 | /*! |
258 | Indicates whether a video surface has been started. |
259 | |
260 | Returns true if the surface has been started, and false otherwise. |
261 | */ |
262 | bool QAbstractVideoSurface::isActive() const |
263 | { |
264 | Q_D(const QAbstractVideoSurface); |
265 | return d->active; |
266 | } |
267 | |
268 | /*! |
269 | \fn QAbstractVideoSurface::activeChanged(bool active) |
270 | |
271 | Signals that the \a active state of a video surface has changed. |
272 | |
273 | \sa isActive(), start(), stop() |
274 | */ |
275 | |
276 | /*! |
277 | \fn QAbstractVideoSurface::present(const QVideoFrame &frame) |
278 | |
279 | Presents a video \a frame. |
280 | |
281 | Returns true if the frame was presented, and false if an error occurred. |
282 | |
283 | Not all surfaces will block until the presentation of a frame has completed. Calling present() |
284 | on a non-blocking surface may fail if called before the presentation of a previous frame has |
285 | completed. In such cases the surface may not return to a ready state until it has had an |
286 | opportunity to process events. |
287 | |
288 | If present() fails for any other reason the surface should immediately enter the stopped state |
289 | and an error() value will be set. |
290 | |
291 | A video surface must be in the started state for present() to succeed, and the format of the |
292 | video frame must be compatible with the current video surface format. |
293 | |
294 | \sa error() |
295 | */ |
296 | |
297 | /*! |
298 | Returns the last error that occurred. |
299 | |
300 | If a surface fails to start(), or stops unexpectedly this function can be called to discover |
301 | what error occurred. |
302 | */ |
303 | |
304 | QAbstractVideoSurface::Error QAbstractVideoSurface::error() const |
305 | { |
306 | Q_D(const QAbstractVideoSurface); |
307 | return d->error; |
308 | } |
309 | |
310 | /*! |
311 | Sets the value of error() to \a error. |
312 | |
313 | This can be called by implementors of this interface to communicate |
314 | what the most recent error was. |
315 | */ |
316 | void QAbstractVideoSurface::setError(Error error) |
317 | { |
318 | Q_D(QAbstractVideoSurface); |
319 | d->error = error; |
320 | } |
321 | |
322 | /*! |
323 | \property QAbstractVideoSurface::nativeResolution |
324 | |
325 | The native resolution of video surface. |
326 | This is the resolution of video frames the surface |
327 | can render with optimal quality and/or performance. |
328 | |
329 | The native resolution is not always known and can be changed during playback. |
330 | */ |
331 | QSize QAbstractVideoSurface::nativeResolution() const |
332 | { |
333 | Q_D(const QAbstractVideoSurface); |
334 | return d->nativeResolution; |
335 | } |
336 | |
337 | /*! |
338 | Set the video surface native \a resolution. |
339 | |
340 | This function can be called by implementors of this interface to specify |
341 | to frame producers what the native resolution of this surface is. |
342 | */ |
343 | void QAbstractVideoSurface::setNativeResolution(const QSize &resolution) |
344 | { |
345 | Q_D(QAbstractVideoSurface); |
346 | |
347 | if (d->nativeResolution != resolution) { |
348 | d->nativeResolution = resolution; |
349 | |
350 | emit nativeResolutionChanged(resolution); |
351 | } |
352 | } |
353 | /*! |
354 | \fn QAbstractVideoSurface::nativeResolutionChanged(const QSize &resolution); |
355 | |
356 | Signals the native \a resolution of video surface has changed. |
357 | */ |
358 | |
359 | #ifndef QT_NO_DEBUG_STREAM |
360 | QDebug operator<<(QDebug dbg, const QAbstractVideoSurface::Error& error) |
361 | { |
362 | QDebugStateSaver saver(dbg); |
363 | dbg.nospace(); |
364 | switch (error) { |
365 | case QAbstractVideoSurface::UnsupportedFormatError: |
366 | dbg << "UnsupportedFormatError" ; |
367 | break; |
368 | case QAbstractVideoSurface::IncorrectFormatError: |
369 | dbg << "IncorrectFormatError" ; |
370 | break; |
371 | case QAbstractVideoSurface::StoppedError: |
372 | dbg << "StoppedError" ; |
373 | break; |
374 | case QAbstractVideoSurface::ResourceError: |
375 | dbg << "ResourceError" ; |
376 | break; |
377 | default: |
378 | dbg << "NoError" ; |
379 | break; |
380 | } |
381 | return dbg; |
382 | } |
383 | #endif |
384 | |
385 | |
386 | QT_END_NAMESPACE |
387 | |
388 | #include "moc_qabstractvideosurface.cpp" |
389 | |
390 | |