| 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 | |