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