diff options
author | Lars Knoll <lars.knoll@qt.io> | 2021-02-17 18:17:06 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2021-03-05 12:32:45 +0000 |
commit | a1f9b691c7960eefed6118b79b66f096094d75b2 (patch) | |
tree | 2047f79ff778dd5a7c1b0162e69f29c63a3ac89a | |
parent | f5ae5377805c3541fa19fe6c8001113f36f86bc4 (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.cpp | 53 | ||||
-rw-r--r-- | examples/multimediawidgets/player/player.h | 9 | ||||
-rw-r--r-- | src/multimedia/platform/gstreamer/common/qgst_p.h | 3 | ||||
-rw-r--r-- | src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp | 117 | ||||
-rw-r--r-- | src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h | 17 | ||||
-rw-r--r-- | src/multimedia/platform/qplatformmediaplayer_p.h | 10 | ||||
-rw-r--r-- | src/multimedia/playback/qmediaplayer.cpp | 79 | ||||
-rw-r--r-- | src/multimedia/playback/qmediaplayer.h | 23 |
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: |