summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorArtem Dyomin <artem.dyomin@qt.io>2023-05-02 16:07:32 +0200
committerArtem Dyomin <artem.dyomin@qt.io>2023-06-02 11:56:29 +0000
commit3d9cca86bfb59d6cfefad2b32d53268d3ad205bf (patch)
tree71d2e8d2ba631f7770b9f5b90af8d5991f11c351 /src
parent24c854fff9af00461b0920074b23d156e345a804 (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')
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer.cpp5
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegaudiorenderer_p.h2
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h14
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer.cpp8
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegsubtitlerenderer_p.h2
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer.cpp14
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegvideorenderer_p.h2
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegplaybackengine.cpp53
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h6
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;