diff options
author | Artem Dyomin <artem.dyomin@qt.io> | 2023-05-02 16:07:32 +0200 |
---|---|---|
committer | Artem Dyomin <artem.dyomin@qt.io> | 2023-06-02 11:56:29 +0000 |
commit | 3d9cca86bfb59d6cfefad2b32d53268d3ad205bf (patch) | |
tree | 71d2e8d2ba631f7770b9f5b90af8d5991f11c351 /src | |
parent | 24c854fff9af00461b0920074b23d156e345a804 (diff) |
Handle QMediaPlayer outputs corner cases
- Clean-up the video sink frame after stop, QMediaPlayer deleting,
and after setting new media.
- ensure no frames lost if change QVideoSink
- ensure no frames sent after changing of outputs.
The patch fixes problems with tests on Android, summarizing of
the related commits:
codereview.qt-project.org/c/qt/qtmultimedia/+/472214
codereview.qt-project.org/c/qt/qtmultimedia/+/470890
codereview.qt-project.org/c/qt/qtmultimedia/+/472052
Users want to have flush mode customization as it was it Qt5.
It might be added in 6.6 afterwards.
Fixes: QTBUG-112173
Task-number: QTBUG-111912
Change-Id: I0e4d34de06fcf23adf8a5736cbff4119478e9baf
Reviewed-by: Lars Knoll <lars@knoll.priv.no>
Diffstat (limited to 'src')
9 files changed, 98 insertions, 8 deletions
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp index e44736c91..f1aa545eb 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp @@ -37,6 +37,11 @@ AudioRenderer::AudioRenderer(const TimeController &tc, QAudioOutput *output) } } +void AudioRenderer::setOutput(QAudioOutput *output) +{ + setOutputInternal(m_output, output, [this](QAudioOutput *) { onDeviceChanged(); }); +} + AudioRenderer::~AudioRenderer() { freeOutput(); diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h index b5aef8a71..594af6edb 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h @@ -35,6 +35,8 @@ class AudioRenderer : public Renderer public: AudioRenderer(const TimeController &tc, QAudioOutput *output); + void setOutput(QAudioOutput *output); + ~AudioRenderer() override; protected: diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h index e0ff9072f..784ab7891 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h @@ -77,6 +77,20 @@ protected: std::chrono::microseconds frameDelay(const Frame &frame) const; + template<typename Output, typename ChangeHandler> + void setOutputInternal(QPointer<Output> &actual, Output *desired, ChangeHandler &&changeHandler) + { + const auto connectionType = thread() == QThread::currentThread() + ? Qt::AutoConnection + : Qt::BlockingQueuedConnection; + auto doer = [desired, changeHandler, &actual]() { + const auto prev = std::exchange(actual, desired); + if (prev != desired) + changeHandler(prev); + }; + QMetaObject::invokeMethod(this, doer, connectionType); + } + private: void doNextStep() override; diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp index 4e86ed482..789c9b53b 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp @@ -15,6 +15,14 @@ SubtitleRenderer::SubtitleRenderer(const TimeController &tc, QVideoSink *sink) { } +void SubtitleRenderer::setOutput(QVideoSink *sink, bool cleanPrevSink) +{ + setOutputInternal(m_sink, sink, [cleanPrevSink](QVideoSink *prev) { + if (prev && cleanPrevSink) + prev->setSubtitleText({}); + }); +} + SubtitleRenderer::~SubtitleRenderer() { if (m_sink) diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h index 146269fc3..972e152b4 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h @@ -30,6 +30,8 @@ public: ~SubtitleRenderer() override; + void setOutput(QVideoSink *sink, bool cleanPrevSink = false); + protected: RenderingResult renderInternal(Frame frame) override; diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp index 72ae0881f..2ad591c30 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp @@ -14,13 +14,23 @@ VideoRenderer::VideoRenderer(const TimeController &tc, QVideoSink *sink) { } +void VideoRenderer::setOutput(QVideoSink *sink, bool cleanPrevSink) +{ + setOutputInternal(m_sink, sink, [cleanPrevSink](QVideoSink *prev) { + if (prev && cleanPrevSink) + prev->setVideoFrame({}); + }); +} + VideoRenderer::RenderingResult VideoRenderer::renderInternal(Frame frame) { - if (!frame.isValid()) + if (!m_sink) return {}; - if (!m_sink) + if (!frame.isValid()) { + m_sink->setVideoFrame({}); return {}; + } // qCDebug(qLcVideoRenderer) << "RHI:" << accel.isNull() << accel.rhi() << sink->rhi(); diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h index e604af9f8..a229df495 100644 --- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h @@ -28,6 +28,8 @@ class VideoRenderer : public Renderer public: VideoRenderer(const TimeController &tc, QVideoSink *sink); + void setOutput(QVideoSink *sink, bool cleanPrevSink = false); + protected: RenderingResult renderInternal(Frame frame) override; diff --git a/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine.cpp b/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine.cpp index c9c4f20f2..06215294d 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine.cpp +++ b/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine.cpp @@ -50,6 +50,8 @@ PlaybackEngine::PlaybackEngine() PlaybackEngine::~PlaybackEngine() { qCDebug(qLcPlaybackEngine) << "Delete PlaybackEngine"; + + finalizeOutputs(); forEachExistingObject([](auto &object) { object.reset(); }); deleteFreeThreads(); } @@ -114,8 +116,10 @@ void PlaybackEngine::setState(QMediaPlayer::PlaybackState state) { const auto prevState = std::exchange(m_state, state); - if (m_state == QMediaPlayer::StoppedState) + if (m_state == QMediaPlayer::StoppedState) { + finalizeOutputs(); finilizeTime(0); + } if (prevState == QMediaPlayer::StoppedState || m_state == QMediaPlayer::StoppedState) recreateObjects(); @@ -438,8 +442,7 @@ void PlaybackEngine::deleteFreeThreads() { bool PlaybackEngine::setMedia(const QUrl &media, QIODevice *stream) { - forEachExistingObject([](auto &object) { object.reset(); }); - deleteFreeThreads(); + stop(); m_codecs = {}; @@ -448,14 +451,21 @@ bool PlaybackEngine::setMedia(const QUrl &media, QIODevice *stream) return false; } - forceUpdate(); return true; } void PlaybackEngine::setVideoSink(QVideoSink *sink) { - if (std::exchange(m_videoSink, sink) != sink) + auto prev = std::exchange(m_videoSink, sink); + if (prev == sink) + return; + + updateActiveVideoOutput(sink); + + if (!sink || !prev) { + // might need some improvements forceUpdate(); + } } void PlaybackEngine::setAudioSink(QPlatformAudioOutput *output) { @@ -464,8 +474,16 @@ void PlaybackEngine::setAudioSink(QPlatformAudioOutput *output) { void PlaybackEngine::setAudioSink(QAudioOutput *output) { - if (std::exchange(m_audioOutput, output) != output) + auto prev = std::exchange(m_audioOutput, output); + if (prev == output) + return; + + updateActiveAudioOutput(output); + + if (!output || !prev) { + // might need some improvements forceUpdate(); + } } qint64 PlaybackEngine::currentPosition(bool topPos) const { @@ -515,6 +533,29 @@ void PlaybackEngine::finilizeTime(qint64 pos) m_timeController.sync(pos); m_currentLoopOffset = {}; } + +void PlaybackEngine::finalizeOutputs() +{ + updateActiveAudioOutput(nullptr); + updateActiveVideoOutput(nullptr, true); +} + +void PlaybackEngine::updateActiveAudioOutput(QAudioOutput *output) +{ + if (auto renderer = + qobject_cast<AudioRenderer *>(m_renderers[QPlatformMediaPlayer::AudioStream].get())) + renderer->setOutput(output); +} + +void PlaybackEngine::updateActiveVideoOutput(QVideoSink *sink, bool cleanOutput) +{ + if (auto renderer = qobject_cast<SubtitleRenderer *>( + m_renderers[QPlatformMediaPlayer::SubtitleStream].get())) + renderer->setOutput(sink, cleanOutput); + if (auto renderer = + qobject_cast<VideoRenderer *>(m_renderers[QPlatformMediaPlayer::VideoStream].get())) + renderer->setOutput(sink, cleanOutput); +} } QT_END_NAMESPACE diff --git a/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h b/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h index 4a61efa2f..2e39cf9cf 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h +++ b/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h @@ -129,6 +129,10 @@ protected: // objects managing virtual RendererPtr createRenderer(QPlatformMediaPlayer::TrackType trackType); + void updateActiveAudioOutput(QAudioOutput *output); + + void updateActiveVideoOutput(QVideoSink *sink, bool cleanOutput = false); + private: void createStreamAndRenderer(QPlatformMediaPlayer::TrackType trackType); @@ -168,6 +172,8 @@ private: void finilizeTime(qint64 pos); + void finalizeOutputs(); + private: TimeController m_timeController; |