summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Dyomin <artem.dyomin@qt.io>2023-11-08 13:34:47 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-11-08 20:01:07 +0000
commit9c401460f807923f429f9b4d118f24416fa85f43 (patch)
tree1b659f751c65a6ced4ea1b33f392b67a6847f122
parent7dc43a2d8f15b4d5e945198f0adb01cbbb2cce0a (diff)
Fix waiting for the end frame in the ffmpeg mediaplayer
The problem was in immediate handling of the ending frame after the last frame; we should wait for the last frame ending before finalization the rendering. Pick-to: 6.5 Change-Id: Ie5e30419678ac3a4d5c0d722d99beb8c197bcb46 Reviewed-by: Lars Knoll <lars@knoll.priv.no> Reviewed-by: Jøger Hansegård <joger.hansegard@qt.io> (cherry picked from commit 4b8077ed171bce50f5ba97caec2058745cbfc44f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp31
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h2
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4bin0 -> 1171 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp30
4 files changed, 54 insertions, 9 deletions
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp
index f3ab4699e..f5381a41c 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer.cpp
@@ -12,7 +12,8 @@ static Q_LOGGING_CATEGORY(qLcRenderer, "qt.multimedia.ffmpeg.renderer");
Renderer::Renderer(const TimeController &tc, const std::chrono::microseconds &seekPosTimeOffset)
: m_timeController(tc),
- m_lastPosition(tc.currentPosition()),
+ m_lastFrameEnd(tc.currentPosition()),
+ m_lastPosition(m_lastFrameEnd),
m_seekPos(tc.currentPosition(-seekPosTimeOffset))
{
}
@@ -119,17 +120,24 @@ float Renderer::playbackRate() const
int Renderer::timerInterval() const
{
- auto frame = !m_frames.empty() ? m_frames.front() : Frame();
- if (frame.isValid()) {
- using namespace std::chrono;
+ if (m_frames.empty())
+ return 0;
- const auto nextTime = m_explicitNextFrameTime
- ? *m_explicitNextFrameTime
- : m_timeController.timeFromPosition(frame.absolutePts());
+ auto calculateInterval = [](const TimePoint &nextTime) {
+ using namespace std::chrono;
const auto delay = nextTime - Clock::now();
return std::max(0, static_cast<int>(duration_cast<milliseconds>(delay).count()));
- }
+ };
+
+ if (m_explicitNextFrameTime)
+ return calculateInterval(*m_explicitNextFrameTime);
+
+ if (m_frames.front().isValid())
+ return calculateInterval(m_timeController.timeFromPosition(m_frames.front().absolutePts()));
+
+ if (m_lastFrameEnd > 0)
+ return calculateInterval(m_timeController.timeFromPosition(m_lastFrameEnd));
return 0;
}
@@ -163,7 +171,10 @@ void Renderer::doNextStep()
if (frame.isValid()) {
m_lastPosition.storeRelease(std::max(frame.absolutePts(), lastPosition()));
- m_seekPos.storeRelaxed(frame.absoluteEnd());
+
+ // TODO: get rid of m_lastFrameEnd or m_seekPos
+ m_lastFrameEnd = frame.absoluteEnd();
+ m_seekPos.storeRelaxed(m_lastFrameEnd);
const auto loopIndex = frame.loopOffset().index;
if (m_loopIndex < loopIndex) {
@@ -172,6 +183,8 @@ void Renderer::doNextStep()
}
emit frameProcessed(frame);
+ } else {
+ m_lastPosition.storeRelease(std::max(m_lastFrameEnd, lastPosition()));
}
} else {
m_explicitNextFrameTime = Clock::now() + result.recheckInterval;
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h
index 863ca60af..e8ee44d84 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegrenderer_p.h
@@ -104,8 +104,10 @@ private:
private:
TimeController m_timeController;
+ qint64 m_lastFrameEnd = 0;
QAtomicInteger<qint64> m_lastPosition = 0;
QAtomicInteger<qint64> m_seekPos = 0;
+
int m_loopIndex = 0;
QQueue<Frame> m_frames;
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4
new file mode 100644
index 000000000..db8e44a3f
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
index fec78f5a1..892efbe16 100644
--- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
+++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
@@ -110,6 +110,7 @@ private slots:
void play_doesNotEnterMediaLoadingState_whenResumingPlayingAfterStop();
void playAndSetSource_emitsExpectedSignalsAndStopsPlayback_whenSetSourceWasCalledWithEmptyUrl();
void play_createsFramesWithExpectedContentAndIncreasingFrameTime_whenPlayingRtspMediaStream();
+ void play_waitsForLastFrameEnd_whenPlayingVideoWithLongFrames();
void stop_entersStoppedState_whenPlayerWasPaused();
@@ -176,6 +177,7 @@ private:
QUrl m_localCompressedSoundFile;
QUrl m_localFileWithMetadata;
QUrl m_localVideoFile3ColorsWithSound;
+ QUrl m_oneRedFrameVideo;
const std::array<QRgb, 3> m_video3Colors = { { 0xFF0000, 0x00FF00, 0x0000FF } };
QString m_vlcCommand;
@@ -287,8 +289,12 @@ void tst_QMediaPlayerBackend::initTestCase()
mediaCandidates << "qrc:/testdata/nokia-tune.mp3";
mediaCandidates << "qrc:/testdata/nokia-tune.mkv";
m_localCompressedSoundFile = MediaFileSelector::selectMediaFile(mediaCandidates);
+
m_localFileWithMetadata = MediaFileSelector::selectMediaFile(QStringList() << "qrc:/testdata/nokia-tune.mp3");
+ m_oneRedFrameVideo =
+ MediaFileSelector::selectMediaFile(QStringList() << "qrc:/testdata/one_red_frame.mp4");
+
detectVlcCommand();
}
@@ -947,6 +953,30 @@ void tst_QMediaPlayerBackend::
QCOMPARE(errorSpy.size(), 0);
}
+void tst_QMediaPlayerBackend::play_waitsForLastFrameEnd_whenPlayingVideoWithLongFrames()
+{
+ m_fixture->player.setSource(m_oneRedFrameVideo);
+ m_fixture->player.play();
+
+ auto firstFrame = m_fixture->surface.waitForFrame();
+ QVERIFY(firstFrame.isValid());
+
+ QElapsedTimer timer;
+ timer.start();
+
+ auto endFrame = m_fixture->surface.waitForFrame();
+ QVERIFY(!endFrame.isValid());
+
+ const auto elapsed = timer.elapsed();
+
+ // 1000 is expected
+ QCOMPARE_GT(elapsed, 900);
+ QCOMPARE_LT(elapsed, 1400);
+
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(m_fixture->surface.m_totalFrames, 2);
+}
+
void tst_QMediaPlayerBackend::stop_entersStoppedState_whenPlayerWasPaused()
{
if (!isWavSupported())