diff options
Diffstat (limited to 'src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp')
-rw-r--r-- | src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp | 147 |
1 files changed, 81 insertions, 66 deletions
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp index f1aa64a5a..ec0a679bd 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp @@ -116,11 +116,6 @@ float QGstreamerMediaPlayer::bufferProgress() const return m_bufferProgress/100.; } -bool QGstreamerMediaPlayer::isSeekable() const -{ - return true; -} - QMediaTimeRange QGstreamerMediaPlayer::availablePlaybackRanges() const { return QMediaTimeRange(); @@ -128,16 +123,13 @@ QMediaTimeRange QGstreamerMediaPlayer::availablePlaybackRanges() const qreal QGstreamerMediaPlayer::playbackRate() const { - return m_playbackRate; + return playerPipeline.playbackRate(); } void QGstreamerMediaPlayer::setPlaybackRate(qreal rate) { - if (rate == m_playbackRate) - return; - m_playbackRate = rate; - playerPipeline.seek(playerPipeline.position(), m_playbackRate); - emit playbackRateChanged(rate); + if (playerPipeline.setPlaybackRate(rate)) + playbackRateChanged(rate); } void QGstreamerMediaPlayer::setPosition(qint64 pos) @@ -146,7 +138,7 @@ void QGstreamerMediaPlayer::setPosition(qint64 pos) if (pos == currentPos) return; playerPipeline.finishStateChange(); - playerPipeline.seek(pos*1e6, m_playbackRate); + playerPipeline.setPosition(pos*1e6); qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << pos << playerPipeline.position()/1e6; if (mediaStatus() == QMediaPlayer::EndOfMedia) mediaStatusChanged(QMediaPlayer::LoadedMedia); @@ -160,12 +152,18 @@ void QGstreamerMediaPlayer::play() *playerPipeline.inStoppedState() = false; if (mediaStatus() == QMediaPlayer::EndOfMedia) { - playerPipeline.seek(0, m_playbackRate); + playerPipeline.setPosition(0); updatePosition(); } qCDebug(qLcMediaPlayer) << "play()."; int ret = playerPipeline.setState(GST_STATE_PLAYING); + if (m_requiresSeekOnPlay) { + // Flushing the pipeline is required to get track changes + // immediately, when they happen while paused. + playerPipeline.flush(); + m_requiresSeekOnPlay = false; + } if (ret == GST_STATE_CHANGE_FAILURE) qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the playing state."; if (mediaStatus() == QMediaPlayer::LoadedMedia) @@ -182,13 +180,13 @@ void QGstreamerMediaPlayer::pause() positionUpdateTimer.stop(); if (*playerPipeline.inStoppedState()) { *playerPipeline.inStoppedState() = false; - playerPipeline.seek(playerPipeline.position(), m_playbackRate); + playerPipeline.flush(); } int ret = playerPipeline.setState(GST_STATE_PAUSED); if (ret == GST_STATE_CHANGE_FAILURE) qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the paused state."; if (mediaStatus() == QMediaPlayer::EndOfMedia) { - playerPipeline.seek(0, m_playbackRate); + playerPipeline.setPosition(0); mediaStatusChanged(QMediaPlayer::BufferedMedia); } updatePosition(); @@ -210,7 +208,7 @@ void QGstreamerMediaPlayer::stopOrEOS(bool eos) if (!ret) qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the stopped state."; if (!eos) - playerPipeline.seek(0, m_playbackRate); + playerPipeline.setPosition(0); updatePosition(); emit stateChanged(QMediaPlayer::StoppedState); mediaStatusChanged(eos ? QMediaPlayer::EndOfMedia : QMediaPlayer::LoadedMedia); @@ -284,7 +282,7 @@ bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message) case GST_STATE_VOID_PENDING: case GST_STATE_NULL: case GST_STATE_READY: - setSeekable(false); + seekableChanged(false); break; case GST_STATE_PAUSED: { @@ -295,9 +293,6 @@ bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message) parseStreamsAndMetadata(); - if (!qFuzzyCompare(m_playbackRate, qreal(1.0))) - playerPipeline.seek(playerPipeline.position(), m_playbackRate); - emit tracksChanged(); mediaStatusChanged(QMediaPlayer::LoadedMedia); } @@ -393,26 +388,17 @@ void QGstreamerMediaPlayer::decoderPadAdded(const QGstElement &src, const QGstPa qCDebug(qLcMediaPlayer) << " " << caps.toString(); TrackType streamType = NTrackTypes; - QGstElement output; if (type.startsWith("video/x-raw")) { streamType = VideoStream; - output = gstVideoOutput->gstElement(); } else if (type.startsWith("audio/x-raw")) { streamType = AudioStream; - if (gstAudioOutput) - output = gstAudioOutput->gstElement(); } else if (type.startsWith("text/")) { streamType = SubtitleStream; } else { qCWarning(qLcMediaPlayer) << "Ignoring unknown media stream:" << pad.name() << type; return; } - if (!selectorIsConnected[streamType] && !output.isNull()) { - playerPipeline.add(output); - inputSelector[streamType].link(output); - output.setState(GST_STATE_PAUSED); - selectorIsConnected[streamType] = true; - } + connectOutput(streamType); QGstPad sinkPad = inputSelector[streamType].getRequestPad("sink_%u"); if (!pad.link(sinkPad)) @@ -453,38 +439,65 @@ void QGstreamerMediaPlayer::decoderPadRemoved(const QGstElement &src, const QGst Q_ASSERT(m_streams[streamType].indexOf(peer) != -1); m_streams[streamType].removeAll(peer); - if (m_streams[streamType].size() == 0) + if (m_streams[streamType].size() == 0) { removeOutput(TrackType(streamType)); + if (streamType == AudioStream) + audioAvailableChanged(false); + else if (streamType == VideoStream) + videoAvailableChanged(false); + } if (!prerolling) - emit tracksChanged(); + tracksChanged(); } void QGstreamerMediaPlayer::removeAllOutputs() { for (int i = 0; i < NTrackTypes; ++i) { removeOutput(TrackType(i)); - for (QGstPad pad : qAsConst(m_streams[i])) { + for (const QGstPad &pad : qAsConst(m_streams[i])) { inputSelector[i].releaseRequestPad(pad); } m_streams[i].clear(); } + audioAvailableChanged(false); + videoAvailableChanged(false); +} + +void QGstreamerMediaPlayer::connectOutput(TrackType t) +{ + if (selectorIsConnected[t]) + return; + + QGstElement e; + if (t == AudioStream) + e = gstAudioOutput->gstElement(); + else if (t == VideoStream) + e = gstVideoOutput->gstElement(); + if (!e.isNull()) { + qCDebug(qLcMediaPlayer) << "connecting output for track type" << t; + playerPipeline.add(e); + inputSelector[t].link(e); + e.setState(GST_STATE_PAUSED); + selectorIsConnected[t] = true; + } } void QGstreamerMediaPlayer::removeOutput(TrackType t) { - if (selectorIsConnected[t]) { - QGstElement e; - if (t == AudioStream) - e = gstAudioOutput->gstElement(); - else if (t == VideoStream) - e = gstVideoOutput->gstElement(); - if (!e.isNull()) { - qCDebug(qLcMediaPlayer) << "removing output for track type" << t; - e.setState(GST_STATE_NULL); - playerPipeline.remove(e); - selectorIsConnected[t] = false; - } + if (!selectorIsConnected[t]) + return; + + QGstElement e; + if (t == AudioStream) + e = gstAudioOutput->gstElement(); + else if (t == VideoStream) + e = gstVideoOutput->gstElement(); + if (!e.isNull()) { + qCDebug(qLcMediaPlayer) << "removing output for track type" << t; + e.setState(GST_STATE_NULL); + playerPipeline.remove(e); + selectorIsConnected[t] = false; } } @@ -496,6 +509,10 @@ void QGstreamerMediaPlayer::uridecodebinElementAddedCallback(GstElement */*uride if (G_OBJECT_TYPE(child) == that->decodebinType) { qCDebug(qLcMediaPlayer) << " -> setting post-stream-topology property"; c.set("post-stream-topology", true); + } else if (!qstrcmp(gst_element_get_name(child), "source")) { + GstBaseSrc *src = GST_BASE_SRC(child); + bool seekable = src && GST_BASE_SRC_GET_CLASS(src)->is_seekable(src); + that->seekableChanged(seekable); } } @@ -519,6 +536,7 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream) src = QGstElement(); decoder = QGstElement(); removeAllOutputs(); + seekableChanged(false); if (m_duration != 0) { m_duration = 0; @@ -546,6 +564,7 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream) src.link(decoder); m_appSrc->setup(m_stream); + seekableChanged(!stream->isSequential()); } else { // use uridecodebin decoder = QGstElement("uridecodebin", "uridecoder"); @@ -574,6 +593,7 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream) qCWarning(qLcMediaPlayer) << "Unable to set the pipeline to the paused state."; } + playerPipeline.setPosition(0); positionChanged(0); } @@ -581,8 +601,17 @@ void QGstreamerMediaPlayer::setAudioOutput(QPlatformAudioOutput *output) { if (gstAudioOutput == output) return; + playerPipeline.beginConfig(); + if (gstAudioOutput) { + removeOutput(AudioStream); + gstAudioOutput->setPipeline({}); + } gstAudioOutput = static_cast<QGstreamerAudioOutput *>(output); - // ### Connect it if we're already running! + if (gstAudioOutput) { + gstAudioOutput->setPipeline(playerPipeline); + connectOutput(AudioStream); + } + playerPipeline.endConfig(); } QMediaMetaData QGstreamerMediaPlayer::metaData() const @@ -595,15 +624,6 @@ void QGstreamerMediaPlayer::setVideoSink(QVideoSink *sink) gstVideoOutput->setVideoSink(sink); } -void QGstreamerMediaPlayer::setSeekable(bool seekable) -{ - qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << seekable; - if (seekable == m_seekable) - return; - m_seekable = seekable; - emit seekableChanged(m_seekable); -} - static QGstStructure endOfChain(const QGstStructure &s) { QGstStructure e = s; @@ -699,6 +719,8 @@ QMediaMetaData QGstreamerMediaPlayer::trackMetaData(QPlatformMediaPlayer::TrackT GstTagList *tagList; g_object_get(s.at(index).object(), "tags", &tagList, nullptr); + if (!tagList) + return {}; QMediaMetaData md = QGstreamerMetaData::fromGstTagList(tagList); return md; @@ -736,17 +758,10 @@ void QGstreamerMediaPlayer::setActiveTrack(QPlatformMediaPlayer::TrackType type, return; selector.set("active-pad", streams.at(index)); // seek to force an immediate change of the stream - playerPipeline.seek(playerPipeline.position(), m_playbackRate); -} - -bool QGstreamerMediaPlayer::isAudioAvailable() const -{ - return !m_streams[AudioStream].isEmpty(); -} - -bool QGstreamerMediaPlayer::isVideoAvailable() const -{ - return !m_streams[VideoStream].isEmpty(); + if (playerPipeline.state() == GST_STATE_PLAYING) + playerPipeline.flush(); + else + m_requiresSeekOnPlay = true; } QT_END_NAMESPACE |