summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2021-09-24 10:53:15 +0200
committerLars Knoll <lars.knoll@qt.io>2021-10-01 08:55:26 +0000
commit23333fb4be2293ceaf129fec134ea687a30596d9 (patch)
tree077f772744c22eaf56e0375bf290e01580ee6d77
parent0581294df9671ad67218ab0ae9e7d297137b4c89 (diff)
Add support for looping to QMediaPlayer
Gapless looping is important for a couple of use cases where you want to play back some file a couple of times. Task-number: QTBUG-95010 Pick-to: 6.2 Change-Id: Idd089f0702acaf3cab71987656f017f4c7fa4c54 Reviewed-by: André de la Rocha <andre.rocha@qt.io> Reviewed-by: Piotr Srebrny <piotr.srebrny@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp6
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm7
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp3
-rw-r--r--src/multimedia/platform/qplatformmediaplayer_p.h20
-rw-r--r--src/multimedia/platform/windows/player/mfplayercontrol.cpp6
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp45
-rw-r--r--src/multimedia/playback/qmediaplayer.h12
7 files changed, 98 insertions, 1 deletions
diff --git a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp
index db24b9f0b..ed1d329f1 100644
--- a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp
+++ b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp
@@ -380,6 +380,8 @@ void QAndroidMediaPlayer::play()
{
StateChangeNotifier notifier(this);
+ resetCurrentLoop();
+
// We need to prepare the mediaplayer again.
if ((mState & AndroidMediaPlayer::Stopped) && !mMediaContent.isEmpty()) {
setMedia(mMediaContent, mMediaStream);
@@ -612,6 +614,10 @@ void QAndroidMediaPlayer::onStateChanged(qint32 state)
Q_EMIT positionChanged(0);
break;
case AndroidMediaPlayer::PlaybackCompleted:
+ if (doLoop()) {
+ mMediaPlayer->play();
+ break;
+ }
stateChanged(QMediaPlayer::StoppedState);
setMediaStatus(QMediaPlayer::EndOfMedia);
break;
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
index 0b5e831ba..6b0514e6e 100644
--- a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
+++ b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
@@ -824,6 +824,8 @@ void AVFMediaPlayer::play()
if (m_state == QMediaPlayer::PlayingState)
return;
+ resetCurrentLoop();
+
if (m_videoOutput && m_videoSink)
m_videoOutput->setLayer([static_cast<AVFMediaPlayerObserver*>(m_observer) playerLayer]);
@@ -933,6 +935,11 @@ void AVFMediaPlayer::audioOutputChanged()
void AVFMediaPlayer::processEOS()
{
+ if (doLoop()) {
+ [[static_cast<AVFMediaPlayerObserver*>(m_observer) player] setRate:m_rate];
+ return;
+ }
+
//AVPlayerItem has reached end of track/stream
#ifdef QT_DEBUG_AVF
qDebug() << Q_FUNC_INFO;
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
index ccfd7041f..e3327a85a 100644
--- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
+++ b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
@@ -203,6 +203,7 @@ void QGstreamerMediaPlayer::play()
{
if (state() == QMediaPlayer::PlayingState || m_url.isEmpty())
return;
+ resetCurrentLoop();
*playerPipeline.inStoppedState() = false;
if (mediaStatus() == QMediaPlayer::EndOfMedia) {
@@ -297,6 +298,8 @@ bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message)
return false;
}
case GST_MESSAGE_EOS:
+ if (doLoop())
+ break;
stopOrEOS(true);
break;
case GST_MESSAGE_BUFFERING: {
diff --git a/src/multimedia/platform/qplatformmediaplayer_p.h b/src/multimedia/platform/qplatformmediaplayer_p.h
index cc9297229..751720774 100644
--- a/src/multimedia/platform/qplatformmediaplayer_p.h
+++ b/src/multimedia/platform/qplatformmediaplayer_p.h
@@ -141,6 +141,24 @@ public:
void mediaStatusChanged(QMediaPlayer::MediaStatus status);
void error(int error, const QString &errorString);
+ void resetCurrentLoop() { m_currentLoop = 0; }
+ bool doLoop() {
+ if (!isSeekable())
+ return false;
+ if (m_loops < 0 || ++m_currentLoop < m_loops) {
+ setPosition(0);
+ return true;
+ }
+ return false;
+ }
+ int loops() { return m_loops; }
+ void setLoops(int loops) {
+ if (m_loops == loops)
+ return;
+ m_loops = loops;
+ Q_EMIT player->loopsChanged();
+ }
+
protected:
explicit QPlatformMediaPlayer(QMediaPlayer *parent = nullptr)
: player(parent)
@@ -152,6 +170,8 @@ private:
bool m_seekable = false;
bool m_videoAvailable = false;
bool m_audioAvailable = false;
+ int m_loops = 1;
+ int m_currentLoop = 0;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/player/mfplayercontrol.cpp b/src/multimedia/platform/windows/player/mfplayercontrol.cpp
index d78768546..4e1046b05 100644
--- a/src/multimedia/platform/windows/player/mfplayercontrol.cpp
+++ b/src/multimedia/platform/windows/player/mfplayercontrol.cpp
@@ -82,6 +82,7 @@ void MFPlayerControl::play()
{
if (m_state == QMediaPlayer::PlayingState)
return;
+ resetCurrentLoop();
if (QMediaPlayer::InvalidMedia == m_session->status())
m_session->load(m_media, m_stream);
@@ -160,7 +161,10 @@ void MFPlayerControl::handleStatusChanged()
QMediaPlayer::MediaStatus status = m_session->status();
switch (status) {
case QMediaPlayer::EndOfMedia:
- changeState(QMediaPlayer::StoppedState);
+ if (doLoop())
+ m_session->start();
+ else
+ changeState(QMediaPlayer::StoppedState);
break;
case QMediaPlayer::InvalidMedia:
break;
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index 2fc4ad4df..d76f3fd0d 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -454,6 +454,51 @@ qreal QMediaPlayer::playbackRate() const
}
/*!
+ \enum QMediaPlayer::Loops
+
+ Some predefined constants for the \l loops property.
+
+ \value Infinite Loop forever.
+ \value Once Play the media once (the default).
+*/
+
+/*!
+ \property QMediaPlayer::loops
+
+ Determines how often the media is played before the player stops.
+ Set to QMediaPlayer::Infinite to loop the current media file forever.
+
+ The default value is \c 1. Setting this property to \c 0 has no effect.
+*/
+
+/*!
+ \qmlproperty int QtMultimedia::MediaPlayer::loops
+
+ Determines how often the media is played before the player stops.
+ Set to MediaPlayer::Infinite to loop the current media file forever.
+
+ The default value is \c 1. Setting this property to \c 0 has no effect.
+*/
+int QMediaPlayer::loops() const
+{
+ Q_D(const QMediaPlayer);
+
+ if (d->control)
+ return d->control->loops();
+
+ return 1;
+}
+
+void QMediaPlayer::setLoops(int loops)
+{
+ Q_D(QMediaPlayer);
+ if (loops == 0)
+ return;
+ if (d->control)
+ d->control->setLoops(loops);
+}
+
+/*!
Returns the current error state.
*/
QMediaPlayer::Error QMediaPlayer::error() const
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index 5796c89e6..0ccb0eaaf 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -66,6 +66,7 @@ class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QObject
Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged)
Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged)
Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged)
+ Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged)
Q_PROPERTY(PlaybackState playbackState READ playbackState NOTIFY playbackStateChanged)
Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged)
Q_PROPERTY(QMediaMetaData metaData READ metaData NOTIFY metaDataChanged)
@@ -118,6 +119,13 @@ public:
};
Q_ENUM(Error)
+ enum Loops
+ {
+ Infinite = -1,
+ Once = 1
+ };
+ Q_ENUM(Loops)
+
explicit QMediaPlayer(QObject *parent = nullptr);
~QMediaPlayer();
@@ -163,6 +171,9 @@ public:
bool isSeekable() const;
qreal playbackRate() const;
+ int loops() const;
+ void setLoops(int loops);
+
Error error() const;
QString errorString() const;
@@ -196,6 +207,7 @@ Q_SIGNALS:
void seekableChanged(bool seekable);
void playbackRateChanged(qreal rate);
+ void loopsChanged();
void metaDataChanged();
void videoOutputChanged();