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 /tests | |
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 'tests')
-rw-r--r-- | tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp | 164 |
1 files changed, 162 insertions, 2 deletions
diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp index 35c7e3f09..fb7d1066c 100644 --- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp +++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp @@ -45,9 +45,11 @@ public slots: private slots: void construction(); void loadInvalidMedia(); + void loadInvalidMediaWhilePlayingAndRestore(); void loadMedia(); void unloadMedia(); void loadMediaInLoadingState(); + void loadMediaWhilePlaying(); void playPauseStop(); void processEOS(); void deleteLaterAtEOS(); @@ -77,6 +79,8 @@ private slots: void infiniteLoops(); void seekOnLoops(); void changeLoopsOnTheFly(); + void changeVideoOutputNoFramesLost(); + void cleanSinkAndNoMoreFramesAfterStop(); void lazyLoadVideo(); void videoSinkSignals(); void nonAsciiFileName(); @@ -123,7 +127,7 @@ public: return spy.wait() ? spy.at(0).at(0).value<QVideoFrame>() : QVideoFrame{}; } -public Q_SLOTS: +private Q_SLOTS: void addVideoFrame(const QVideoFrame &frame) { // qDebug() << m_elapsedTimer.elapsed() << frame.startTime() << frame.endTime() << // frame.toImage().pixelColor(1, 1); @@ -150,6 +154,11 @@ private: bool m_storeFrames; }; +static void setVideoSinkAsyncFramesCounter(QVideoSink &sink, std::atomic_int &counter) +{ + QObject::connect(&sink, &QVideoSink::videoFrameChanged, [&counter]() { ++counter; }); +} + void tst_QMediaPlayerBackend::init() { } @@ -246,7 +255,7 @@ void tst_QMediaPlayerBackend::loadInvalidMedia() QSKIP("Sound format is not supported"); QAudioOutput output; - TestVideoSink surface; + TestVideoSink surface(false); QMediaPlayer player; QSignalSpy stateSpy(&player, &QMediaPlayer::playbackStateChanged); @@ -281,6 +290,49 @@ void tst_QMediaPlayerBackend::loadInvalidMedia() QCOMPARE(player.mediaStatus(), QMediaPlayer::InvalidMedia); } +void tst_QMediaPlayerBackend::loadInvalidMediaWhilePlayingAndRestore() +{ + QMediaPlayer player; + QAudioOutput output; + QVideoSink surface; + std::atomic_int framesCount = 0; + setVideoSinkAsyncFramesCounter(surface, framesCount); + + QSignalSpy stateSpy(&player, &QMediaPlayer::playbackStateChanged); + QSignalSpy errorSpy(&player, &QMediaPlayer::errorOccurred); + + player.setAudioOutput(&output); + player.setVideoOutput(&surface); + + player.setSource(localVideoFile3ColorsWithSound); + player.play(); + + QTRY_VERIFY(framesCount > 0); + QCOMPARE(errorSpy.size(), 0); + + player.setSource(QUrl("Some not existing media")); + const int savedFramesCount = framesCount; + + QCOMPARE(player.source(), QUrl("Some not existing media")); + + QTRY_COMPARE(player.playbackState(), QMediaPlayer::StoppedState); + QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::InvalidMedia); + QTRY_COMPARE(player.error(), QMediaPlayer::ResourceError); + + QVERIFY(!surface.videoFrame().isValid()); + + QCOMPARE(errorSpy.size(), 1); + + QTest::qWait(20); + QCOMPARE(framesCount, savedFramesCount); + + // restore playing + player.setSource(localVideoFile3ColorsWithSound); + player.play(); + QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia); + QCOMPARE(player.error(), QMediaPlayer::NoError); +} + void tst_QMediaPlayerBackend::loadMedia() { if (!isWavSupported()) @@ -389,6 +441,43 @@ void tst_QMediaPlayerBackend::loadMediaInLoadingState() QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadingMedia); } +void tst_QMediaPlayerBackend::loadMediaWhilePlaying() +{ + QMediaPlayer player; + QAudioOutput output; + TestVideoSink surface(false); + + player.setAudioOutput(&output); + player.setVideoOutput(&surface); + + player.setSource(localVideoFile3ColorsWithSound); + player.play(); + QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState); + QVERIFY(surface.waitForFrame().isValid()); + QVERIFY(player.hasAudio()); + QVERIFY(player.hasVideo()); + + QSignalSpy stateSpy(&player, &QMediaPlayer::playbackStateChanged); + QSignalSpy errorSpy(&player, &QMediaPlayer::errorChanged); + + player.setSource(localWavFile2); + QCOMPARE(player.source(), localWavFile2); + QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.size(), 1); + QCOMPARE(errorSpy.size(), 0); + QVERIFY(player.hasAudio()); + QVERIFY(!player.hasVideo()); + QVERIFY(!surface.videoFrame().isValid()); + + player.play(); + + player.setSource(localVideoFile2); + QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState); + QVERIFY(player.hasVideo()); + QVERIFY(!player.hasAudio()); + QCOMPARE(errorSpy.size(), 0); +} + void tst_QMediaPlayerBackend::playPauseStop() { if (!isWavSupported()) @@ -1858,6 +1947,77 @@ void tst_QMediaPlayerBackend::changeLoopsOnTheFly() QCOMPARE(intervals[1], std::make_pair(qint64(0), player.duration())); } +void tst_QMediaPlayerBackend::changeVideoOutputNoFramesLost() +{ + QVideoSink sinks[4]; + std::atomic_int framesCount[4] = { + 0, + }; + for (int i = 0; i < 4; ++i) + setVideoSinkAsyncFramesCounter(sinks[i], framesCount[i]); + + QMediaPlayer player; + + player.setPlaybackRate(10); + + player.setVideoOutput(&sinks[0]); + player.setSource(localVideoFile3ColorsWithSound); + player.play(); + QTRY_VERIFY(!player.isPlaying()); + + player.setPlaybackRate(4); + player.setVideoOutput(&sinks[1]); + player.play(); + + QTRY_VERIFY(framesCount[1] >= framesCount[0] / 4); + player.setVideoOutput(&sinks[2]); + const int savedFrameNumber1 = framesCount[1]; + + QTRY_VERIFY(framesCount[2] >= (framesCount[0] - savedFrameNumber1) / 2); + player.setVideoOutput(&sinks[3]); + const int savedFrameNumber2 = framesCount[2]; + + QTRY_VERIFY(!player.isPlaying()); + + // check if no frames sent to old sinks + QCOMPARE(framesCount[1], savedFrameNumber1); + QCOMPARE(framesCount[2], savedFrameNumber2); + + // no frames lost + QCOMPARE(framesCount[1] + framesCount[2] + framesCount[3], framesCount[0]); +} + +void tst_QMediaPlayerBackend::cleanSinkAndNoMoreFramesAfterStop() +{ + QVideoSink sink; + std::atomic_int framesCount = 0; + setVideoSinkAsyncFramesCounter(sink, framesCount); + QMediaPlayer player; + + player.setPlaybackRate(10); + player.setVideoOutput(&sink); + + player.setSource(localVideoFile3ColorsWithSound); + + // Run a few time to have more chances to detect race conditions + for (int i = 0; i < 8; ++i) { + player.play(); + QTRY_VERIFY(framesCount > 0); + + player.stop(); + + QVERIFY(!sink.videoFrame().isValid()); + + QCOMPARE_NE(framesCount, 0); + framesCount = 0; + + QTest::qWait(30); + + // check if nothing changed after short waiting + QCOMPARE(framesCount, 0); + } +} + void tst_QMediaPlayerBackend::lazyLoadVideo() { QQmlEngine engine; |