summaryrefslogtreecommitdiffstats
path: root/src/multimedia/playback/qmediaplayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/multimedia/playback/qmediaplayer.cpp')
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp307
1 files changed, 139 insertions, 168 deletions
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index ac7c8fa06..2336cf12e 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmediaplayer_p.h"
+#include <private/qmultimediautils_p.h>
#include <private/qplatformmediaintegration_p.h>
#include <qvideosink.h>
#include <qaudiooutput.h>
@@ -47,12 +12,15 @@
#include <QtCore/qmetaobject.h>
#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
#include <QtCore/qpointer.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qtemporaryfile.h>
-#include <QtCore/qdir.h>
#include <QtCore/qcoreapplication.h>
-#include <QtCore/qjniobject.h>
+
+#if defined(Q_OS_ANDROID)
+# include <QtCore/qjniobject.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -130,13 +98,15 @@ QT_BEGIN_NAMESPACE
\sa AudioOutput, VideoOutput
*/
-void QMediaPlayerPrivate::setState(QMediaPlayer::PlaybackState ps)
+void QMediaPlayerPrivate::setState(QMediaPlayer::PlaybackState toState)
{
Q_Q(QMediaPlayer);
- if (ps != state) {
- state = ps;
- emit q->playbackStateChanged(ps);
+ if (toState != state) {
+ const auto fromState = std::exchange(state, toState);
+ if (toState == QMediaPlayer::PlayingState || fromState == QMediaPlayer::PlayingState)
+ emit q->playingChanged(toState == QMediaPlayer::PlayingState);
+ emit q->playbackStateChanged(toState);
}
}
@@ -147,14 +117,11 @@ void QMediaPlayerPrivate::setStatus(QMediaPlayer::MediaStatus s)
emit q->mediaStatusChanged(s);
}
-void QMediaPlayerPrivate::setError(int error, const QString &errorString)
+void QMediaPlayerPrivate::setError(QMediaPlayer::Error error, const QString &errorString)
{
Q_Q(QMediaPlayer);
- this->error = QMediaPlayer::Error(error);
- this->errorString = errorString;
- emit q->errorChanged();
- emit q->errorOccurred(this->error, errorString);
+ this->error.setAndNotify(error, errorString, *q);
}
void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
@@ -220,25 +187,14 @@ void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
qWarning("Qt was built with -no-feature-temporaryfile: playback from resource file is not supported!");
#endif
}
-#if defined(Q_OS_ANDROID)
- } else if (media.scheme() == QLatin1String("content") && !stream) {
- // content scheme should happen only on android
- const int fd = QJniObject::callStaticMethod<jint>(
- "org/qtproject/qt/android/QtNative", "openFdForContentUrl",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I",
- QNativeInterface::QAndroidApplication::context(),
- QJniObject::fromString(media.toString()).object(),
- QJniObject::fromString(QLatin1String("r")).object());
-
- file.reset(new QFile(QLatin1Char(':') + media.path()));
- file->open(fd, QFile::ReadOnly, QFile::FileHandleFlag::AutoCloseHandle);
- control->setMedia(media, file.get());
-#endif
} else {
qrcMedia = QUrl();
- QUrl url = media;
- if (url.scheme().isEmpty() || url.scheme() == QLatin1String("file"))
- url = QUrl::fromUserInput(media.path(), QDir::currentPath(), QUrl::AssumeLocalFile);
+ QUrl url = qMediaFromUserInput(media);
+ if (url.scheme() == QLatin1String("content") && !stream) {
+ file.reset(new QFile(media.url()));
+ stream = file.get();
+ }
+
control->setMedia(url, stream);
}
@@ -266,14 +222,14 @@ QMediaPlayer::QMediaPlayer(QObject *parent)
{
Q_D(QMediaPlayer);
- d->control = QPlatformMediaIntegration::instance()->createPlayer(this);
- if (!d->control) { // ### Should this be an assertion?
- d->setError(QMediaPlayer::ResourceError, QMediaPlayer::tr("Platform does not support media playback."));
- return;
+ auto maybeControl = QPlatformMediaIntegration::instance()->createPlayer(this);
+ if (maybeControl) {
+ d->control = maybeControl.value();
+ d->state = d->control->state();
+ } else {
+ qWarning() << "Failed to initialize QMediaPlayer" << maybeControl.error();
+ d->setError(QMediaPlayer::ResourceError, maybeControl.error());
}
- Q_ASSERT(d->control);
-
- d->state = d->control->state();
}
@@ -285,9 +241,13 @@ QMediaPlayer::~QMediaPlayer()
{
Q_D(QMediaPlayer);
- // Disconnect everything to prevent notifying
- // when a receiver is already destroyed.
- disconnect();
+ // prevents emitting audioOutputChanged and videoOutputChanged.
+ QSignalBlocker blocker(this);
+
+ // Reset audio output and video sink to ensure proper unregistering of the source
+ // To be investigated: registering of the source might be removed after switching on the ffmpeg
+ // backend;
+
setAudioOutput(nullptr);
d->setVideoSink(nullptr);
@@ -316,13 +276,20 @@ const QIODevice *QMediaPlayer::sourceDevice() const
return d->stream;
}
+/*!
+ \property QMediaPlayer::playbackState
+
+ Returns the \l{QMediaPlayer::}{PlaybackState}.
+
+ \sa playing
+*/
QMediaPlayer::PlaybackState QMediaPlayer::playbackState() const
{
Q_D(const QMediaPlayer);
// In case if EndOfMedia status is already received
// but state is not.
- if (d->control != nullptr
+ if (d->control
&& d->control->mediaStatus() == QMediaPlayer::EndOfMedia
&& d->state != d->control->state()) {
return d->control->state();
@@ -347,11 +314,7 @@ QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const
qint64 QMediaPlayer::duration() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->duration();
-
- return 0;
+ return d->control ? d->control->duration() : 0;
}
/*!
@@ -364,15 +327,11 @@ qint64 QMediaPlayer::duration() const
qint64 QMediaPlayer::position() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->position();
-
- return 0;
+ return d->control ? d->control->position() : 0;
}
/*!
- Returns a number betwee 0 and 1 when buffering data.
+ Returns a number between 0 and 1 when buffering data.
0 means that there is no buffered data available, playback is usually
stalled in this case. Playback will resume once the buffer reaches 1,
@@ -383,11 +342,7 @@ qint64 QMediaPlayer::position() const
float QMediaPlayer::bufferProgress() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->bufferProgress();
-
- return 0.;
+ return d->control ? d->control->bufferProgress() : 0;
}
/*!
@@ -402,11 +357,7 @@ float QMediaPlayer::bufferProgress() const
QMediaTimeRange QMediaPlayer::bufferedTimeRange() const
{
Q_D(const QMediaPlayer);
-
- if (d->control)
- return d->control->availablePlaybackRanges();
-
- return {};
+ return d->control ? d->control->availablePlaybackRanges() : QMediaTimeRange{};
}
/*!
@@ -422,11 +373,7 @@ QMediaTimeRange QMediaPlayer::bufferedTimeRange() const
bool QMediaPlayer::hasAudio() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->isAudioAvailable();
-
- return false;
+ return d->control && d->control->isAudioAvailable();
}
/*!
@@ -442,11 +389,7 @@ bool QMediaPlayer::hasAudio() const
bool QMediaPlayer::hasVideo() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->isVideoAvailable();
-
- return false;
+ return d->control && d->control->isVideoAvailable();
}
/*!
@@ -458,11 +401,13 @@ bool QMediaPlayer::hasVideo() const
bool QMediaPlayer::isSeekable() const
{
Q_D(const QMediaPlayer);
+ return d->control && d->control->isSeekable();
+}
- if (d->control != nullptr)
- return d->control->isSeekable();
-
- return false;
+bool QMediaPlayer::isPlaying() const
+{
+ Q_D(const QMediaPlayer);
+ return d->state == QMediaPlayer::PlayingState;
}
/*!
@@ -471,11 +416,7 @@ bool QMediaPlayer::isSeekable() const
qreal QMediaPlayer::playbackRate() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->playbackRate();
-
- return 0.0;
+ return d->control ? d->control->playbackRate() : 0.;
}
/*!
@@ -507,11 +448,7 @@ qreal QMediaPlayer::playbackRate() const
int QMediaPlayer::loops() const
{
Q_D(const QMediaPlayer);
-
- if (d->control)
- return d->control->loops();
-
- return 1;
+ return d->control ? d->control->loops() : 1;
}
void QMediaPlayer::setLoops(int loops)
@@ -528,7 +465,7 @@ void QMediaPlayer::setLoops(int loops)
*/
QMediaPlayer::Error QMediaPlayer::error() const
{
- return d_func()->error;
+ return d_func()->error.code();
}
/*!
@@ -545,7 +482,7 @@ QMediaPlayer::Error QMediaPlayer::error() const
*/
QString QMediaPlayer::errorString() const
{
- return d_func()->errorString;
+ return d_func()->error.description();
}
/*!
@@ -553,7 +490,8 @@ QString QMediaPlayer::errorString() const
Starts or resumes playback of the media.
- Sets the \l playbackState property to PlayingState.
+ Sets the \l playbackState property to PlayingState, and changes
+ \l playing to \c true.
*/
/*!
@@ -569,8 +507,7 @@ void QMediaPlayer::play()
return;
// Reset error conditions
- d->error = NoError;
- d->errorString = QString();
+ d->setError(NoError, QString());
d->control->play();
}
@@ -580,7 +517,8 @@ void QMediaPlayer::play()
Pauses playback of the media.
- Sets the \l playbackState property to PausedState.
+ Sets the \l playbackState property to PausedState,
+ and changes \l playing to \c false.
*/
/*!
@@ -592,7 +530,7 @@ void QMediaPlayer::pause()
{
Q_D(QMediaPlayer);
- if (d->control != nullptr)
+ if (d->control)
d->control->pause();
}
@@ -601,7 +539,8 @@ void QMediaPlayer::pause()
Stops playback of the media.
- Sets the \l playbackState property to StoppedState.
+ Sets the \l playbackState property to StoppedState,
+ and changes \l playing to \c false.
*/
/*!
@@ -613,7 +552,7 @@ void QMediaPlayer::stop()
{
Q_D(QMediaPlayer);
- if (d->control != nullptr)
+ if (d->control)
d->control->stop();
}
@@ -621,7 +560,7 @@ void QMediaPlayer::setPosition(qint64 position)
{
Q_D(QMediaPlayer);
- if (d->control == nullptr)
+ if (!d->control)
return;
if (!d->control->isSeekable())
return;
@@ -632,7 +571,7 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
{
Q_D(QMediaPlayer);
- if (d->control != nullptr)
+ if (d->control)
d->control->setPlaybackRate(rate);
}
@@ -651,12 +590,18 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
Setting the media to a null QUrl will cause the player to discard all
information relating to the current media source and to cease all I/O operations related
- to that media.
+ to that media. Setting the media will stop the playback.
\note This function returns immediately after recording the specified source of the media.
It does not wait for the media to finish loading and does not check for errors. Listen for
the mediaStatusChanged() and error() signals to be notified when the media is loaded and
when an error occurs during loading.
+
+ \note FFmpeg, used by the FFmpeg media backend, restricts use of nested protocols for
+ security reasons. In controlled environments where all inputs are trusted, the list of
+ approved protocols can be overridden using the QT_FFMPEG_PROTOCOL_WHITELIST environment
+ variable. This environment variable is Qt's private API and can change between patch
+ releases without notice.
*/
void QMediaPlayer::setSource(const QUrl &source)
@@ -729,12 +674,14 @@ void QMediaPlayer::setAudioOutput(QAudioOutput *output)
if (oldOutput == output)
return;
d->audioOutput = output;
- d->control->setAudioOutput(nullptr);
+ if (d->control)
+ d->control->setAudioOutput(nullptr);
if (oldOutput)
oldOutput->setDisconnectFunction({});
if (output) {
output->setDisconnectFunction([this](){ setAudioOutput(nullptr); });
- d->control->setAudioOutput(output->handle());
+ if (d->control)
+ d->control->setAudioOutput(output->handle());
}
emit audioOutputChanged();
}
@@ -759,6 +706,8 @@ QAudioOutput *QMediaPlayer::audioOutput() const
*/
/*!
+ \property QMediaPlayer::audioTracks
+
Lists the set of available audio tracks inside the media.
The QMediaMetaData returned describes the properties of individual
@@ -784,6 +733,8 @@ QList<QMediaMetaData> QMediaPlayer::audioTracks() const
*/
/*!
+ \property QMediaPlayer::videoTracks
+
Lists the set of available video tracks inside the media.
The QMediaMetaData returned describes the properties of individual
@@ -809,6 +760,8 @@ QList<QMediaMetaData> QMediaPlayer::videoTracks() const
*/
/*!
+ \property QMediaPlayer::subtitleTracks
+
Lists the set of available subtitle tracks inside the media.
The QMediaMetaData returned describes the properties of individual
@@ -840,9 +793,7 @@ QList<QMediaMetaData> QMediaPlayer::subtitleTracks() const
int QMediaPlayer::activeAudioTrack() const
{
Q_D(const QMediaPlayer);
- if (d->control)
- return d->control->activeTrack(QPlatformMediaPlayer::AudioStream);
- return 0;
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::AudioStream) : 0;
}
/*!
@@ -866,9 +817,7 @@ int QMediaPlayer::activeAudioTrack() const
int QMediaPlayer::activeVideoTrack() const
{
Q_D(const QMediaPlayer);
- if (d->control)
- return d->control->activeTrack(QPlatformMediaPlayer::VideoStream);
- return -1;
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::VideoStream) : -1;
}
/*!
@@ -892,9 +841,7 @@ int QMediaPlayer::activeVideoTrack() const
int QMediaPlayer::activeSubtitleTrack() const
{
Q_D(const QMediaPlayer);
- if (d->control)
- return d->control->activeTrack(QPlatformMediaPlayer::SubtitleStream);
- return -1;
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::SubtitleStream) : -1;
}
void QMediaPlayer::setActiveAudioTrack(int index)
@@ -958,31 +905,32 @@ QObject *QMediaPlayer::videoOutput() const
void QMediaPlayer::setVideoOutput(QObject *output)
{
Q_D(QMediaPlayer);
- if (!d->control)
- return;
if (d->videoOutput == output)
return;
- QVideoSink *sink = qobject_cast<QVideoSink *>(output);
+ auto *sink = qobject_cast<QVideoSink *>(output);
if (!sink && output) {
auto *mo = output->metaObject();
- if (output)
- mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
+ mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
}
d->videoOutput = output;
d->setVideoSink(sink);
}
+/*!
+ Sets \a sink to be the QVideoSink instance to
+ retrieve video data.
+*/
void QMediaPlayer::setVideoSink(QVideoSink *sink)
{
Q_D(QMediaPlayer);
- if (!d->control)
- return;
-
d->videoOutput = nullptr;
d->setVideoSink(sink);
}
+/*!
+ Returns the QVideoSink instance.
+*/
QVideoSink *QMediaPlayer::videoSink() const
{
Q_D(const QMediaPlayer);
@@ -1013,11 +961,7 @@ void QMediaPlayer::setVideoOutput(const QList<QVideoSink *> &sinks)
bool QMediaPlayer::isAvailable() const
{
Q_D(const QMediaPlayer);
-
- if (!d->control)
- return false;
-
- return true;
+ return bool(d->control);
}
/*!
@@ -1032,6 +976,8 @@ bool QMediaPlayer::isAvailable() const
*/
/*!
+ \property QMediaPlayer::metaData
+
Returns meta data for the current media used by the media player.
Meta data can contain information such as the title of the video or its creation date.
@@ -1042,7 +988,7 @@ bool QMediaPlayer::isAvailable() const
QMediaMetaData QMediaPlayer::metaData() const
{
Q_D(const QMediaPlayer);
- return d->control->metaData();
+ return d->control ? d->control->metaData() : QMediaMetaData{};
}
// Enums
@@ -1053,7 +999,7 @@ QMediaMetaData QMediaPlayer::metaData() const
\value StoppedState The media player is not playing content, playback will begin from the start
of the current track.
- \value PlayingState The media player is currently playing content.
+ \value PlayingState The media player is currently playing content. This indicates the same as the \l playing property.
\value PausedState The media player has paused playback, playback of the current track will
resume from the position the player was paused at.
*/
@@ -1067,7 +1013,7 @@ QMediaMetaData QMediaPlayer::metaData() const
\header \li Property value
\li Description
\row \li PlayingState
- \li The media is currently playing.
+ \li The media is currently playing. This indicates the same as the \l playing property.
\row \li PausedState
\li Playback of the media has been suspended.
\row \li StoppedState
@@ -1082,6 +1028,12 @@ QMediaMetaData QMediaPlayer::metaData() const
*/
/*!
+ \qmlsignal QtMultimedia::MediaPlayer::playingChanged()
+
+ This signal is emitted when the \l playing property changes.
+*/
+
+/*!
\enum QMediaPlayer::MediaStatus
Defines the status of a media player's current media.
@@ -1288,7 +1240,7 @@ QMediaMetaData QMediaPlayer::metaData() const
Playback can start or resume only when the buffer is entirely filled.
When the buffer is filled, \c MediaPlayer.Buffered is true.
- When buffer progress is between \c 0.0 and \c 0.1, \c MediaPlayer.Buffering
+ When buffer progress is between \c 0.0 and \c 1.0, \c MediaPlayer.Buffering
is set to \c{true}.
A value lower than \c 1.0 implies that the property \c MediaPlayer.StalledMedia
@@ -1327,11 +1279,30 @@ QMediaMetaData QMediaPlayer::metaData() const
*/
/*!
+ \qmlproperty bool QtMultimedia::MediaPlayer::playing
+ \since 6.5
+
+ Indicates whether the media is currently playing.
+
+ \sa playbackState
+*/
+
+/*!
+ \property QMediaPlayer::playing
+ \brief Whether the media is playing.
+ \since 6.5
+
+ \sa playbackState, PlayingState
+*/
+
+/*!
\qmlproperty real QtMultimedia::MediaPlayer::playbackRate
- This property holds the rate at which audio is played at as a multiple of
+ This property holds the rate at which media is played at as a multiple of
the normal rate.
+ For more information, see \l{QMediaPlayer::playbackRate}.
+
Defaults to \c{1.0}.
*/
@@ -1339,11 +1310,11 @@ QMediaMetaData QMediaPlayer::metaData() const
\property QMediaPlayer::playbackRate
\brief the playback rate of the current media.
- This value is a multiplier applied to the media's standard play rate. By
- default this value is 1.0, indicating that the media is playing at the
- standard pace. Values higher than 1.0 will increase the rate of play.
- Values less than zero can be set and indicate the media should rewind at the
- multiplier of the standard pace.
+ This value is a multiplier applied to the media's standard playback
+ rate. By default this value is 1.0, indicating that the media is
+ playing at the standard speed. Values higher than 1.0 will increase
+ the playback speed, while values between 0.0 and 1.0 results in
+ slower playback. Negative playback rates are not supported.
Not all playback services support change of the playback rate. It is
framework defined as to the status and quality of audio and video