summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2021-02-17 18:17:06 +0100
committerLars Knoll <lars.knoll@qt.io>2021-03-05 12:32:45 +0000
commita1f9b691c7960eefed6118b79b66f096094d75b2 (patch)
tree2047f79ff778dd5a7c1b0162e69f29c63a3ac89a
parentf5ae5377805c3541fa19fe6c8001113f36f86bc4 (diff)
Add support for selecting audio/video tracks
Implement this for the gstreamer backend. The API for subtitle tracks is also there, but we do not support displaying those for the moment. Change-Id: Ia561656d63c33ac4ea5d167846d4535820180fb3 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Doris Verria <doris.verria@qt.io>
-rw-r--r--examples/multimediawidgets/player/player.cpp53
-rw-r--r--examples/multimediawidgets/player/player.h9
-rw-r--r--src/multimedia/platform/gstreamer/common/qgst_p.h3
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp117
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h17
-rw-r--r--src/multimedia/platform/qplatformmediaplayer_p.h10
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp79
-rw-r--r--src/multimedia/playback/qmediaplayer.h23
8 files changed, 260 insertions, 51 deletions
diff --git a/examples/multimediawidgets/player/player.cpp b/examples/multimediawidgets/player/player.cpp
index 6c4df136c..7f7657ce2 100644
--- a/examples/multimediawidgets/player/player.cpp
+++ b/examples/multimediawidgets/player/player.cpp
@@ -91,6 +91,7 @@ Player::Player(QWidget *parent)
connect(m_player, &QMediaPlayer::videoAvailableChanged, this, &Player::videoAvailableChanged);
connect(m_player, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error), this, &Player::displayErrorMessage);
connect(m_player, &QMediaPlayer::stateChanged, this, &Player::stateChanged);
+ connect(m_player, &QMediaPlayer::tracksChanged, this, &Player::tracksChanged);
m_playlistView = new QListView(this);
m_playlistView->setModel(m_playlistModel);
@@ -104,6 +105,20 @@ Player::Player(QWidget *parent)
m_labelDuration = new QLabel(this);
connect(m_slider, &QSlider::sliderMoved, this, &Player::seek);
+ m_audioTracks = new QComboBox(this);
+ m_videoTracks = new QComboBox(this);
+ m_subtitleTracks = new QComboBox(this);
+ connect(m_audioTracks, &QComboBox::activated, this, &Player::selectAudioStream);
+ connect(m_videoTracks, &QComboBox::activated, this, &Player::selectVideoStream);
+ connect(m_subtitleTracks, &QComboBox::activated, this, &Player::selectSubtitleStream);
+ QGridLayout *tracksLayout = new QGridLayout;
+ tracksLayout->addWidget(new QLabel(tr("Audio Tracks:"), this), 0, 0);
+ tracksLayout->addWidget(m_audioTracks, 0, 1);
+ tracksLayout->addWidget(new QLabel(tr("Video Tracks:"), this), 1, 0);
+ tracksLayout->addWidget(m_videoTracks, 1, 1);
+ tracksLayout->addWidget(new QLabel(tr("Subtitle Tracks:"), this), 2, 0);
+ tracksLayout->addWidget(m_subtitleTracks, 2, 1);
+
m_labelHistogram = new QLabel(this);
m_labelHistogram->setText("Histogram:");
m_videoHistogram = new HistogramWidget(this);
@@ -201,6 +216,7 @@ Player::Player(QWidget *parent)
hLayout->addWidget(m_labelDuration);
layout->addLayout(hLayout);
layout->addLayout(controlLayout);
+ layout->addLayout(tracksLayout);
layout->addLayout(histogramLayout);
layout->addWidget(metaDataLabel);
layout->addLayout(metaDataLayout);
@@ -326,6 +342,25 @@ void Player::metaDataChanged()
}
}
+void Player::tracksChanged()
+{
+ m_audioTracks->clear();
+ m_videoTracks->clear();
+ m_subtitleTracks->clear();
+
+ const auto audioStreams = m_player->audioTracks();
+ for (int i = 0; i < audioStreams.size(); ++i)
+ m_audioTracks->addItem(audioStreams.at(i).stringValue(QMediaMetaData::Language), i);
+
+ const auto videoStreams = m_player->videoTracks();
+ for (int i = 0; i < videoStreams.size(); ++i)
+ m_videoTracks->addItem(videoStreams.at(i).stringValue(QMediaMetaData::Language), i);
+
+ const auto subtitleStreams = m_player->subtitleTracks();
+ for (int i = 0; i < subtitleStreams.size(); ++i)
+ m_subtitleTracks->addItem(subtitleStreams.at(i).stringValue(QMediaMetaData::Language), i);
+}
+
void Player::previousClicked()
{
// Go to previous track if we are within the first 5 seconds of playback
@@ -429,6 +464,24 @@ void Player::videoAvailableChanged(bool available)
m_colorButton->setEnabled(available);
}
+void Player::selectAudioStream()
+{
+ int stream = m_audioTracks->currentData().toInt();
+ m_player->setActiveAudioTrack(stream);
+}
+
+void Player::selectVideoStream()
+{
+ int stream = m_audioTracks->currentData().toInt();
+ m_player->setActiveVideoTrack(stream);
+}
+
+void Player::selectSubtitleStream()
+{
+ int stream = m_audioTracks->currentData().toInt();
+ m_player->setActiveSubtitleTrack(stream);
+}
+
void Player::setTrackInfo(const QString &info)
{
m_trackInfo = info;
diff --git a/examples/multimediawidgets/player/player.h b/examples/multimediawidgets/player/player.h
index 3944d0f3f..7385d27a9 100644
--- a/examples/multimediawidgets/player/player.h
+++ b/examples/multimediawidgets/player/player.h
@@ -92,6 +92,7 @@ private slots:
void durationChanged(qint64 duration);
void positionChanged(qint64 progress);
void metaDataChanged();
+ void tracksChanged();
void previousClicked();
@@ -104,6 +105,10 @@ private slots:
void bufferingProgress(int progress);
void videoAvailableChanged(bool available);
+ void selectAudioStream();
+ void selectVideoStream();
+ void selectSubtitleStream();
+
void displayErrorMessage();
void showColorDialog();
@@ -129,6 +134,10 @@ private:
QLabel *m_statusLabel = nullptr;
QStatusBar *m_statusBar = nullptr;
+ QComboBox *m_audioTracks = nullptr;
+ QComboBox *m_videoTracks = nullptr;
+ QComboBox *m_subtitleTracks = nullptr;
+
QLabel *m_labelHistogram = nullptr;
HistogramWidget *m_videoHistogram = nullptr;
HistogramWidget *m_audioHistogram = nullptr;
diff --git a/src/multimedia/platform/gstreamer/common/qgst_p.h b/src/multimedia/platform/gstreamer/common/qgst_p.h
index 3bfa2503a..b779960f9 100644
--- a/src/multimedia/platform/gstreamer/common/qgst_p.h
+++ b/src/multimedia/platform/gstreamer/common/qgst_p.h
@@ -236,7 +236,7 @@ public:
QGstObject(GstObject *o, RefMode mode = HasRef)
: m_object(o)
{
- if (mode == NeedsRef)
+ if (o && mode == NeedsRef)
// Use ref_sink to remove any floating references
gst_object_ref_sink(m_object);
}
@@ -274,6 +274,7 @@ public:
void set(const char *property, qint64 i) { g_object_set(m_object, property, gint64(i), nullptr); }
void set(const char *property, quint64 i) { g_object_set(m_object, property, guint64(i), nullptr); }
void set(const char *property, double d) { g_object_set(m_object, property, gdouble(d), nullptr); }
+ void set(const char *property, const QGstObject &o) { g_object_set(m_object, property, o.object(), nullptr); }
QGString getString(const char *property) const
{ char *s = nullptr; g_object_get(m_object, property, &s, nullptr); return s; }
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
index ee8e8e279..6fbaba9b1 100644
--- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
+++ b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
@@ -39,7 +39,6 @@
#include <private/qgstreamermediaplayer_p.h>
#include <private/qgstreamerplayersession_p.h>
-#include <private/qgstreamerstreamscontrol_p.h>
#include <private/qgstreamervideorenderer_p.h>
#include <private/qgstreamerbushelper_p.h>
#include <private/qgstreamermetadata_p.h>
@@ -66,24 +65,24 @@ QT_BEGIN_NAMESPACE
QGstreamerMediaPlayer::QGstreamerMediaPlayer(QObject *parent)
: QPlatformMediaPlayer(parent)
{
- audioInputSelector = QGstElement("input-selector", "audioInputSelector");
+ inputSelector[AudioStream] = QGstElement("input-selector", "audioInputSelector");
audioQueue = QGstElement("queue", "audioQueue");
audioConvert = QGstElement("audioconvert", "audioConvert");
audioResample = QGstElement("audioresample", "audioResample");
audioVolume = QGstElement("volume", "volume");
audioSink = QGstElement("autoaudiosink", "autoAudioSink");
- playerPipeline.add(audioInputSelector, audioQueue, audioConvert, audioResample, audioVolume, audioSink);
- audioInputSelector.link(audioQueue, audioConvert, audioResample, audioVolume, audioSink);
+ playerPipeline.add(inputSelector[AudioStream], audioQueue, audioConvert, audioResample, audioVolume, audioSink);
+ inputSelector[AudioStream].link(audioQueue, audioConvert, audioResample, audioVolume, audioSink);
- videoInputSelector = QGstElement("input-selector", "videoInputSelector");
+ inputSelector[VideoStream] = QGstElement("input-selector", "videoInputSelector");
videoQueue = QGstElement("queue", "videoQueue");
videoConvert = QGstElement("videoconvert", "videoConvert");
videoScale = QGstElement("videoscale", "videoScale");
- playerPipeline.add(videoInputSelector, videoQueue, videoConvert, videoScale);
- videoInputSelector.link(videoQueue, videoConvert, videoScale);
+ playerPipeline.add(inputSelector[VideoStream], videoQueue, videoConvert, videoScale);
+ inputSelector[VideoStream].link(videoQueue, videoConvert, videoScale);
- subTitleInputSelector = QGstElement("input-selector", "subTitleInputSelector");
- playerPipeline.add(subTitleInputSelector);
+ inputSelector[SubtitleStream] = QGstElement("input-selector", "subTitleInputSelector");
+ playerPipeline.add(inputSelector[SubtitleStream]);
playerPipeline.setState(GST_STATE_NULL);
@@ -300,12 +299,16 @@ void QGstreamerMediaPlayer::busMessage(const QGstreamerMessage &message)
QMediaPlayer::State prevState = m_state;
m_state = QMediaPlayer::PausedState;
- //check for seekable
- if (oldState == GST_STATE_READY) {
+ if (prerolling) {
+ prerolling = false;
+ GST_DEBUG_BIN_TO_DOT_FILE(playerPipeline.bin(), GST_DEBUG_GRAPH_SHOW_ALL, "playerPipeline");
+
parseStreamsAndMetadata();
if (!qFuzzyCompare(m_playbackRate, qreal(1.0)))
playerPipeline.seek(playerPipeline.position(), m_playbackRate);
+
+ emit tracksChanged();
}
if (m_state != prevState)
@@ -473,26 +476,38 @@ void QGstreamerMediaPlayer::decoderPadAdded(const QGstElement &src, const QGstPa
qCDebug(qLcMediaPlayer) << "Received new pad" << pad.name() << "from" << src.name() << "type" << type;
qCDebug(qLcMediaPlayer) << " " << caps.toString();
- QGstElement selector;
+ TrackType streamType = NTrackTypes;
if (type.startsWith("video/x-raw")) {
- selector = videoInputSelector;
+ streamType = VideoStream;
} else if (type.startsWith("audio/x-raw")) {
- selector = audioInputSelector;
+ streamType = AudioStream;
} else if (type.startsWith("text/")) {
- selector = subTitleInputSelector;
+ streamType = SubtitleStream;
} else {
- qCWarning(qLcMediaPlayer) << "Failed to add fake sink to unknown pad." << pad.name() << type;
+ qCWarning(qLcMediaPlayer) << "Ignoring unknown media stream:" << pad.name() << type;
return;
}
- QGstPad sinkPad = selector.getRequestPad("sink_%u");
+ QGstPad sinkPad = inputSelector[streamType].getRequestPad("sink_%u");
if (!pad.link(sinkPad))
qCWarning(qLcMediaPlayer) << "Failed to link video pads.";
+ m_streams[streamType].append(sinkPad);
+
+ if (!prerolling)
+ emit tracksChanged();
decoderOutputMap.insert(pad.name(), sinkPad);
}
void QGstreamerMediaPlayer::decoderPadRemoved(const QGstElement &src, const QGstPad &pad)
{
+ int streamType;
+ for (streamType = 0; streamType < NTrackTypes; ++streamType) {
+ if (src == inputSelector[streamType])
+ break;
+ }
+ if (streamType == NTrackTypes)
+ return;
+
qCDebug(qLcMediaPlayer) << "Removed pad" << pad.name() << "from" << src.name();
QGstPad peer = decoderOutputMap.value(pad.name());
if (peer.isNull())
@@ -500,12 +515,12 @@ void QGstreamerMediaPlayer::decoderPadRemoved(const QGstElement &src, const QGst
QGstElement peerParent = peer.parent();
qCDebug(qLcMediaPlayer) << " was linked to pad" << peer.name() << "from" << peerParent.name();
peerParent.releaseRequestPad(peer);
-}
-void QGstreamerMediaPlayer::padsDone(const QGstElement &/*src*/)
-{
- qCDebug(qLcMediaPlayer) << "All pads have been added";
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (playerPipeline.bin(), GST_DEBUG_GRAPH_SHOW_ALL, "playerPipeline");
+ Q_ASSERT(m_streams[streamType].indexOf(peer) != -1);
+ m_streams[streamType].removeAll(peer);
+
+ if (!prerolling)
+ emit tracksChanged();
}
void QGstreamerMediaPlayer::uridecodebinElementAddedCallback(GstElement */*uridecodebin*/, GstElement *child, QGstreamerMediaPlayer *that)
@@ -523,6 +538,8 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
{
qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << "setting location to" << content;
+ prerolling = true;
+
int ret = playerPipeline.setStateSync(GST_STATE_NULL);
if (ret == GST_STATE_CHANGE_FAILURE)
qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the stopped state.";
@@ -564,7 +581,6 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
}
decoder.onPadAdded<&QGstreamerMediaPlayer::decoderPadAdded>(this);
decoder.onPadRemoved<&QGstreamerMediaPlayer::decoderPadRemoved>(this);
- decoder.onNoMorePads<&QGstreamerMediaPlayer::padsDone>(this);
if (m_state == QMediaPlayer::PlayingState) {
int ret = playerPipeline.setState(GST_STATE_PLAYING);
@@ -780,6 +796,15 @@ void QGstreamerMediaPlayer::parseStreamsAndMetadata()
}
}
+ QGstPad sinkPad = inputSelector[VideoStream].getObject("active-pad");
+ Q_ASSERT(!sinkPad.isNull());
+ bool hasTags = g_object_class_find_property (G_OBJECT_GET_CLASS (sinkPad.object()), "tags") != NULL;
+
+ GstTagList *tl = nullptr;
+ g_object_get(sinkPad.object(), "tags", &tl, nullptr);
+ qCDebug(qLcMediaPlayer) << " tags=" << hasTags << (tl ? gst_tag_list_to_string(tl) : "(null)");
+
+
qCDebug(qLcMediaPlayer) << "============== end parse topology ============";
emit metaDataChanged();
}
@@ -797,23 +822,53 @@ void QGstreamerMediaPlayer::setVideoSurface(QAbstractVideoSurface *surface)
updateVideoSink();
}
-QMediaStreamsControl *QGstreamerMediaPlayer::mediaStreams()
+int QGstreamerMediaPlayer::trackCount(QPlatformMediaPlayer::TrackType type)
{
-// if (!m_streamsControl)
-// m_streamsControl = new QGstreamerStreamsControl(m_session, this);
- return m_streamsControl;
+ return m_streams[type].count();
+}
+
+QMediaMetaData QGstreamerMediaPlayer::trackMetaData(QPlatformMediaPlayer::TrackType type, int index)
+{
+ auto &s = m_streams[type];
+ if (index < 0 || index >= s.count())
+ return QMediaMetaData();
+
+ GstTagList *tagList;
+ g_object_get(s.at(index).object(), "tags", &tagList, nullptr);
+
+ QMediaMetaData md = QGstreamerMetaData::fromGstTagList(tagList);
+ return md;
+}
+
+int QGstreamerMediaPlayer::activeTrack(QPlatformMediaPlayer::TrackType type)
+{
+ auto &selector = inputSelector[type];
+ Q_ASSERT(!selector.isNull());
+ QGstPad activePad = selector.getObject("active-pad");
+ if (activePad.isNull())
+ return -1;
+ auto &streams = m_streams[type];
+ return streams.indexOf(activePad);
+}
+
+void QGstreamerMediaPlayer::setActiveTrack(QPlatformMediaPlayer::TrackType type, int index)
+{
+ auto &streams = m_streams[type];
+ if (index < 0 || index >= streams.count())
+ return;
+ auto &selector = inputSelector[type];
+ Q_ASSERT(!selector.isNull());
+ selector.set("active-pad", streams.at(index));
}
bool QGstreamerMediaPlayer::isAudioAvailable() const
{
-// return m_session->isAudioAvailable();
- return true;
+ return !m_streams[AudioStream].isEmpty();
}
bool QGstreamerMediaPlayer::isVideoAvailable() const
{
-// return m_session->isVideoAvailable();
- return true;
+ return !m_streams[VideoStream].isEmpty();
}
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
index 89a6fc250..93fea1c06 100644
--- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
+++ b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
@@ -61,7 +61,6 @@ QT_BEGIN_NAMESPACE
class QNetworkAccessManager;
class QGstreamerPlayerSession;
-class QGstreamerStreamsControl;
class QGstreamerVideoRenderer;
class QGstreamerBusHelper;
class QGstreamerMessage;
@@ -108,7 +107,10 @@ public:
void setVideoSurface(QAbstractVideoSurface *surface) override;
- QMediaStreamsControl *mediaStreams() override;
+ int trackCount(TrackType) override;
+ QMediaMetaData trackMetaData(TrackType /*type*/, int /*streamNumber*/) override;
+ int activeTrack(TrackType) override;
+ void setActiveTrack(TrackType, int /*streamNumber*/) override;
public Q_SLOTS:
void setPosition(qint64 pos) override;
@@ -122,11 +124,12 @@ public Q_SLOTS:
void busMessage(const QGstreamerMessage& message);
+
+
private:
friend class QGstreamerStreamsControl;
void decoderPadAdded(const QGstElement &src, const QGstPad &pad);
void decoderPadRemoved(const QGstElement &src, const QGstPad &pad);
- void padsDone(const QGstElement &src);
void prepareAudioOutputChange(const QGstPad &pad);
static void uridecodebinElementAddedCallback(GstElement *uridecodebin, GstElement *child, QGstreamerMediaPlayer *that);
bool changeAudioOutput();
@@ -134,8 +137,8 @@ private:
void setSeekable(bool seekable);
void parseStreamsAndMetadata();
- QGstreamerStreamsControl *m_streamsControl = nullptr;
QMediaMetaData m_metaData;
+ QList<QGstPad> m_streams[3];
QMediaPlayer::State m_state = QMediaPlayer::StoppedState;
QMediaPlayer::MediaStatus m_mediaStatus = QMediaPlayer::NoMedia;
@@ -146,6 +149,7 @@ private:
QIODevice *m_stream = nullptr;
bool ownStream = false;
+ bool prerolling = false;
int m_volume = 100.;
bool m_muted = false;
double m_playbackRate = 1.;
@@ -166,9 +170,8 @@ private:
QGstPipeline playerPipeline;
QGstElement src;
QGstElement decoder;
- QGstElement audioInputSelector;
- QGstElement videoInputSelector;
- QGstElement subTitleInputSelector;
+ QGstElement inputSelector[3];
+
// QGstElement streamSynchronizer;
QGstElement audioQueue;
diff --git a/src/multimedia/platform/qplatformmediaplayer_p.h b/src/multimedia/platform/qplatformmediaplayer_p.h
index 9169d7c89..6015bc52e 100644
--- a/src/multimedia/platform/qplatformmediaplayer_p.h
+++ b/src/multimedia/platform/qplatformmediaplayer_p.h
@@ -106,7 +106,13 @@ public:
virtual void setVideoSurface(QAbstractVideoSurface *surface) = 0;
- virtual QMediaStreamsControl *mediaStreams() { return nullptr; }
+ // media streams
+ enum TrackType { VideoStream, AudioStream, SubtitleStream, NTrackTypes };
+
+ virtual int trackCount(TrackType) { return 0; };
+ virtual QMediaMetaData trackMetaData(TrackType /*type*/, int /*streamNumber*/) { return QMediaMetaData(); }
+ virtual int activeTrack(TrackType) { return -1; }
+ virtual void setActiveTrack(TrackType, int /*streamNumber*/) {}
Q_SIGNALS:
void audioRoleChanged(QAudio::Role role);
@@ -125,6 +131,8 @@ Q_SIGNALS:
void playbackRateChanged(qreal rate);
void error(int error, const QString &errorString);
void metaDataChanged();
+ void tracksChanged();
+ void activeTracksChanged();
protected:
explicit QPlatformMediaPlayer(QObject *parent = nullptr);
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index fef7951b5..ef264e296 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -101,6 +101,8 @@ public:
void setMedia(const QUrl &media, QIODevice *stream = nullptr);
+ QList<QMediaMetaData> streamMetaData(QPlatformMediaPlayer::TrackType s) const;
+
void _q_stateChanged(QMediaPlayer::State state);
void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status);
void _q_error(int error, const QString &errorString);
@@ -253,6 +255,18 @@ void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
qrcFile.swap(file); // Cleans up any previous file
}
+QList<QMediaMetaData> QMediaPlayerPrivate::streamMetaData(QPlatformMediaPlayer::TrackType s) const
+{
+ QList<QMediaMetaData> streams;
+ if (control) {
+ int count = control->trackCount(s);
+ for (int i = 0; i < count; ++i) {
+ streams.append(control->trackMetaData(s, i));
+ }
+ }
+ return streams;
+}
+
/*!
Construct a QMediaPlayer instance
parented to \a parent and with \a flags.
@@ -285,6 +299,8 @@ QMediaPlayer::QMediaPlayer(QObject *parent):
connect(d->control, &QPlatformMediaPlayer::playbackRateChanged, this, &QMediaPlayer::playbackRateChanged);
connect(d->control, &QPlatformMediaPlayer::bufferStatusChanged, this, &QMediaPlayer::bufferStatusChanged);
connect(d->control, &QPlatformMediaPlayer::metaDataChanged, this, &QMediaPlayer::metaDataChanged);
+ connect(d->control, &QPlatformMediaPlayer::tracksChanged, this, &QMediaPlayer::tracksChanged);
+ connect(d->control, &QPlatformMediaPlayer::activeTracksChanged, this, &QMediaPlayer::activeTracksChanged);
d->state = d->control->state();
d->status = d->control->mediaStatus();
@@ -686,6 +702,69 @@ QAudioDeviceInfo QMediaPlayer::audioOutput() const
return d->control->audioOutput();
}
+QList<QMediaMetaData> QMediaPlayer::audioTracks() const
+{
+ Q_D(const QMediaPlayer);
+ return d->streamMetaData(QPlatformMediaPlayer::AudioStream);
+}
+
+QList<QMediaMetaData> QMediaPlayer::videoTracks() const
+{
+ Q_D(const QMediaPlayer);
+ return d->streamMetaData(QPlatformMediaPlayer::VideoStream);
+}
+
+QList<QMediaMetaData> QMediaPlayer::subtitleTracks() const
+{
+ Q_D(const QMediaPlayer);
+ return d->streamMetaData(QPlatformMediaPlayer::SubtitleStream);
+}
+
+int QMediaPlayer::activeAudioTrack() const
+{
+ Q_D(const QMediaPlayer);
+ if (d->control)
+ return d->control->activeTrack(QPlatformMediaPlayer::AudioStream);
+ return 0;
+}
+
+int QMediaPlayer::activeVideoTrack() const
+{
+ Q_D(const QMediaPlayer);
+ if (d->control)
+ return d->control->activeTrack(QPlatformMediaPlayer::VideoStream);
+ return 0;
+}
+
+int QMediaPlayer::activeSubtitleTrack() const
+{
+ Q_D(const QMediaPlayer);
+ if (d->control)
+ return d->control->activeTrack(QPlatformMediaPlayer::SubtitleStream);
+ return 0;
+}
+
+void QMediaPlayer::setActiveAudioTrack(int index)
+{
+ Q_D(QMediaPlayer);
+ if (d->control)
+ d->control->setActiveTrack(QPlatformMediaPlayer::AudioStream, index);
+}
+
+void QMediaPlayer::setActiveVideoTrack(int index)
+{
+ Q_D(QMediaPlayer);
+ if (d->control)
+ d->control->setActiveTrack(QPlatformMediaPlayer::VideoStream, index);
+}
+
+void QMediaPlayer::setActiveSubtitleTrack(int index)
+{
+ Q_D(QMediaPlayer);
+ if (d->control)
+ d->control->setActiveTrack(QPlatformMediaPlayer::SubtitleStream, index);
+}
+
/*!
Attach a video \a output to the media player.
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index 6df346e50..58f5201ce 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -123,19 +123,17 @@ public:
bool setAudioOutput(const QAudioDeviceInfo &device);
QAudioDeviceInfo audioOutput() const;
-// using ContentStream = QVariantHash;
+ QList<QMediaMetaData> audioTracks() const;
+ QList<QMediaMetaData> videoTracks() const;
+ QList<QMediaMetaData> subtitleTracks() const;
-// QList<ContentStream> audioStreams() const;
-// QList<ContentStream> videoStreams() const;
-// QList<ContentStream> subtitleStreams() const;
+ int activeAudioTrack() const;
+ int activeVideoTrack() const;
+ int activeSubtitleTrack() const;
-// int audioStream() const;
-// int videoStream() const;
-// int subtitleStream() const;
-
-// void setAudioStream(int index) const;
-// void setVideoStream(int index) const;
-// void setSubtitleStream(int index) const;
+ void setActiveAudioTrack(int index);
+ void setActiveVideoTrack(int index);
+ void setActiveSubtitleTrack(int index);
void setVideoOutput(QObject *);
void setVideoOutput(QAbstractVideoSurface *surface);
@@ -212,6 +210,9 @@ Q_SIGNALS:
void metaDataChanged();
+ void tracksChanged();
+ void activeTracksChanged();
+
void error(QMediaPlayer::Error error);
private: