summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLev Zelenskiy <lev.zelenskiy@nokia.com>2012-03-09 09:53:21 +1000
committerQt by Nokia <qt-info@nokia.com>2012-03-21 05:43:27 +0100
commit2c034beab5a8d72a148c47e85e020dc64c58068f (patch)
tree069cc8427d307f4c5ee359182a55be6ba7026ee6 /src
parent2ebea05283a2ddad831d5039a49817cefb7c7625 (diff)
QMediaPlayer frontend: changes to playlist support.
Allow to load playlists using setMedia(). Use QNetworkMediaPlaylistProvider for playlist parsing. Updated unit tests. Change-Id: If4dba07be8b2e8a9e9549d5bed58e552dfb958b7 Reviewed-by: Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/multimedia/playback/playback.pri10
-rw-r--r--src/multimedia/playback/qlocalmediaplaylistprovider.cpp194
-rw-r--r--src/multimedia/playback/qlocalmediaplaylistprovider_p.h98
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp403
-rw-r--r--src/multimedia/playback/qmediaplayer.h8
-rw-r--r--src/multimedia/playback/qmediaplaylist.cpp6
-rw-r--r--src/multimedia/playback/qmediaplaylist_p.h16
7 files changed, 346 insertions, 389 deletions
diff --git a/src/multimedia/playback/playback.pri b/src/multimedia/playback/playback.pri
index 284c9f8e6..327b63b32 100644
--- a/src/multimedia/playback/playback.pri
+++ b/src/multimedia/playback/playback.pri
@@ -11,16 +11,18 @@ PRIVATE_HEADERS += \
playback/qmediaplaylist_p.h \
playback/qmediaplaylistprovider_p.h \
playback/qmediaplaylistioplugin_p.h \
- playback/qlocalmediaplaylistprovider_p.h \
- playback/qmediaplaylistnavigator_p.h
+ playback/qmediaplaylistnavigator_p.h \
+ playback/qmedianetworkplaylistprovider_p.h \
+ playback/playlistfileparser_p.h
SOURCES += \
playback/qaudioendpointselector.cpp \
- playback/qlocalmediaplaylistprovider.cpp \
+ playback/qmedianetworkplaylistprovider.cpp \
playback/qmediacontent.cpp \
playback/qmediaplayer.cpp \
playback/qmediaplaylist.cpp \
playback/qmediaplaylistioplugin.cpp \
playback/qmediaplaylistnavigator.cpp \
playback/qmediaplaylistprovider.cpp \
- playback/qmediaresource.cpp
+ playback/qmediaresource.cpp \
+ playback/playlistfileparser.cpp
diff --git a/src/multimedia/playback/qlocalmediaplaylistprovider.cpp b/src/multimedia/playback/qlocalmediaplaylistprovider.cpp
deleted file mode 100644
index 051f76a9b..000000000
--- a/src/multimedia/playback/qlocalmediaplaylistprovider.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qlocalmediaplaylistprovider_p.h"
-#include "qmediaplaylistprovider_p.h"
-#include "qmediacontent.h"
-
-QT_BEGIN_NAMESPACE
-
-class QLocalMediaPlaylistProviderPrivate: public QMediaPlaylistProviderPrivate
-{
-public:
- QList<QMediaContent> resources;
-};
-
-QLocalMediaPlaylistProvider::QLocalMediaPlaylistProvider(QObject *parent)
- :QMediaPlaylistProvider(*new QLocalMediaPlaylistProviderPrivate, parent)
-{
-}
-
-QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider()
-{
-}
-
-bool QLocalMediaPlaylistProvider::isReadOnly() const
-{
- return false;
-}
-
-int QLocalMediaPlaylistProvider::mediaCount() const
-{
- return d_func()->resources.size();
-}
-
-QMediaContent QLocalMediaPlaylistProvider::media(int pos) const
-{
- return d_func()->resources.value(pos);
-}
-
-bool QLocalMediaPlaylistProvider::addMedia(const QMediaContent &content)
-{
- Q_D(QLocalMediaPlaylistProvider);
-
- int pos = d->resources.count();
-
- emit mediaAboutToBeInserted(pos, pos);
- d->resources.append(content);
- emit mediaInserted(pos, pos);
-
- return true;
-}
-
-bool QLocalMediaPlaylistProvider::addMedia(const QList<QMediaContent> &items)
-{
- Q_D(QLocalMediaPlaylistProvider);
-
- if (items.isEmpty())
- return true;
-
- int pos = d->resources.count();
- int end = pos+items.count()-1;
-
- emit mediaAboutToBeInserted(pos, end);
- d->resources.append(items);
- emit mediaInserted(pos, end);
-
- return true;
-}
-
-
-bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QMediaContent &content)
-{
- Q_D(QLocalMediaPlaylistProvider);
-
- emit mediaAboutToBeInserted(pos, pos);
- d->resources.insert(pos, content);
- emit mediaInserted(pos,pos);
-
- return true;
-}
-
-bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QList<QMediaContent> &items)
-{
- Q_D(QLocalMediaPlaylistProvider);
-
- if (items.isEmpty())
- return true;
-
- const int last = pos+items.count()-1;
-
- emit mediaAboutToBeInserted(pos, last);
- for (int i=0; i<items.count(); i++)
- d->resources.insert(pos+i, items.at(i));
- emit mediaInserted(pos, last);
-
- return true;
-}
-
-bool QLocalMediaPlaylistProvider::removeMedia(int fromPos, int toPos)
-{
- Q_D(QLocalMediaPlaylistProvider);
-
- Q_ASSERT(fromPos >= 0);
- Q_ASSERT(fromPos <= toPos);
- Q_ASSERT(toPos < mediaCount());
-
- emit mediaAboutToBeRemoved(fromPos, toPos);
- d->resources.erase(d->resources.begin()+fromPos, d->resources.begin()+toPos+1);
- emit mediaRemoved(fromPos, toPos);
-
- return true;
-}
-
-bool QLocalMediaPlaylistProvider::removeMedia(int pos)
-{
- Q_D(QLocalMediaPlaylistProvider);
-
- emit mediaAboutToBeRemoved(pos, pos);
- d->resources.removeAt(pos);
- emit mediaRemoved(pos, pos);
-
- return true;
-}
-
-bool QLocalMediaPlaylistProvider::clear()
-{
- Q_D(QLocalMediaPlaylistProvider);
- if (!d->resources.isEmpty()) {
- int lastPos = mediaCount()-1;
- emit mediaAboutToBeRemoved(0, lastPos);
- d->resources.clear();
- emit mediaRemoved(0, lastPos);
- }
-
- return true;
-}
-
-void QLocalMediaPlaylistProvider::shuffle()
-{
- Q_D(QLocalMediaPlaylistProvider);
- if (!d->resources.isEmpty()) {
- QList<QMediaContent> resources;
-
- while (!d->resources.isEmpty()) {
- resources.append(d->resources.takeAt(qrand() % d->resources.size()));
- }
-
- d->resources = resources;
- emit mediaChanged(0, mediaCount()-1);
- }
-
-}
-
-#include "moc_qlocalmediaplaylistprovider_p.cpp"
-QT_END_NAMESPACE
-
diff --git a/src/multimedia/playback/qlocalmediaplaylistprovider_p.h b/src/multimedia/playback/qlocalmediaplaylistprovider_p.h
deleted file mode 100644
index 879e8f715..000000000
--- a/src/multimedia/playback/qlocalmediaplaylistprovider_p.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QLOCALMEDIAPAYLISTPROVIDER_P_H
-#define QLOCALMEDIAPAYLISTPROVIDER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qmediaplaylistprovider_p.h"
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-QT_MODULE(Multimedia)
-
-
-class QLocalMediaPlaylistProviderPrivate;
-class Q_MULTIMEDIA_EXPORT QLocalMediaPlaylistProvider : public QMediaPlaylistProvider
-{
- Q_OBJECT
-public:
- QLocalMediaPlaylistProvider(QObject *parent=0);
- virtual ~QLocalMediaPlaylistProvider();
-
- virtual int mediaCount() const;
- virtual QMediaContent media(int pos) const;
-
- virtual bool isReadOnly() const;
-
- virtual bool addMedia(const QMediaContent &content);
- virtual bool addMedia(const QList<QMediaContent> &items);
- virtual bool insertMedia(int pos, const QMediaContent &content);
- virtual bool insertMedia(int pos, const QList<QMediaContent> &items);
- virtual bool removeMedia(int pos);
- virtual bool removeMedia(int start, int end);
- virtual bool clear();
-
-public Q_SLOTS:
- virtual void shuffle();
-
-private:
- Q_DECLARE_PRIVATE(QLocalMediaPlaylistProvider)
-};
-
-QT_END_NAMESPACE
-
-QT_END_HEADER
-
-
-#endif // QLOCALMEDIAPAYLISTSOURCE_P_H
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index 0ff341438..a699e281f 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -49,7 +49,6 @@
#include <qmediaplaylist.h>
#include <qmediaplaylistcontrol_p.h>
#include <qmediaplaylistsourcecontrol_p.h>
-
#include <qmedianetworkaccesscontrol.h>
#include <QtCore/qcoreevent.h>
@@ -97,6 +96,8 @@ public:
} _registerPlayerMetaTypes;
}
+#define MAX_NESTED_PLAYLISTS 16
+
class QMediaPlayerPrivate : public QMediaObjectPrivate
{
Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer)
@@ -105,47 +106,86 @@ public:
QMediaPlayerPrivate()
: provider(0)
, control(0)
- , playlistSourceControl(0)
, state(QMediaPlayer::StoppedState)
, error(QMediaPlayer::NoError)
- , filterStates(false)
, playlist(0)
, networkAccessControl(0)
+ , nestedPlaylists(0)
{}
QMediaServiceProvider *provider;
QMediaPlayerControl* control;
- QMediaPlaylistSourceControl* playlistSourceControl;
QMediaPlayer::State state;
QMediaPlayer::Error error;
QString errorString;
- bool filterStates;
QPointer<QObject> videoOutput;
QMediaPlaylist *playlist;
QMediaNetworkAccessControl *networkAccessControl;
QVideoSurfaceOutput surfaceOutput;
+ QMediaContent rootMedia;
+ QMediaContent pendingPlaylist;
+ QMediaPlaylist *parentPlaylist(QMediaPlaylist *pls);
+ bool isInChain(QUrl url);
+ int nestedPlaylists;
+
+ void setPlaylist(QMediaPlaylist *playlist);
+ void setPlaylistMedia();
+ void loadPlaylist();
+ void disconnectPlaylist();
+ void connectPlaylist();
+
void _q_stateChanged(QMediaPlayer::State state);
void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status);
void _q_error(int error, const QString &errorString);
void _q_updateMedia(const QMediaContent&);
void _q_playlistDestroyed();
+ void _q_handlePlaylistLoaded();
+ void _q_handlePlaylistLoadFailed();
};
+QMediaPlaylist *QMediaPlayerPrivate::parentPlaylist(QMediaPlaylist *pls)
+{
+ // This function finds a parent playlist for an item in the active chain of playlists.
+ // Every item in the chain comes from currentMedia() of its parent.
+ // We don't need to travers the whole tree of playlists,
+ // but only the subtree of active ones.
+ for (QMediaPlaylist *current = rootMedia.playlist(); current && current != pls; current = current->currentMedia().playlist())
+ if (current->currentMedia().playlist() == pls)
+ return current;
+ return 0;
+}
+
+bool QMediaPlayerPrivate::isInChain(QUrl url)
+{
+ // Check whether a URL is already in the chain of playlists.
+ // Also see a comment in parentPlaylist().
+ for (QMediaPlaylist *current = rootMedia.playlist(); current && current != playlist; current = current->currentMedia().playlist())
+ if (current->currentMedia().canonicalUrl() == url) {
+ return true;
+ }
+ return false;
+}
+
void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps)
{
Q_Q(QMediaPlayer);
- if (filterStates)
- return;
-
- if (playlist
- && ps != state && ps == QMediaPlayer::StoppedState
- && (control->mediaStatus() == QMediaPlayer::EndOfMedia ||
- control->mediaStatus() == QMediaPlayer::InvalidMedia)) {
- playlist->next();
- ps = control->state();
+ // Backend switches into stopped state every time new media is about to be loaded.
+ // If media player has a playlist loaded make sure player doesn' stop.
+ if (playlist && playlist->currentIndex() != -1 && ps != state && ps == QMediaPlayer::StoppedState) {
+ if (control->mediaStatus() == QMediaPlayer::EndOfMedia ||
+ control->mediaStatus() == QMediaPlayer::InvalidMedia) {
+ // if media player is not stopped, and
+ // we have finished playback for the current media,
+ // advance to the next item in the playlist
+ Q_ASSERT(state != QMediaPlayer::StoppedState);
+ playlist->next();
+ return;
+ } else if (control->mediaStatus() == QMediaPlayer::LoadingMedia) {
+ return;
+ }
}
if (ps != state) {
@@ -182,10 +222,16 @@ void QMediaPlayerPrivate::_q_error(int error, const QString &errorString)
{
Q_Q(QMediaPlayer);
- this->error = QMediaPlayer::Error(error);
- this->errorString = errorString;
+ if (error == int(QMediaPlayer::MediaIsPlaylist)) {
+ loadPlaylist();
+ } else {
+ this->error = QMediaPlayer::Error(error);
+ this->errorString = errorString;
+ emit q->error(this->error);
- emit q->error(this->error);
+ if (playlist)
+ playlist->next();
+ }
}
void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
@@ -195,9 +241,45 @@ void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
if (!control)
return;
+ // check if the current playlist is a top-level playlist
+ Q_ASSERT(playlist);
+ if (media.isNull() && playlist != rootMedia.playlist()) {
+ // switch back to parent playlist
+ QMediaPlaylist *pls = parentPlaylist(playlist);
+ Q_ASSERT(pls);
+ disconnectPlaylist();
+ playlist = pls;
+ connectPlaylist();
+
+ Q_ASSERT(!pendingPlaylist.playlist());
+ nestedPlaylists--;
+ Q_ASSERT(nestedPlaylists >= 0);
+
+ playlist->next();
+ return;
+ }
+
+ if (media.playlist()) {
+ if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
+ nestedPlaylists++;
+ Q_ASSERT(!pendingPlaylist.playlist());
+
+ // disconnect current playlist
+ disconnectPlaylist();
+ // new playlist signals are connected
+ // in the call to setPlaylist() in _q_handlePlaylistLoaded()
+ playlist = media.playlist();
+ emit q->currentMediaChanged(media);
+ _q_handlePlaylistLoaded();
+ return;
+ } else if (playlist) {
+ playlist->next();
+ }
+ return;
+ }
+
const QMediaPlayer::State currentState = state;
- filterStates = true;
control->setMedia(media, 0);
if (!media.isNull()) {
@@ -212,18 +294,8 @@ void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
break;
}
}
- filterStates = false;
- state = control->state();
-
- if (state != currentState) {
- if (state == QMediaPlayer::PlayingState)
- q->addPropertyWatch("position");
- else
- q->removePropertyWatch("position");
-
- emit q->stateChanged(state);
- }
+ _q_stateChanged(control->state());
}
void QMediaPlayerPrivate::_q_playlistDestroyed()
@@ -233,12 +305,151 @@ void QMediaPlayerPrivate::_q_playlistDestroyed()
if (!control)
return;
- if (playlistSourceControl)
- playlistSourceControl->setPlaylist(0);
-
control->setMedia(QMediaContent(), 0);
}
+void QMediaPlayerPrivate::setPlaylist(QMediaPlaylist *pls)
+{
+ disconnectPlaylist();
+ playlist = pls;
+
+ setPlaylistMedia();
+}
+
+void QMediaPlayerPrivate::setPlaylistMedia()
+{
+ // This function loads current playlist media into backend.
+ // If current media is a playlist, the function recursively
+ // loads media from the playlist.
+ // It also makes sure the correct playlist signals are connected.
+ Q_Q(QMediaPlayer);
+
+ if (playlist) {
+ connectPlaylist();
+ if (playlist->currentMedia().playlist()) {
+ if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
+ emit q->currentMediaChanged(playlist->currentMedia());
+ // rewind nested playlist to start
+ playlist->currentMedia().playlist()->setCurrentIndex(0);
+ nestedPlaylists++;
+ setPlaylist(playlist->currentMedia().playlist());
+ } else {
+ playlist->next();
+ }
+ return;
+ } else if (control != 0) {
+ // If we've just switched to a new playlist,
+ // then last emited currentMediaChanged was a playlist.
+ // Make sure we emit currentMediaChanged if new playlist has
+ // the same media as the previous one:
+ // sample.m3u
+ // test.wav -- processed by backend
+ // nested.m3u -- processed by frontend
+ // test.wav -- processed by backend,
+ // media is not changed,
+ // frontend needs to emit currentMediaChanged
+ bool isSameMedia = (control->media() == playlist->currentMedia());
+ control->setMedia(playlist->currentMedia(), 0);
+ if (isSameMedia) {
+ emit q->currentMediaChanged(control->media());
+ }
+ }
+ } else {
+ q->setMedia(QMediaContent(), 0);
+ }
+}
+
+void QMediaPlayerPrivate::loadPlaylist()
+{
+ Q_Q(QMediaPlayer);
+ Q_ASSERT(pendingPlaylist.isNull());
+
+ // Do not load a playlist if there are more than MAX_NESTED_PLAYLISTS in the chain already,
+ // or if the playlist URL is already in the chain, i.e. do not allow recursive playlists and loops.
+ if (nestedPlaylists < MAX_NESTED_PLAYLISTS && !q->currentMedia().canonicalUrl().isEmpty() && !isInChain(q->currentMedia().canonicalUrl())) {
+ pendingPlaylist = QMediaContent(new QMediaPlaylist, q->currentMedia().canonicalUrl(), true);
+ QObject::connect(pendingPlaylist.playlist(), SIGNAL(loaded()), q, SLOT(_q_handlePlaylistLoaded()));
+ QObject::connect(pendingPlaylist.playlist(), SIGNAL(loadFailed()), q, SLOT(_q_handlePlaylistLoadFailed()));
+ pendingPlaylist.playlist()->load(pendingPlaylist.canonicalUrl());
+ } else if (playlist) {
+ playlist->next();
+ }
+}
+
+void QMediaPlayerPrivate::disconnectPlaylist()
+{
+ Q_Q(QMediaPlayer);
+ if (playlist) {
+ QObject::disconnect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
+ q, SLOT(_q_updateMedia(QMediaContent)));
+ QObject::disconnect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
+ }
+}
+
+void QMediaPlayerPrivate::connectPlaylist()
+{
+ Q_Q(QMediaPlayer);
+ if (playlist) {
+ QObject::connect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
+ q, SLOT(_q_updateMedia(QMediaContent)));
+ QObject::connect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
+ }
+}
+
+void QMediaPlayerPrivate::_q_handlePlaylistLoaded()
+{
+ Q_Q(QMediaPlayer);
+
+ QMediaPlaylist *oldPlaylist = 0;
+ if (pendingPlaylist.playlist()) {
+ Q_ASSERT(!q->currentMedia().playlist());
+ // if there is an active playlist
+ if (playlist) {
+ Q_ASSERT(playlist->currentIndex() >= 0);
+ oldPlaylist = playlist;
+ disconnectPlaylist();
+ playlist->insertMedia(playlist->currentIndex() + 1, pendingPlaylist);
+ playlist->removeMedia(playlist->currentIndex());
+ nestedPlaylists++;
+ } else {
+ Q_ASSERT(!rootMedia.playlist());
+ rootMedia = pendingPlaylist;
+ emit q->mediaChanged(rootMedia);
+ }
+
+ playlist = pendingPlaylist.playlist();
+ emit q->currentMediaChanged(pendingPlaylist);
+ }
+ pendingPlaylist = QMediaContent();
+
+ playlist->next();
+ setPlaylistMedia();
+
+ switch (state) {
+ case QMediaPlayer::PausedState:
+ control->pause();
+ break;
+ case QMediaPlayer::PlayingState:
+ control->play();
+ break;
+ case QMediaPlayer::StoppedState:
+ break;
+ }
+}
+
+void QMediaPlayerPrivate::_q_handlePlaylistLoadFailed()
+{
+ pendingPlaylist = QMediaContent();
+
+ if (!control)
+ return;
+
+ if (playlist)
+ playlist->next();
+ else
+ control->setMedia(QMediaContent(), 0);
+}
+
static QMediaService *playerService(QMediaPlayer::Flags flags)
{
QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();
@@ -277,10 +488,9 @@ QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
d->error = ServiceMissingError;
} else {
d->control = qobject_cast<QMediaPlayerControl*>(d->service->requestControl(QMediaPlayerControl_iid));
- d->playlistSourceControl = qobject_cast<QMediaPlaylistSourceControl*>(d->service->requestControl(QMediaPlaylistSourceControl_iid));
d->networkAccessControl = qobject_cast<QMediaNetworkAccessControl*>(d->service->requestControl(QMediaNetworkAccessControl_iid));
if (d->control != 0) {
- connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(mediaChanged(QMediaContent)));
+ connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(currentMediaChanged(QMediaContent)));
connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State)));
connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus)));
@@ -330,10 +540,7 @@ QMediaContent QMediaPlayer::media() const
{
Q_D(const QMediaPlayer);
- if (d->control != 0)
- return d->control->media();
-
- return QMediaContent();
+ return d->rootMedia;
}
/*!
@@ -356,44 +563,25 @@ const QIODevice *QMediaPlayer::mediaStream() const
QMediaPlaylist *QMediaPlayer::playlist() const
{
- return d_func()->playlistSourceControl ?
- d_func()->playlistSourceControl->playlist() :
- d_func()->playlist;
+ Q_D(const QMediaPlayer);
+
+ return d->rootMedia.playlist();
}
-void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
+QMediaContent QMediaPlayer::currentMedia() const
{
- Q_D(QMediaPlayer);
-
- if (d->playlistSourceControl) {
- if (d->playlistSourceControl->playlist())
- disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
-
- d->playlistSourceControl->setPlaylist(playlist);
-
- if (playlist)
- connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
- } else {
- if (d->playlist) {
- disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)),
- this, SLOT(_q_updateMedia(QMediaContent)));
- disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
- }
-
- d->playlist = playlist;
+ Q_D(const QMediaPlayer);
- if (d->playlist) {
- connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)),
- this, SLOT(_q_updateMedia(QMediaContent)));
- connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
+ if (d->control != 0)
+ return d->control->media();
- if (d->control != 0)
- d->control->setMedia(playlist->currentMedia(), 0);
- } else {
- setMedia(QMediaContent(), 0);
- }
+ return QMediaContent();
+}
- }
+void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
+{
+ QMediaContent m(playlist, QUrl(), false);
+ setMedia(m);
}
/*!
@@ -563,8 +751,18 @@ void QMediaPlayer::play()
}
//if playlist control is available, the service should advance itself
- if (d->playlist && d->playlist->currentIndex() == -1 && !d->playlist->isEmpty())
+ if (d->rootMedia.playlist() && d->rootMedia.playlist()->currentIndex() == -1 && !d->rootMedia.playlist()->isEmpty()) {
+
+ // switch to playing state
+ if (d->state != QMediaPlayer::PlayingState)
+ d->_q_stateChanged(QMediaPlayer::PlayingState);
+
+ if (d->playlist != d->rootMedia.playlist())
+ d->setPlaylist(d->rootMedia.playlist());
+ Q_ASSERT(d->playlist == d->rootMedia.playlist());
+ emit currentMediaChanged(d->rootMedia);
d->playlist->setCurrentIndex(0);
+ }
// Reset error conditions
d->error = NoError;
@@ -595,6 +793,17 @@ void QMediaPlayer::stop()
if (d->control != 0)
d->control->stop();
+
+ // If media player didn't stop in response to control.
+ // This happens if we have an active playlist and control
+ // media status is
+ // QMediaPlayer::LoadingMedia, QMediaPlayer::InvalidMedia, or QMediaPlayer::EndOfMedia
+ // see QMediaPlayerPrivate::_q_stateChanged()
+ if (d->playlist && d->state != QMediaPlayer::StoppedState) {
+ d->state = QMediaPlayer::StoppedState;
+ removePropertyWatch("position");
+ emit stateChanged(QMediaPlayer::StoppedState);
+ }
}
void QMediaPlayer::setPosition(qint64 position)
@@ -654,12 +863,24 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream)
{
Q_D(QMediaPlayer);
-
- if (playlist() && playlist()->currentMedia() != media)
- setPlaylist(0);
-
- if (d->control != 0)
- d_func()->control->setMedia(media, stream);
+ stop();
+
+ QMediaContent oldMedia = d->rootMedia;
+ d->disconnectPlaylist();
+ d->playlist = 0;
+ d->rootMedia = media;
+ d->nestedPlaylists = 0;
+
+ if (oldMedia != media)
+ emit mediaChanged(d->rootMedia);
+
+ if (media.playlist()) {
+ // reset playlist to the 1st item
+ media.playlist()->setCurrentIndex(0);
+ d->setPlaylist(media.playlist());
+ } else if (d->control != 0) {
+ d->control->setMedia(media, stream);
+ }
}
/*!
@@ -796,6 +1017,7 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
return QMediaObject::availabilityError();
}
+
// Enums
/*!
\enum QMediaPlayer::State
@@ -841,6 +1063,7 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
\value NetworkError A network error occurred.
\value AccessDeniedError There are not the appropriate permissions to play a media resource.
\value ServiceMissingError A valid playback service was not found, playback cannot proceed.
+ \omitvalue MediaIsPlaylist
*/
// Signals
@@ -869,9 +1092,17 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
/*!
\fn void QMediaPlayer::mediaChanged(const QMediaContent &media);
- Signals that the current playing content will be obtained from \a media.
+ Signals that the media source has been changed to \a media.
+
+ \sa media(), currentMediaChanged()
+*/
+
+/*!
+ \fn void QMediaPlayer::currentMediaChanged(const QMediaContent &media);
+
+ Signals that the current playing content has been changed to \a media.
- \sa media()
+ \sa currentMedia(), mediaChanged()
*/
/*!
@@ -916,7 +1147,17 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
information relating to the current media source and to cease all I/O operations related
to that media.
- \sa QMediaContent
+ \sa QMediaContent, currentMedia()
+*/
+
+/*!
+ \property QMediaPlayer::currentMedia
+ \brief the current active media content being played by the player object.
+ This value could be different from QMediaPlayer::media property if a playlist is used.
+ In this case currentMedia indicates the current media content being processed
+ by the player, while QMediaPlayer::media property contains the original playlist.
+
+ \sa QMediaContent, media()
*/
/*!
@@ -928,7 +1169,7 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
By default this property is set to null.
- If the media playlist is used as a source, QMediaPlayer::media is updated with
+ If the media playlist is used as a source, QMediaPlayer::currentMedia is updated with
a current playlist item. The current source should be selected with
QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(),
otherwise the current playlist will be discarded.
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index eed09b566..b6d154bc2 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -65,6 +65,7 @@ class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject
{
Q_OBJECT
Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged)
+ Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged)
Q_PROPERTY(QMediaPlaylist * playlist READ playlist WRITE setPlaylist)
Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged)
Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged)
@@ -118,7 +119,8 @@ public:
FormatError,
NetworkError,
AccessDeniedError,
- ServiceMissingError
+ ServiceMissingError,
+ MediaIsPlaylist
};
QMediaPlayer(QObject *parent = 0, Flags flags = 0);
@@ -136,6 +138,7 @@ public:
QMediaContent media() const;
const QIODevice *mediaStream() const;
QMediaPlaylist *playlist() const;
+ QMediaContent currentMedia() const;
State state() const;
MediaStatus mediaStatus() const;
@@ -178,6 +181,7 @@ public Q_SLOTS:
Q_SIGNALS:
void mediaChanged(const QMediaContent &media);
+ void currentMediaChanged(const QMediaContent &media);
void stateChanged(QMediaPlayer::State newState);
void mediaStatusChanged(QMediaPlayer::MediaStatus status);
@@ -210,6 +214,8 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &))
Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&))
Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed())
+ Q_PRIVATE_SLOT(d_func(), void _q_handlePlaylistLoaded())
+ Q_PRIVATE_SLOT(d_func(), void _q_handlePlaylistLoadFailed())
};
QT_END_NAMESPACE
diff --git a/src/multimedia/playback/qmediaplaylist.cpp b/src/multimedia/playback/qmediaplaylist.cpp
index 860fca2cc..8c2cd3112 100644
--- a/src/multimedia/playback/qmediaplaylist.cpp
+++ b/src/multimedia/playback/qmediaplaylist.cpp
@@ -42,8 +42,8 @@
#include "qmediaplaylist.h"
#include "qmediaplaylist_p.h"
#include "qmediaplaylistprovider_p.h"
-#include "qlocalmediaplaylistprovider_p.h"
#include "qmediaplaylistioplugin_p.h"
+#include "qmedianetworkplaylistprovider_p.h"
#include "qmediaservice.h"
#include "qmediaplaylistcontrol_p.h"
#include "qmediaplayercontrol.h"
@@ -129,7 +129,7 @@ QMediaPlaylist::QMediaPlaylist(QObject *parent)
Q_D(QMediaPlaylist);
d->q_ptr = this;
- d->localPlaylistControl = new QLocalMediaPlaylistControl(this);
+ d->networkPlaylistControl = new QMediaNetworkPlaylistControl(this);
setMediaObject(0);
}
@@ -178,7 +178,7 @@ bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject)
newControl = qobject_cast<QMediaPlaylistControl*>(service->requestControl(QMediaPlaylistControl_iid));
if (!newControl)
- newControl = d->localPlaylistControl;
+ newControl = d->networkPlaylistControl;
if (d->control != newControl) {
int oldSize = 0;
diff --git a/src/multimedia/playback/qmediaplaylist_p.h b/src/multimedia/playback/qmediaplaylist_p.h
index 7d718da2a..9a1555184 100644
--- a/src/multimedia/playback/qmediaplaylist_p.h
+++ b/src/multimedia/playback/qmediaplaylist_p.h
@@ -57,7 +57,7 @@
#include "qmediaplaylistcontrol_p.h"
#include "qmediaplayer.h"
#include "qmediaplayercontrol.h"
-#include "qlocalmediaplaylistprovider_p.h"
+#include "qmedianetworkplaylistprovider_p.h"
#include "qmediaobject_p.h"
#include <QtCore/qdebug.h>
@@ -86,7 +86,7 @@ public:
QMediaPlaylistPrivate()
:mediaObject(0),
control(0),
- localPlaylistControl(0),
+ networkPlaylistControl(0),
error(QMediaPlaylist::NoError)
{
}
@@ -105,7 +105,7 @@ public:
{
Q_Q(QMediaPlaylist);
mediaObject = 0;
- if (control != localPlaylistControl)
+ if (control != networkPlaylistControl)
control = 0;
q->setMediaObject(0);
}
@@ -115,7 +115,7 @@ public:
QMediaPlaylistControl *control;
QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); }
- QMediaPlaylistControl *localPlaylistControl;
+ QMediaPlaylistControl *networkPlaylistControl;
bool readItems(QMediaPlaylistReader *reader);
bool writeItems(QMediaPlaylistWriter *writer);
@@ -127,14 +127,14 @@ public:
};
-class QLocalMediaPlaylistControl : public QMediaPlaylistControl
+class QMediaNetworkPlaylistControl : public QMediaPlaylistControl
{
Q_OBJECT
public:
- QLocalMediaPlaylistControl(QObject *parent)
+ QMediaNetworkPlaylistControl(QObject *parent)
:QMediaPlaylistControl(parent)
{
- QMediaPlaylistProvider *playlist = new QLocalMediaPlaylistProvider(this);
+ QMediaPlaylistProvider *playlist = new QMediaNetworkPlaylistProvider(this);
m_navigator = new QMediaPlaylistNavigator(playlist,this);
m_navigator->setPlaybackMode(QMediaPlaylist::Sequential);
@@ -143,7 +143,7 @@ public:
connect(m_navigator, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)));
}
- virtual ~QLocalMediaPlaylistControl() {};
+ virtual ~QMediaNetworkPlaylistControl() {};
QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); }
bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist)