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#include "qmediaplayer.h"
41#include "qvideosurfaces_p.h"
42#include "qvideosurfaceoutput_p.h"
43
44#include "qmediaobject_p.h"
45#include <qmediaservice.h>
46#include <qmediaplayercontrol.h>
47#include <qmediaserviceprovider_p.h>
48#include <qmediaplaylist.h>
49#include <qmediaplaylistcontrol_p.h>
50#include <qmediaplaylistsourcecontrol_p.h>
51#include <qmedianetworkaccesscontrol.h>
52#include <qaudiorolecontrol.h>
53#include <qcustomaudiorolecontrol.h>
54
55#include <QtCore/qcoreevent.h>
56#include <QtCore/qmetaobject.h>
57#include <QtCore/qtimer.h>
58#include <QtCore/qdebug.h>
59#include <QtCore/qpointer.h>
60#include <QtCore/qfileinfo.h>
61#include <QtCore/qtemporaryfile.h>
62#include <QDir>
63
64QT_BEGIN_NAMESPACE
65
66/*!
67 \class QMediaPlayer
68 \brief The QMediaPlayer class allows the playing of a media source.
69 \inmodule QtMultimedia
70 \ingroup multimedia
71 \ingroup multimedia_playback
72
73 The QMediaPlayer class is a high level media playback class. It can be used
74 to playback such content as songs, movies and internet radio. The content
75 to playback is specified as a QMediaContent object, which can be thought of as a
76 main or canonical URL with additional information attached. When provided
77 with a QMediaContent playback may be able to commence.
78
79 \snippet multimedia-snippets/media.cpp Player
80
81 QVideoWidget can be used with QMediaPlayer for video rendering and QMediaPlaylist
82 for accessing playlist functionality.
83
84 \snippet multimedia-snippets/media.cpp Movie playlist
85
86 Since QMediaPlayer is a QMediaObject, you can use several of the QMediaObject
87 functions for things like:
88
89 \list
90 \li Accessing the currently playing media's metadata (\l {QMediaObject::metaData()} and \l {QMediaMetaData}{predefined meta-data keys})
91 \li Checking to see if the media playback service is currently available (\l {QMediaObject::availability()})
92 \endlist
93
94 \sa QMediaObject, QMediaService, QVideoWidget, QMediaPlaylist
95*/
96
97static void qRegisterMediaPlayerMetaTypes()
98{
99 qRegisterMetaType<QMediaPlayer::State>(typeName: "QMediaPlayer::State");
100 qRegisterMetaType<QMediaPlayer::MediaStatus>(typeName: "QMediaPlayer::MediaStatus");
101 qRegisterMetaType<QMediaPlayer::Error>(typeName: "QMediaPlayer::Error");
102}
103
104Q_CONSTRUCTOR_FUNCTION(qRegisterMediaPlayerMetaTypes)
105
106#define MAX_NESTED_PLAYLISTS 16
107
108class QMediaPlayerPrivate : public QMediaObjectPrivate
109{
110 Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer)
111
112public:
113 QMediaPlayerPrivate()
114 : provider(nullptr)
115 , control(nullptr)
116 , audioRoleControl(nullptr)
117 , customAudioRoleControl(nullptr)
118 , playlist(nullptr)
119#ifndef QT_NO_BEARERMANAGEMENT
120 , networkAccessControl(nullptr)
121#endif
122 , state(QMediaPlayer::StoppedState)
123 , status(QMediaPlayer::UnknownMediaStatus)
124 , error(QMediaPlayer::NoError)
125 , ignoreNextStatusChange(-1)
126 , nestedPlaylists(0)
127 , hasStreamPlaybackFeature(false)
128 {}
129
130 QMediaServiceProvider *provider;
131 QMediaPlayerControl* control;
132 QAudioRoleControl *audioRoleControl;
133 QCustomAudioRoleControl *customAudioRoleControl;
134 QString errorString;
135
136 QPointer<QObject> videoOutput;
137 QMediaPlaylist *playlist;
138#ifndef QT_NO_BEARERMANAGEMENT
139QT_WARNING_PUSH
140QT_WARNING_DISABLE_DEPRECATED
141 QMediaNetworkAccessControl *networkAccessControl;
142QT_WARNING_POP
143#endif
144 QVideoSurfaceOutput surfaceOutput;
145 QMediaContent qrcMedia;
146 QScopedPointer<QFile> qrcFile;
147
148 QMediaContent rootMedia;
149 QMediaContent pendingPlaylist;
150 QMediaPlayer::State state;
151 QMediaPlayer::MediaStatus status;
152 QMediaPlayer::Error error;
153 int ignoreNextStatusChange;
154 int nestedPlaylists;
155 bool hasStreamPlaybackFeature;
156
157 QMediaPlaylist *parentPlaylist(QMediaPlaylist *pls);
158 bool isInChain(const QUrl &url);
159
160 void setMedia(const QMediaContent &media, QIODevice *stream = nullptr);
161
162 void setPlaylist(QMediaPlaylist *playlist);
163 void setPlaylistMedia();
164 void loadPlaylist();
165 void disconnectPlaylist();
166 void connectPlaylist();
167
168 void _q_stateChanged(QMediaPlayer::State state);
169 void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status);
170 void _q_error(int error, const QString &errorString);
171 void _q_updateMedia(const QMediaContent&);
172 void _q_playlistDestroyed();
173 void _q_handleMediaChanged(const QMediaContent&);
174 void _q_handlePlaylistLoaded();
175 void _q_handlePlaylistLoadFailed();
176};
177
178QMediaPlaylist *QMediaPlayerPrivate::parentPlaylist(QMediaPlaylist *pls)
179{
180 // This function finds a parent playlist for an item in the active chain of playlists.
181 // Every item in the chain comes from currentMedia() of its parent.
182 // We don't need to travers the whole tree of playlists,
183 // but only the subtree of active ones.
184 for (QMediaPlaylist *current = rootMedia.playlist(); current && current != pls; current = current->currentMedia().playlist())
185 if (current->currentMedia().playlist() == pls)
186 return current;
187 return nullptr;
188}
189
190bool QMediaPlayerPrivate::isInChain(const QUrl &url)
191{
192 // Check whether a URL is already in the chain of playlists.
193 // Also see a comment in parentPlaylist().
194 for (QMediaPlaylist *current = rootMedia.playlist(); current && current != playlist; current = current->currentMedia().playlist())
195 if (current->currentMedia().request().url() == url) {
196 return true;
197 }
198 return false;
199}
200
201void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps)
202{
203 Q_Q(QMediaPlayer);
204
205 // Backend switches into stopped state every time new media is about to be loaded.
206 // If media player has a playlist loaded make sure player doesn' stop.
207 if (playlist && playlist->currentIndex() != -1 && ps != state && ps == QMediaPlayer::StoppedState) {
208 if (control->mediaStatus() == QMediaPlayer::EndOfMedia ||
209 control->mediaStatus() == QMediaPlayer::InvalidMedia) {
210 // if media player is not stopped, and
211 // we have finished playback for the current media,
212 // advance to the next item in the playlist
213 Q_ASSERT(state != QMediaPlayer::StoppedState);
214 playlist->next();
215 return;
216 } else if (control->mediaStatus() == QMediaPlayer::LoadingMedia) {
217 return;
218 }
219 }
220
221 if (ps != state) {
222 state = ps;
223
224 if (ps == QMediaPlayer::PlayingState)
225 q->addPropertyWatch(name: "position");
226 else
227 q->removePropertyWatch(name: "position");
228
229 emit q->stateChanged(newState: ps);
230 }
231}
232
233void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus s)
234{
235 Q_Q(QMediaPlayer);
236
237 if (int(s) == ignoreNextStatusChange) {
238 ignoreNextStatusChange = -1;
239 return;
240 }
241
242 if (s != status) {
243 status = s;
244
245 switch (s) {
246 case QMediaPlayer::StalledMedia:
247 case QMediaPlayer::BufferingMedia:
248 q->addPropertyWatch(name: "bufferStatus");
249 break;
250 default:
251 q->removePropertyWatch(name: "bufferStatus");
252 break;
253 }
254
255 emit q->mediaStatusChanged(status: s);
256 }
257}
258
259void QMediaPlayerPrivate::_q_error(int error, const QString &errorString)
260{
261 Q_Q(QMediaPlayer);
262
263 if (error == int(QMediaPlayer::MediaIsPlaylist)) {
264 loadPlaylist();
265 } else {
266 this->error = QMediaPlayer::Error(error);
267 this->errorString = errorString;
268 emit q->error(error: this->error);
269
270 if (playlist)
271 playlist->next();
272 }
273}
274
275void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
276{
277 Q_Q(QMediaPlayer);
278
279 if (!control)
280 return;
281
282 // check if the current playlist is a top-level playlist
283 Q_ASSERT(playlist);
284 if (media.isNull() && playlist != rootMedia.playlist()) {
285 // switch back to parent playlist
286 QMediaPlaylist *pls = parentPlaylist(pls: playlist);
287 Q_ASSERT(pls);
288 disconnectPlaylist();
289 playlist = pls;
290 connectPlaylist();
291
292 Q_ASSERT(!pendingPlaylist.playlist());
293 nestedPlaylists--;
294 Q_ASSERT(nestedPlaylists >= 0);
295
296 playlist->next();
297 return;
298 }
299
300 if (media.playlist()) {
301 if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
302 nestedPlaylists++;
303 Q_ASSERT(!pendingPlaylist.playlist());
304
305 // disconnect current playlist
306 disconnectPlaylist();
307 // new playlist signals are connected
308 // in the call to setPlaylist() in _q_handlePlaylistLoaded()
309 playlist = media.playlist();
310 emit q->currentMediaChanged(media);
311 _q_handlePlaylistLoaded();
312 return;
313 } else if (playlist) {
314 playlist->next();
315 }
316 return;
317 }
318
319 const QMediaPlayer::State currentState = state;
320
321 setMedia(media, stream: nullptr);
322
323 if (!media.isNull()) {
324 switch (currentState) {
325 case QMediaPlayer::PlayingState:
326 control->play();
327 break;
328 case QMediaPlayer::PausedState:
329 control->pause();
330 break;
331 default:
332 break;
333 }
334 }
335
336 _q_stateChanged(ps: control->state());
337}
338
339void QMediaPlayerPrivate::_q_playlistDestroyed()
340{
341 playlist = nullptr;
342 setMedia(media: QMediaContent(), stream: nullptr);
343}
344
345void QMediaPlayerPrivate::setMedia(const QMediaContent &media, QIODevice *stream)
346{
347 Q_Q(QMediaPlayer);
348
349 if (!control)
350 return;
351
352 QScopedPointer<QFile> file;
353
354 // Backends can't play qrc files directly.
355 // If the backend supports StreamPlayback, we pass a QFile for that resource.
356 // If it doesn't, we copy the data to a temporary file and pass its path.
357 if (!media.isNull() && !stream && media.request().url().scheme() == QLatin1String("qrc")) {
358 qrcMedia = media;
359
360 file.reset(other: new QFile(QLatin1Char(':') + media.request().url().path()));
361 if (!file->open(flags: QFile::ReadOnly)) {
362 QMetaObject::invokeMethod(obj: q, member: "_q_error", type: Qt::QueuedConnection,
363 Q_ARG(int, QMediaPlayer::ResourceError),
364 Q_ARG(QString, QMediaPlayer::tr("Attempting to play invalid Qt resource")));
365 QMetaObject::invokeMethod(obj: q, member: "_q_mediaStatusChanged", type: Qt::QueuedConnection,
366 Q_ARG(QMediaPlayer::MediaStatus, QMediaPlayer::InvalidMedia));
367 file.reset();
368 // Ignore the next NoMedia status change, we just want to clear the current media
369 // on the backend side since we can't load the new one and we want to be in the
370 // InvalidMedia status.
371 ignoreNextStatusChange = QMediaPlayer::NoMedia;
372 control->setMedia(media: QMediaContent(), stream: nullptr);
373
374 } else if (hasStreamPlaybackFeature) {
375 control->setMedia(media, stream: file.data());
376 } else {
377#if QT_CONFIG(temporaryfile)
378#if defined(Q_OS_ANDROID)
379 QString tempFileName = QDir::tempPath() + media.request().url().path();
380 QDir().mkpath(QFileInfo(tempFileName).path());
381 QTemporaryFile *tempFile = QTemporaryFile::createNativeFile(*file);
382 if (!tempFile->rename(tempFileName))
383 qWarning() << "Could not rename temporary file to:" << tempFileName;
384#else
385 QTemporaryFile *tempFile = new QTemporaryFile;
386
387 // Preserve original file extension, some backends might not load the file if it doesn't
388 // have an extension.
389 const QString suffix = QFileInfo(*file).suffix();
390 if (!suffix.isEmpty())
391 tempFile->setFileTemplate(tempFile->fileTemplate() + QLatin1Char('.') + suffix);
392
393 // Copy the qrc data into the temporary file
394 tempFile->open();
395 char buffer[4096];
396 while (true) {
397 qint64 len = file->read(data: buffer, maxlen: sizeof(buffer));
398 if (len < 1)
399 break;
400 tempFile->write(data: buffer, len);
401 }
402 tempFile->close();
403#endif
404 file.reset(other: tempFile);
405 control->setMedia(media: QMediaContent(QUrl::fromLocalFile(localfile: file->fileName())), stream: nullptr);
406#else
407 qWarning("Qt was built with -no-feature-temporaryfile: playback from resource file is not supported!");
408#endif
409 }
410 } else {
411 qrcMedia = QMediaContent();
412 control->setMedia(media, stream);
413 }
414
415 qrcFile.swap(other&: file); // Cleans up any previous file
416}
417
418void QMediaPlayerPrivate::_q_handleMediaChanged(const QMediaContent &media)
419{
420 Q_Q(QMediaPlayer);
421
422 emit q->currentMediaChanged(media: qrcMedia.isNull() ? media : qrcMedia);
423}
424
425void QMediaPlayerPrivate::setPlaylist(QMediaPlaylist *pls)
426{
427 disconnectPlaylist();
428 playlist = pls;
429
430 setPlaylistMedia();
431}
432
433void QMediaPlayerPrivate::setPlaylistMedia()
434{
435 // This function loads current playlist media into backend.
436 // If current media is a playlist, the function recursively
437 // loads media from the playlist.
438 // It also makes sure the correct playlist signals are connected.
439 Q_Q(QMediaPlayer);
440
441 if (playlist) {
442 connectPlaylist();
443 if (playlist->currentMedia().playlist()) {
444 if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
445 emit q->currentMediaChanged(media: playlist->currentMedia());
446 // rewind nested playlist to start
447 playlist->currentMedia().playlist()->setCurrentIndex(0);
448 nestedPlaylists++;
449 setPlaylist(playlist->currentMedia().playlist());
450 } else {
451 playlist->next();
452 }
453 return;
454 } else {
455 // If we've just switched to a new playlist,
456 // then last emitted currentMediaChanged was a playlist.
457 // Make sure we emit currentMediaChanged if new playlist has
458 // the same media as the previous one:
459 // sample.m3u
460 // test.wav -- processed by backend
461 // nested.m3u -- processed by frontend
462 // test.wav -- processed by backend,
463 // media is not changed,
464 // frontend needs to emit currentMediaChanged
465 bool isSameMedia = (q->currentMedia() == playlist->currentMedia());
466 setMedia(media: playlist->currentMedia(), stream: nullptr);
467 if (isSameMedia) {
468 emit q->currentMediaChanged(media: q->currentMedia());
469 }
470 }
471 } else {
472 setMedia(media: QMediaContent(), stream: nullptr);
473 }
474}
475
476void QMediaPlayerPrivate::loadPlaylist()
477{
478 Q_Q(QMediaPlayer);
479 Q_ASSERT(pendingPlaylist.isNull());
480
481 // Do not load a playlist if there are more than MAX_NESTED_PLAYLISTS in the chain already,
482 // or if the playlist URL is already in the chain, i.e. do not allow recursive playlists and loops.
483 if (nestedPlaylists < MAX_NESTED_PLAYLISTS
484 && !q->currentMedia().request().url().isEmpty()
485 && !isInChain(url: q->currentMedia().request().url()))
486 {
487 pendingPlaylist = QMediaContent(new QMediaPlaylist, q->currentMedia().request().url(), true);
488 QObject::connect(sender: pendingPlaylist.playlist(), SIGNAL(loaded()), receiver: q, SLOT(_q_handlePlaylistLoaded()));
489 QObject::connect(sender: pendingPlaylist.playlist(), SIGNAL(loadFailed()), receiver: q, SLOT(_q_handlePlaylistLoadFailed()));
490 pendingPlaylist.playlist()->load(request: pendingPlaylist.request());
491 } else if (playlist) {
492 playlist->next();
493 }
494}
495
496void QMediaPlayerPrivate::disconnectPlaylist()
497{
498 Q_Q(QMediaPlayer);
499 if (playlist) {
500 QObject::disconnect(sender: playlist, SIGNAL(currentMediaChanged(QMediaContent)),
501 receiver: q, SLOT(_q_updateMedia(QMediaContent)));
502 QObject::disconnect(sender: playlist, SIGNAL(destroyed()), receiver: q, SLOT(_q_playlistDestroyed()));
503 q->unbind(playlist);
504 }
505}
506
507void QMediaPlayerPrivate::connectPlaylist()
508{
509 Q_Q(QMediaPlayer);
510 if (playlist) {
511 q->bind(playlist);
512 QObject::connect(sender: playlist, SIGNAL(currentMediaChanged(QMediaContent)),
513 receiver: q, SLOT(_q_updateMedia(QMediaContent)));
514 QObject::connect(sender: playlist, SIGNAL(destroyed()), receiver: q, SLOT(_q_playlistDestroyed()));
515 }
516}
517
518void QMediaPlayerPrivate::_q_handlePlaylistLoaded()
519{
520 Q_Q(QMediaPlayer);
521
522 if (pendingPlaylist.playlist()) {
523 Q_ASSERT(!q->currentMedia().playlist());
524 // if there is an active playlist
525 if (playlist) {
526 Q_ASSERT(playlist->currentIndex() >= 0);
527 disconnectPlaylist();
528 playlist->insertMedia(index: playlist->currentIndex() + 1, content: pendingPlaylist);
529 playlist->removeMedia(pos: playlist->currentIndex());
530 nestedPlaylists++;
531 } else {
532 Q_ASSERT(!rootMedia.playlist());
533 rootMedia = pendingPlaylist;
534 emit q->mediaChanged(media: rootMedia);
535 }
536
537 playlist = pendingPlaylist.playlist();
538 emit q->currentMediaChanged(media: pendingPlaylist);
539 }
540 pendingPlaylist = QMediaContent();
541
542 playlist->next();
543 setPlaylistMedia();
544
545 switch (state) {
546 case QMediaPlayer::PausedState:
547 control->pause();
548 break;
549 case QMediaPlayer::PlayingState:
550 control->play();
551 break;
552 case QMediaPlayer::StoppedState:
553 break;
554 }
555}
556
557void QMediaPlayerPrivate::_q_handlePlaylistLoadFailed()
558{
559 pendingPlaylist = QMediaContent();
560
561 if (!control)
562 return;
563
564 if (playlist)
565 playlist->next();
566 else
567 setMedia(media: QMediaContent(), stream: nullptr);
568}
569
570static QMediaService *playerService(QMediaPlayer::Flags flags)
571{
572 QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();
573 if (flags) {
574 QMediaServiceProviderHint::Features features;
575 if (flags & QMediaPlayer::LowLatency)
576 features |= QMediaServiceProviderHint::LowLatencyPlayback;
577
578 if (flags & QMediaPlayer::StreamPlayback)
579 features |= QMediaServiceProviderHint::StreamPlayback;
580
581 if (flags & QMediaPlayer::VideoSurface)
582 features |= QMediaServiceProviderHint::VideoSurface;
583
584 return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER,
585 hint: QMediaServiceProviderHint(features));
586 }
587
588 return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER);
589}
590
591
592/*!
593 Construct a QMediaPlayer instance
594 parented to \a parent and with \a flags.
595*/
596
597QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
598 QMediaObject(*new QMediaPlayerPrivate,
599 parent,
600 playerService(flags))
601{
602 Q_D(QMediaPlayer);
603
604 d->provider = QMediaServiceProvider::defaultServiceProvider();
605 if (d->service == nullptr) {
606 d->error = ServiceMissingError;
607 } else {
608 d->control = qobject_cast<QMediaPlayerControl*>(object: d->service->requestControl(QMediaPlayerControl_iid));
609#ifndef QT_NO_BEARERMANAGEMENT
610QT_WARNING_PUSH
611QT_WARNING_DISABLE_DEPRECATED
612 d->networkAccessControl = qobject_cast<QMediaNetworkAccessControl*>(object: d->service->requestControl(QMediaNetworkAccessControl_iid));
613QT_WARNING_POP
614#endif
615 if (d->control != nullptr) {
616 connect(asender: d->control, SIGNAL(mediaChanged(QMediaContent)), SLOT(_q_handleMediaChanged(QMediaContent)));
617 connect(asender: d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State)));
618 connect(asender: d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
619 SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus)));
620 connect(asender: d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString)));
621
622 connect(sender: d->control, signal: &QMediaPlayerControl::durationChanged, receiver: this, slot: &QMediaPlayer::durationChanged);
623 connect(sender: d->control, signal: &QMediaPlayerControl::positionChanged, receiver: this, slot: &QMediaPlayer::positionChanged);
624 connect(sender: d->control, signal: &QMediaPlayerControl::audioAvailableChanged, receiver: this, slot: &QMediaPlayer::audioAvailableChanged);
625 connect(sender: d->control, signal: &QMediaPlayerControl::videoAvailableChanged, receiver: this, slot: &QMediaPlayer::videoAvailableChanged);
626 connect(sender: d->control, signal: &QMediaPlayerControl::volumeChanged, receiver: this, slot: &QMediaPlayer::volumeChanged);
627 connect(sender: d->control, signal: &QMediaPlayerControl::mutedChanged, receiver: this, slot: &QMediaPlayer::mutedChanged);
628 connect(sender: d->control, signal: &QMediaPlayerControl::seekableChanged, receiver: this, slot: &QMediaPlayer::seekableChanged);
629 connect(sender: d->control, signal: &QMediaPlayerControl::playbackRateChanged, receiver: this, slot: &QMediaPlayer::playbackRateChanged);
630 connect(sender: d->control, signal: &QMediaPlayerControl::bufferStatusChanged, receiver: this, slot: &QMediaPlayer::bufferStatusChanged);
631
632 d->state = d->control->state();
633 d->status = d->control->mediaStatus();
634
635 if (d->state == PlayingState)
636 addPropertyWatch(name: "position");
637
638 if (d->status == StalledMedia || d->status == BufferingMedia)
639 addPropertyWatch(name: "bufferStatus");
640
641 d->hasStreamPlaybackFeature = d->provider->supportedFeatures(service: d->service).testFlag(flag: QMediaServiceProviderHint::StreamPlayback);
642
643 d->audioRoleControl = qobject_cast<QAudioRoleControl*>(object: d->service->requestControl(QAudioRoleControl_iid));
644 if (d->audioRoleControl) {
645 connect(sender: d->audioRoleControl, signal: &QAudioRoleControl::audioRoleChanged,
646 receiver: this, slot: &QMediaPlayer::audioRoleChanged);
647
648 d->customAudioRoleControl = qobject_cast<QCustomAudioRoleControl *>(
649 object: d->service->requestControl(QCustomAudioRoleControl_iid));
650 if (d->customAudioRoleControl) {
651 connect(sender: d->customAudioRoleControl,
652 signal: &QCustomAudioRoleControl::customAudioRoleChanged,
653 receiver: this,
654 slot: &QMediaPlayer::customAudioRoleChanged);
655 }
656 }
657 }
658#ifndef QT_NO_BEARERMANAGEMENT
659 if (d->networkAccessControl != nullptr) {
660QT_WARNING_PUSH
661QT_WARNING_DISABLE_DEPRECATED
662 connect(sender: d->networkAccessControl, signal: &QMediaNetworkAccessControl::configurationChanged,
663 receiver: this, slot: &QMediaPlayer::networkConfigurationChanged);
664QT_WARNING_POP
665 }
666#endif
667 }
668}
669
670
671/*!
672 Destroys the player object.
673*/
674
675QMediaPlayer::~QMediaPlayer()
676{
677 Q_D(QMediaPlayer);
678
679 d->disconnectPlaylist();
680 // Disconnect everything to prevent notifying
681 // when a receiver is already destroyed.
682 disconnect();
683
684 if (d->service) {
685 if (d->control)
686 d->service->releaseControl(control: d->control);
687 if (d->audioRoleControl)
688 d->service->releaseControl(control: d->audioRoleControl);
689 if (d->customAudioRoleControl)
690 d->service->releaseControl(control: d->customAudioRoleControl);
691
692 d->provider->releaseService(service: d->service);
693 }
694}
695
696QMediaContent QMediaPlayer::media() const
697{
698 Q_D(const QMediaPlayer);
699
700 return d->rootMedia;
701}
702
703/*!
704 Returns the stream source of media data.
705
706 This is only valid if a stream was passed to setMedia().
707
708 \sa setMedia()
709*/
710
711const QIODevice *QMediaPlayer::mediaStream() const
712{
713 Q_D(const QMediaPlayer);
714
715 // When playing a resource file, we might have passed a QFile to the backend. Hide it from
716 // the user.
717 if (d->control && d->qrcMedia.isNull())
718 return d->control->mediaStream();
719
720 return nullptr;
721}
722
723QMediaPlaylist *QMediaPlayer::playlist() const
724{
725 Q_D(const QMediaPlayer);
726
727 return d->rootMedia.playlist();
728}
729
730QMediaContent QMediaPlayer::currentMedia() const
731{
732 Q_D(const QMediaPlayer);
733
734 // When playing a resource file, don't return the backend's current media, which
735 // can be a temporary file.
736 if (!d->qrcMedia.isNull())
737 return d->qrcMedia;
738
739 if (d->control)
740 return d->control->media();
741
742 return QMediaContent();
743}
744
745void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
746{
747 QMediaContent m(playlist, QUrl(), false);
748 setMedia(media: m);
749}
750
751#ifndef QT_NO_BEARERMANAGEMENT
752QT_WARNING_PUSH
753QT_WARNING_DISABLE_DEPRECATED
754/*!
755 \obsolete
756
757 Sets the network access points for remote media playback.
758 \a configurations contains, in ascending preferential order, a list of
759 configuration that can be used for network access.
760
761 This will invalidate the choice of previous configurations.
762*/
763void QMediaPlayer::setNetworkConfigurations(const QList<QNetworkConfiguration> &configurations)
764{
765 Q_D(QMediaPlayer);
766
767 if (d->networkAccessControl)
768 d->networkAccessControl->setConfigurations(configurations);
769}
770QT_WARNING_POP
771#endif
772
773QMediaPlayer::State QMediaPlayer::state() const
774{
775 Q_D(const QMediaPlayer);
776
777 // In case if EndOfMedia status is already received
778 // but state is not.
779 if (d->control != nullptr
780 && d->status == QMediaPlayer::EndOfMedia
781 && d->state != d->control->state()) {
782 return d->control->state();
783 }
784
785 return d->state;
786}
787
788QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const
789{
790 return d_func()->status;
791}
792
793qint64 QMediaPlayer::duration() const
794{
795 Q_D(const QMediaPlayer);
796
797 if (d->control != nullptr)
798 return d->control->duration();
799
800 return -1;
801}
802
803qint64 QMediaPlayer::position() const
804{
805 Q_D(const QMediaPlayer);
806
807 if (d->control != nullptr)
808 return d->control->position();
809
810 return 0;
811}
812
813int QMediaPlayer::volume() const
814{
815 Q_D(const QMediaPlayer);
816
817 if (d->control != nullptr)
818 return d->control->volume();
819
820 return 0;
821}
822
823bool QMediaPlayer::isMuted() const
824{
825 Q_D(const QMediaPlayer);
826
827 if (d->control != nullptr)
828 return d->control->isMuted();
829
830 return false;
831}
832
833int QMediaPlayer::bufferStatus() const
834{
835 Q_D(const QMediaPlayer);
836
837 if (d->control != nullptr)
838 return d->control->bufferStatus();
839
840 return 0;
841}
842
843bool QMediaPlayer::isAudioAvailable() const
844{
845 Q_D(const QMediaPlayer);
846
847 if (d->control != nullptr)
848 return d->control->isAudioAvailable();
849
850 return false;
851}
852
853bool QMediaPlayer::isVideoAvailable() const
854{
855 Q_D(const QMediaPlayer);
856
857 if (d->control != nullptr)
858 return d->control->isVideoAvailable();
859
860 return false;
861}
862
863bool QMediaPlayer::isSeekable() const
864{
865 Q_D(const QMediaPlayer);
866
867 if (d->control != nullptr)
868 return d->control->isSeekable();
869
870 return false;
871}
872
873qreal QMediaPlayer::playbackRate() const
874{
875 Q_D(const QMediaPlayer);
876
877 if (d->control != nullptr)
878 return d->control->playbackRate();
879
880 return 0.0;
881}
882
883/*!
884 Returns the current error state.
885*/
886
887QMediaPlayer::Error QMediaPlayer::error() const
888{
889 return d_func()->error;
890}
891
892QString QMediaPlayer::errorString() const
893{
894 return d_func()->errorString;
895}
896
897#ifndef QT_NO_BEARERMANAGEMENT
898QT_WARNING_PUSH
899QT_WARNING_DISABLE_DEPRECATED
900/*!
901 \obsolete
902
903 Returns the current network access point in use.
904 If a default contructed QNetworkConfiguration is returned
905 this feature is not available or that none of the
906 current supplied configurations are in use.
907*/
908QNetworkConfiguration QMediaPlayer::currentNetworkConfiguration() const
909{
910 Q_D(const QMediaPlayer);
911
912 if (d->networkAccessControl)
913 return d_func()->networkAccessControl->currentConfiguration();
914
915 return QNetworkConfiguration();
916}
917QT_WARNING_POP
918#endif
919
920//public Q_SLOTS:
921/*!
922 Start or resume playing the current source.
923*/
924
925void QMediaPlayer::play()
926{
927 Q_D(QMediaPlayer);
928
929 if (d->control == nullptr) {
930 QMetaObject::invokeMethod(obj: this, member: "_q_error", type: Qt::QueuedConnection,
931 Q_ARG(int, QMediaPlayer::ServiceMissingError),
932 Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service")));
933 return;
934 }
935
936 //if playlist control is available, the service should advance itself
937 if (d->rootMedia.playlist() && !d->rootMedia.playlist()->isEmpty()) {
938 // switch to playing state
939 if (d->state != QMediaPlayer::PlayingState)
940 d->_q_stateChanged(ps: QMediaPlayer::PlayingState);
941
942 if (d->rootMedia.playlist()->currentIndex() == -1) {
943 if (d->playlist != d->rootMedia.playlist())
944 d->setPlaylist(d->rootMedia.playlist());
945 Q_ASSERT(d->playlist == d->rootMedia.playlist());
946
947 emit currentMediaChanged(media: d->rootMedia);
948 d->playlist->setCurrentIndex(0);
949 }
950 }
951
952 // Reset error conditions
953 d->error = NoError;
954 d->errorString = QString();
955
956 d->control->play();
957}
958
959/*!
960 Pause playing the current source.
961*/
962
963void QMediaPlayer::pause()
964{
965 Q_D(QMediaPlayer);
966
967 if (d->control != nullptr)
968 d->control->pause();
969}
970
971/*!
972 Stop playing, and reset the play position to the beginning.
973*/
974
975void QMediaPlayer::stop()
976{
977 Q_D(QMediaPlayer);
978
979 if (d->control != nullptr)
980 d->control->stop();
981
982 // If media player didn't stop in response to control.
983 // This happens if we have an active playlist and control
984 // media status is
985 // QMediaPlayer::LoadingMedia, QMediaPlayer::InvalidMedia, or QMediaPlayer::EndOfMedia
986 // see QMediaPlayerPrivate::_q_stateChanged()
987 if (d->playlist && d->state != QMediaPlayer::StoppedState) {
988 d->state = QMediaPlayer::StoppedState;
989 removePropertyWatch(name: "position");
990 emit stateChanged(newState: QMediaPlayer::StoppedState);
991 }
992}
993
994void QMediaPlayer::setPosition(qint64 position)
995{
996 Q_D(QMediaPlayer);
997
998 if (d->control == nullptr)
999 return;
1000
1001 d->control->setPosition(qMax(a: position, b: 0ll));
1002}
1003
1004void QMediaPlayer::setVolume(int v)
1005{
1006 Q_D(QMediaPlayer);
1007
1008 if (d->control == nullptr)
1009 return;
1010
1011 int clamped = qBound(min: 0, val: v, max: 100);
1012 if (clamped == volume())
1013 return;
1014
1015 d->control->setVolume(clamped);
1016}
1017
1018void QMediaPlayer::setMuted(bool muted)
1019{
1020 Q_D(QMediaPlayer);
1021
1022 if (d->control == nullptr || muted == isMuted())
1023 return;
1024
1025 d->control->setMuted(muted);
1026}
1027
1028void QMediaPlayer::setPlaybackRate(qreal rate)
1029{
1030 Q_D(QMediaPlayer);
1031
1032 if (d->control != nullptr)
1033 d->control->setPlaybackRate(rate);
1034}
1035
1036/*!
1037 Sets the current \a media source.
1038
1039 If a \a stream is supplied; media data will be read from it instead of resolving the media
1040 source. In this case the url should be provided to resolve additional information
1041 about the media such as mime type. The \a stream must be open and readable.
1042 For macOS the \a stream should be also seekable.
1043
1044 Setting the media to a null QMediaContent will cause the player to discard all
1045 information relating to the current media source and to cease all I/O operations related
1046 to that media.
1047
1048 \note This function returns immediately after recording the specified source of the media.
1049 It does not wait for the media to finish loading and does not check for errors. Listen for
1050 the mediaStatusChanged() and error() signals to be notified when the media is loaded and
1051 when an error occurs during loading.
1052
1053 Since Qt 5.12.2, the url scheme \c gst-pipeline provides custom pipelines
1054 for the GStreamer backend.
1055
1056 \snippet multimedia-snippets/media.cpp Pipeline
1057
1058 If QAbstractVideoSurface is used as the video output,
1059 \c qtvideosink can be used as a video sink element directly in the pipeline.
1060 After that the surface will receive the video frames in QAbstractVideoSurface::present().
1061
1062 \snippet multimedia-snippets/media.cpp Pipeline Surface
1063
1064 If QVideoWidget is used as the video output
1065 and the pipeline contains a video sink element named \c qtvideosink,
1066 current QVideoWidget will be used to render the video.
1067
1068 \snippet multimedia-snippets/media.cpp Pipeline Widget
1069
1070 If the pipeline contains appsrc element, it will be used to push data from \a stream.
1071
1072 \snippet multimedia-snippets/media.cpp Pipeline appsrc
1073*/
1074
1075void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream)
1076{
1077 Q_D(QMediaPlayer);
1078 stop();
1079
1080 QMediaContent oldMedia = d->rootMedia;
1081 d->disconnectPlaylist();
1082 d->playlist = nullptr;
1083 d->rootMedia = media;
1084 d->nestedPlaylists = 0;
1085
1086 if (oldMedia != media)
1087 emit mediaChanged(media: d->rootMedia);
1088
1089 if (media.playlist()) {
1090 // reset playlist to the 1st item
1091 media.playlist()->setCurrentIndex(0);
1092 d->setPlaylist(media.playlist());
1093 } else {
1094 d->setMedia(media, stream);
1095 }
1096}
1097
1098/*!
1099 \internal
1100*/
1101
1102bool QMediaPlayer::bind(QObject *obj)
1103{
1104 return QMediaObject::bind(obj);
1105}
1106
1107/*!
1108 \internal
1109*/
1110
1111void QMediaPlayer::unbind(QObject *obj)
1112{
1113 QMediaObject::unbind(obj);
1114}
1115
1116/*!
1117 Returns the level of support a media player has for a \a mimeType and a set of \a codecs.
1118
1119 The \a flags argument allows additional requirements such as performance indicators to be
1120 specified.
1121*/
1122QMultimedia::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType,
1123 const QStringList& codecs,
1124 Flags flags)
1125{
1126 return QMediaServiceProvider::defaultServiceProvider()->hasSupport(serviceType: QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
1127 mimeType,
1128 codecs,
1129 flags);
1130}
1131
1132/*!
1133 \deprecated
1134 Returns a list of MIME types supported by the media player.
1135
1136 The \a flags argument causes the resultant list to be restricted to MIME types which can be supported
1137 given additional requirements, such as performance indicators.
1138
1139 This function may not return useful results on some platforms, and support for a specific file of a
1140 given mime type is not guaranteed even if the mime type is in general supported. In addition, in some
1141 cases this function will need to load all available media plugins and query them for their support, which
1142 may take some time.
1143*/
1144QStringList QMediaPlayer::supportedMimeTypes(Flags flags)
1145{
1146 return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(serviceType: QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
1147 flags);
1148}
1149
1150/*!
1151 \fn void QMediaPlayer::setVideoOutput(QVideoWidget* output)
1152
1153 Attach a QVideoWidget video \a output to the media player.
1154
1155 If the media player has already video output attached,
1156 it will be replaced with a new one.
1157*/
1158void QMediaPlayer::setVideoOutput(QVideoWidget *output)
1159{
1160 Q_D(QMediaPlayer);
1161
1162 if (d->videoOutput)
1163 unbind(obj: d->videoOutput);
1164
1165 // We don't know (in this library) that QVideoWidget inherits QObject
1166 QObject *outputObject = reinterpret_cast<QObject*>(output);
1167
1168 d->videoOutput = outputObject && bind(obj: outputObject) ? outputObject : nullptr;
1169}
1170
1171/*!
1172 \fn void QMediaPlayer::setVideoOutput(QGraphicsVideoItem* output)
1173
1174 Attach a QGraphicsVideoItem video \a output to the media player.
1175
1176 If the media player has already video output attached,
1177 it will be replaced with a new one.
1178*/
1179void QMediaPlayer::setVideoOutput(QGraphicsVideoItem *output)
1180{
1181 Q_D(QMediaPlayer);
1182
1183 if (d->videoOutput)
1184 unbind(obj: d->videoOutput);
1185
1186 // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject
1187 // but QObject inheritance depends on QObject coming first, so try this out.
1188 QObject *outputObject = reinterpret_cast<QObject*>(output);
1189
1190 d->videoOutput = outputObject && bind(obj: outputObject) ? outputObject : nullptr;
1191}
1192
1193/*!
1194 Sets a video \a surface as the video output of a media player.
1195
1196 If a video output has already been set on the media player the new surface
1197 will replace it.
1198*/
1199
1200void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface)
1201{
1202 Q_D(QMediaPlayer);
1203
1204 d->surfaceOutput.setVideoSurface(surface);
1205
1206 if (d->videoOutput != &d->surfaceOutput) {
1207 if (d->videoOutput)
1208 unbind(obj: d->videoOutput);
1209
1210 d->videoOutput = nullptr;
1211
1212 if (surface && bind(obj: &d->surfaceOutput))
1213 d->videoOutput = &d->surfaceOutput;
1214 } else if (!surface) {
1215 //unbind the surfaceOutput if null surface is set
1216 unbind(obj: &d->surfaceOutput);
1217 d->videoOutput = nullptr;
1218 }
1219}
1220
1221/*!
1222 \since 5.15
1223 Sets multiple video surfaces as the video output of a media player.
1224 This allows the media player to render video frames on different surfaces.
1225
1226 All video surfaces must support at least one shared \c QVideoFrame::PixelFormat.
1227
1228 If a video output has already been set on the media player the new surfaces
1229 will replace it.
1230
1231 \sa QAbstractVideoSurface::supportedPixelFormats
1232*/
1233
1234void QMediaPlayer::setVideoOutput(const QVector<QAbstractVideoSurface *> &surfaces)
1235{
1236 setVideoOutput(!surfaces.empty() ? new QVideoSurfaces(surfaces, this) : nullptr);
1237}
1238
1239/*! \reimp */
1240QMultimedia::AvailabilityStatus QMediaPlayer::availability() const
1241{
1242 Q_D(const QMediaPlayer);
1243
1244 if (!d->control)
1245 return QMultimedia::ServiceMissing;
1246
1247 return QMediaObject::availability();
1248}
1249
1250QAudio::Role QMediaPlayer::audioRole() const
1251{
1252 Q_D(const QMediaPlayer);
1253
1254 if (d->audioRoleControl != nullptr)
1255 return d->audioRoleControl->audioRole();
1256
1257 return QAudio::UnknownRole;
1258}
1259
1260void QMediaPlayer::setAudioRole(QAudio::Role audioRole)
1261{
1262 Q_D(QMediaPlayer);
1263
1264 if (d->audioRoleControl) {
1265 if (d->customAudioRoleControl != nullptr && d->audioRoleControl->audioRole() != audioRole) {
1266 d->customAudioRoleControl->setCustomAudioRole(QString());
1267 }
1268
1269 d->audioRoleControl->setAudioRole(audioRole);
1270 }
1271}
1272
1273/*!
1274 Returns a list of supported audio roles.
1275
1276 If setting the audio role is not supported, an empty list is returned.
1277
1278 \since 5.6
1279 \sa audioRole
1280*/
1281QList<QAudio::Role> QMediaPlayer::supportedAudioRoles() const
1282{
1283 Q_D(const QMediaPlayer);
1284
1285 if (d->audioRoleControl)
1286 return d->audioRoleControl->supportedAudioRoles();
1287
1288 return QList<QAudio::Role>();
1289}
1290
1291QString QMediaPlayer::customAudioRole() const
1292{
1293 Q_D(const QMediaPlayer);
1294
1295 if (audioRole() != QAudio::CustomRole)
1296 return QString();
1297
1298 if (d->customAudioRoleControl != nullptr)
1299 return d->customAudioRoleControl->customAudioRole();
1300
1301 return QString();
1302}
1303
1304void QMediaPlayer::setCustomAudioRole(const QString &audioRole)
1305{
1306 Q_D(QMediaPlayer);
1307
1308 if (d->customAudioRoleControl) {
1309 Q_ASSERT(d->audioRoleControl);
1310 setAudioRole(QAudio::CustomRole);
1311 d->customAudioRoleControl->setCustomAudioRole(audioRole);
1312 }
1313}
1314
1315/*!
1316 Returns a list of supported custom audio roles. An empty list may
1317 indicate that the supported custom audio roles aren't known. The
1318 list may not be complete.
1319
1320 \since 5.11
1321 \sa customAudioRole
1322*/
1323QStringList QMediaPlayer::supportedCustomAudioRoles() const
1324{
1325 Q_D(const QMediaPlayer);
1326
1327 if (d->customAudioRoleControl)
1328 return d->customAudioRoleControl->supportedCustomAudioRoles();
1329
1330 return QStringList();
1331}
1332
1333// Enums
1334/*!
1335 \enum QMediaPlayer::State
1336
1337 Defines the current state of a media player.
1338
1339 \value StoppedState The media player is not playing content, playback will begin from the start
1340 of the current track.
1341 \value PlayingState The media player is currently playing content.
1342 \value PausedState The media player has paused playback, playback of the current track will
1343 resume from the position the player was paused at.
1344*/
1345
1346/*!
1347 \enum QMediaPlayer::MediaStatus
1348
1349 Defines the status of a media player's current media.
1350
1351 \value UnknownMediaStatus The status of the media cannot be determined.
1352 \value NoMedia There is no current media. The player is in the StoppedState.
1353 \value LoadingMedia The current media is being loaded. The player may be in any state.
1354 \value LoadedMedia The current media has been loaded. The player is in the StoppedState.
1355 \value StalledMedia Playback of the current media has stalled due to insufficient buffering or
1356 some other temporary interruption. The player is in the PlayingState or PausedState.
1357 \value BufferingMedia The player is buffering data but has enough data buffered for playback to
1358 continue for the immediate future. The player is in the PlayingState or PausedState.
1359 \value BufferedMedia The player has fully buffered the current media. The player is in the
1360 PlayingState or PausedState.
1361 \value EndOfMedia Playback has reached the end of the current media. The player is in the
1362 StoppedState.
1363 \value InvalidMedia The current media cannot be played. The player is in the StoppedState.
1364*/
1365
1366/*!
1367 \enum QMediaPlayer::Error
1368
1369 Defines a media player error condition.
1370
1371 \value NoError No error has occurred.
1372 \value ResourceError A media resource couldn't be resolved.
1373 \value FormatError The format of a media resource isn't (fully) supported. Playback may still
1374 be possible, but without an audio or video component.
1375 \value NetworkError A network error occurred.
1376 \value AccessDeniedError There are not the appropriate permissions to play a media resource.
1377 \value ServiceMissingError A valid playback service was not found, playback cannot proceed.
1378 \omitvalue MediaIsPlaylist
1379*/
1380
1381// Signals
1382/*!
1383 \fn QMediaPlayer::error(QMediaPlayer::Error error)
1384
1385 Signals that an \a error condition has occurred.
1386
1387 \sa errorString()
1388*/
1389
1390/*!
1391 \fn void QMediaPlayer::stateChanged(State state)
1392
1393 Signal the \a state of the Player object has changed.
1394*/
1395
1396/*!
1397 \fn QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
1398
1399 Signals that the \a status of the current media has changed.
1400
1401 \sa mediaStatus()
1402*/
1403
1404/*!
1405 \fn void QMediaPlayer::mediaChanged(const QMediaContent &media);
1406
1407 Signals that the media source has been changed to \a media.
1408
1409 \sa media(), currentMediaChanged()
1410*/
1411
1412/*!
1413 \fn void QMediaPlayer::currentMediaChanged(const QMediaContent &media);
1414
1415 Signals that the current playing content has been changed to \a media.
1416
1417 \sa currentMedia(), mediaChanged()
1418*/
1419
1420/*!
1421 \fn void QMediaPlayer::playbackRateChanged(qreal rate);
1422
1423 Signals the playbackRate has changed to \a rate.
1424*/
1425
1426/*!
1427 \fn void QMediaPlayer::seekableChanged(bool seekable);
1428
1429 Signals the \a seekable status of the player object has changed.
1430*/
1431
1432/*!
1433 \fn void QMediaPlayer::audioRoleChanged(QAudio::Role role)
1434
1435 Signals that the audio \a role of the media player has changed.
1436
1437 \since 5.6
1438*/
1439
1440/*!
1441 \fn void QMediaPlayer::customAudioRoleChanged(const QString &role)
1442
1443 Signals that the audio \a role of the media player has changed.
1444
1445 \since 5.11
1446*/
1447
1448// Properties
1449/*!
1450 \property QMediaPlayer::state
1451 \brief the media player's playback state.
1452
1453 By default this property is QMediaPlayer::Stopped
1454
1455 \sa mediaStatus(), play(), pause(), stop()
1456*/
1457
1458/*!
1459 \property QMediaPlayer::error
1460 \brief a string describing the last error condition.
1461
1462 \sa error()
1463*/
1464
1465/*!
1466 \property QMediaPlayer::media
1467 \brief the active media source being used by the player object.
1468
1469 The player object will use the QMediaContent for selection of the content to
1470 be played.
1471
1472 By default this property has a null QMediaContent.
1473
1474 Setting this property to a null QMediaContent will cause the player to discard all
1475 information relating to the current media source and to cease all I/O operations related
1476 to that media.
1477
1478 \sa QMediaContent, currentMedia()
1479*/
1480
1481/*!
1482 \property QMediaPlayer::currentMedia
1483 \brief the current active media content being played by the player object.
1484 This value could be different from QMediaPlayer::media property if a playlist is used.
1485 In this case currentMedia indicates the current media content being processed
1486 by the player, while QMediaPlayer::media property contains the original playlist.
1487
1488 \sa QMediaContent, media()
1489*/
1490
1491/*!
1492 \property QMediaPlayer::playlist
1493 \brief the media playlist being used by the player object.
1494
1495 The player object will use the current playlist item for selection of the content to
1496 be played.
1497
1498 By default this property is set to null.
1499
1500 If the media playlist is used as a source, QMediaPlayer::currentMedia is updated with
1501 a current playlist item. The current source should be selected with
1502 QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(),
1503 otherwise the current playlist will be discarded.
1504
1505 \sa QMediaContent
1506*/
1507
1508
1509/*!
1510 \property QMediaPlayer::mediaStatus
1511 \brief the status of the current media stream.
1512
1513 The stream status describes how the playback of the current stream is
1514 progressing.
1515
1516 By default this property is QMediaPlayer::NoMedia
1517
1518 \sa state
1519*/
1520
1521/*!
1522 \property QMediaPlayer::duration
1523 \brief the duration of the current media.
1524
1525 The value is the total playback time in milliseconds of the current media.
1526 The value may change across the life time of the QMediaPlayer object and
1527 may not be available when initial playback begins, connect to the
1528 durationChanged() signal to receive status notifications.
1529*/
1530
1531/*!
1532 \property QMediaPlayer::position
1533 \brief the playback position of the current media.
1534
1535 The value is the current playback position, expressed in milliseconds since
1536 the beginning of the media. Periodically changes in the position will be
1537 indicated with the signal positionChanged(), the interval between updates
1538 can be set with QMediaObject's method setNotifyInterval().
1539*/
1540
1541/*!
1542 \property QMediaPlayer::volume
1543 \brief the current playback volume.
1544
1545 The playback volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume).
1546 Values outside this range will be clamped.
1547
1548 By default the volume is \c 100.
1549
1550 UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale
1551 will produce linear changes in perceived loudness, which is what a user would normally expect
1552 from a volume control. See QAudio::convertVolume() for more details.
1553*/
1554
1555/*!
1556 \property QMediaPlayer::muted
1557 \brief the muted state of the current media.
1558
1559 The value will be true if the playback volume is muted; otherwise false.
1560*/
1561
1562/*!
1563 \property QMediaPlayer::bufferStatus
1564 \brief the percentage of the temporary buffer filled before playback begins or resumes, from
1565 \c 0 (empty) to \c 100 (full).
1566
1567 When the player object is buffering; this property holds the percentage of
1568 the temporary buffer that is filled. The buffer will need to reach 100%
1569 filled before playback can start or resume, at which time mediaStatus() will return
1570 BufferedMedia or BufferingMedia. If the value is anything lower than \c 100, mediaStatus() will
1571 return StalledMedia.
1572
1573 \sa mediaStatus()
1574*/
1575
1576/*!
1577 \property QMediaPlayer::audioAvailable
1578 \brief the audio availabilty status for the current media.
1579
1580 As the life time of QMediaPlayer can be longer than the playback of one
1581 QMediaContent, this property may change over time, the
1582 audioAvailableChanged signal can be used to monitor it's status.
1583*/
1584
1585/*!
1586 \property QMediaPlayer::videoAvailable
1587 \brief the video availability status for the current media.
1588
1589 If available, the QVideoWidget class can be used to view the video. As the
1590 life time of QMediaPlayer can be longer than the playback of one
1591 QMediaContent, this property may change over time, the
1592 videoAvailableChanged signal can be used to monitor it's status.
1593
1594 \sa QVideoWidget, QMediaContent
1595*/
1596
1597/*!
1598 \property QMediaPlayer::seekable
1599 \brief the seek-able status of the current media
1600
1601 If seeking is supported this property will be true; false otherwise. The
1602 status of this property may change across the life time of the QMediaPlayer
1603 object, use the seekableChanged signal to monitor changes.
1604*/
1605
1606/*!
1607 \property QMediaPlayer::playbackRate
1608 \brief the playback rate of the current media.
1609
1610 This value is a multiplier applied to the media's standard play rate. By
1611 default this value is 1.0, indicating that the media is playing at the
1612 standard pace. Values higher than 1.0 will increase the rate of play.
1613 Values less than zero can be set and indicate the media should rewind at the
1614 multiplier of the standard pace.
1615
1616 Not all playback services support change of the playback rate. It is
1617 framework defined as to the status and quality of audio and video
1618 while fast forwarding or rewinding.
1619*/
1620
1621/*!
1622 \property QMediaPlayer::audioRole
1623 \brief the role of the audio stream played by the media player.
1624
1625 It can be set to specify the type of audio being played, allowing the system to make
1626 appropriate decisions when it comes to volume, routing or post-processing.
1627
1628 The audio role must be set before calling setMedia().
1629
1630 customAudioRole is cleared when this property is set to anything other than
1631 QAudio::CustomRole.
1632
1633 \since 5.6
1634 \sa supportedAudioRoles()
1635*/
1636
1637/*!
1638 \property QMediaPlayer::customAudioRole
1639 \brief the role of the audio stream played by the media player.
1640
1641 It can be set to specify the type of audio being played when the backend supports
1642 audio roles unknown to Qt. Specifying a role allows the system to make appropriate
1643 decisions when it comes to volume, routing or post-processing.
1644
1645 The audio role must be set before calling setMedia().
1646
1647 audioRole is set to QAudio::CustomRole when this property is set.
1648
1649 \since 5.11
1650 \sa supportedCustomAudioRoles()
1651*/
1652
1653/*!
1654 \fn void QMediaPlayer::durationChanged(qint64 duration)
1655
1656 Signal the duration of the content has changed to \a duration, expressed in milliseconds.
1657*/
1658
1659/*!
1660 \fn void QMediaPlayer::positionChanged(qint64 position)
1661
1662 Signal the position of the content has changed to \a position, expressed in
1663 milliseconds.
1664*/
1665
1666/*!
1667 \fn void QMediaPlayer::volumeChanged(int volume)
1668
1669 Signal the playback volume has changed to \a volume.
1670*/
1671
1672/*!
1673 \fn void QMediaPlayer::mutedChanged(bool muted)
1674
1675 Signal the mute state has changed to \a muted.
1676*/
1677
1678/*!
1679 \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable)
1680
1681 Signal the availability of visual content has changed to \a videoAvailable.
1682*/
1683
1684/*!
1685 \fn void QMediaPlayer::audioAvailableChanged(bool available)
1686
1687 Signals the availability of audio content has changed to \a available.
1688*/
1689
1690/*!
1691 \fn void QMediaPlayer::bufferStatusChanged(int percentFilled)
1692
1693 Signal the amount of the local buffer filled as a percentage by \a percentFilled.
1694*/
1695
1696/*!
1697 \fn void QMediaPlayer::networkConfigurationChanged(const QNetworkConfiguration &configuration)
1698 \obsolete
1699
1700 Signal that the active in use network access point has been changed to \a configuration and all subsequent network access will use this \a configuration.
1701*/
1702
1703/*!
1704 \enum QMediaPlayer::Flag
1705
1706 \value LowLatency The player is expected to be used with simple audio formats,
1707 but playback should start without significant delay.
1708 Such playback service can be used for beeps, ringtones, etc.
1709
1710 \value StreamPlayback The player is expected to play QIODevice based streams.
1711 If passed to QMediaPlayer constructor, the service supporting
1712 streams playback will be chosen.
1713
1714 \value VideoSurface The player is expected to be able to render to a
1715 QAbstractVideoSurface \l {setVideoOutput()}{output}.
1716*/
1717
1718QT_END_NAMESPACE
1719
1720#include "moc_qmediaplayer.cpp"
1721

source code of qtmultimedia/src/multimedia/playback/qmediaplayer.cpp