Android: fix some problems with the media player.

- Correctly emit positionChanged signal. One of the problems with
  this was that QMediaPlayer automatically sends periodic
  position updates while playing a media. There's no need to have
  the same logic in the backend.
- Seeking after reaching the end of the media now correctly works

Auto tests included.

Change-Id: I6d5ecbae6e05f94a8aac1a0834cf57427adf219b
Reviewed-by: Christian Stromme <christian.stromme@digia.com>
This commit is contained in:
Yoann Lopes
2014-09-19 09:53:53 +02:00
parent 5c30ed55ef
commit ec24592186
4 changed files with 294 additions and 103 deletions

View File

@@ -83,23 +83,6 @@ public class QtAndroidMediaPlayer
private volatile int mState = State.Uninitialized; private volatile int mState = State.Uninitialized;
private class ProgressWatcher
implements Runnable
{
@Override
public void run()
{
try {
while ((mState & (State.Started)) != 0) {
onProgressUpdateNative(getCurrentPosition(), mID);
Thread.sleep(1000);
}
} catch (final InterruptedException e) {
// Ignore
}
}
}
/** /**
* MediaPlayer OnErrorListener * MediaPlayer OnErrorListener
*/ */
@@ -257,8 +240,6 @@ public class QtAndroidMediaPlayer
try { try {
mMediaPlayer.start(); mMediaPlayer.start();
setState(State.Started); setState(State.Started);
Thread progressThread = new Thread(new ProgressWatcher());
progressThread.start();
} catch (final IllegalStateException e) { } catch (final IllegalStateException e) {
Log.d(TAG, "" + e.getMessage()); Log.d(TAG, "" + e.getMessage());
} }
@@ -309,7 +290,6 @@ public class QtAndroidMediaPlayer
try { try {
mMediaPlayer.seekTo(msec); mMediaPlayer.seekTo(msec);
onProgressUpdateNative(msec, mID);
} catch (final IllegalStateException e) { } catch (final IllegalStateException e) {
Log.d(TAG, "" + e.getMessage()); Log.d(TAG, "" + e.getMessage());
} }

View File

@@ -86,6 +86,7 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent)
mPendingSetMedia(false), mPendingSetMedia(false),
mPendingVolume(-1), mPendingVolume(-1),
mPendingMute(-1), mPendingMute(-1),
mReloadingMedia(false),
mActiveStateChangeNotifiers(0) mActiveStateChangeNotifiers(0)
{ {
connect(mMediaPlayer,SIGNAL(bufferingChanged(qint32)), connect(mMediaPlayer,SIGNAL(bufferingChanged(qint32)),
@@ -138,17 +139,14 @@ qint64 QAndroidMediaPlayerControl::position() const
if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia) if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia)
return duration(); return duration();
if ((mState & (AndroidMediaPlayer::Idle if ((mState & (AndroidMediaPlayer::Prepared
| AndroidMediaPlayer::Initialized
| AndroidMediaPlayer::Prepared
| AndroidMediaPlayer::Started | AndroidMediaPlayer::Started
| AndroidMediaPlayer::Paused | AndroidMediaPlayer::Paused
| AndroidMediaPlayer::Stopped | AndroidMediaPlayer::PlaybackCompleted))) {
| AndroidMediaPlayer::PlaybackCompleted)) == 0) { return mMediaPlayer->getCurrentPosition();
return (mPendingPosition == -1) ? 0 : mPendingPosition;
} }
return (mCurrentState == QMediaPlayer::StoppedState) ? 0 : mMediaPlayer->getCurrentPosition(); return (mPendingPosition == -1) ? 0 : mPendingPosition;
} }
void QAndroidMediaPlayerControl::setPosition(qint64 position) void QAndroidMediaPlayerControl::setPosition(qint64 position)
@@ -158,26 +156,25 @@ void QAndroidMediaPlayerControl::setPosition(qint64 position)
const int seekPosition = (position > INT_MAX) ? INT_MAX : position; const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
if ((mState & (AndroidMediaPlayer::Prepared if (seekPosition == this->position())
| AndroidMediaPlayer::Started
| AndroidMediaPlayer::Paused
| AndroidMediaPlayer::PlaybackCompleted)) == 0) {
if (mPendingPosition != seekPosition) {
mPendingPosition = seekPosition;
Q_EMIT positionChanged(seekPosition);
}
return; return;
}
StateChangeNotifier notifier(this); StateChangeNotifier notifier(this);
if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia) if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia)
setMediaStatus(QMediaPlayer::LoadedMedia); setMediaStatus(QMediaPlayer::LoadedMedia);
mMediaPlayer->seekTo(seekPosition); if ((mState & (AndroidMediaPlayer::Prepared
| AndroidMediaPlayer::Started
| AndroidMediaPlayer::Paused
| AndroidMediaPlayer::PlaybackCompleted)) == 0) {
mPendingPosition = seekPosition;
} else {
mMediaPlayer->seekTo(seekPosition);
if (mPendingPosition != -1) { if (mPendingPosition != -1) {
mPendingPosition = -1; mPendingPosition = -1;
}
} }
Q_EMIT positionChanged(seekPosition); Q_EMIT positionChanged(seekPosition);
@@ -310,9 +307,9 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
{ {
StateChangeNotifier notifier(this); StateChangeNotifier notifier(this);
const bool reloading = (mMediaContent == mediaContent); mReloadingMedia = (mMediaContent == mediaContent);
if (!reloading) { if (!mReloadingMedia) {
mMediaContent = mediaContent; mMediaContent = mediaContent;
mMediaStream = stream; mMediaStream = stream;
} }
@@ -321,43 +318,45 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
if ((mState & (AndroidMediaPlayer::Idle | AndroidMediaPlayer::Uninitialized)) == 0) if ((mState & (AndroidMediaPlayer::Idle | AndroidMediaPlayer::Uninitialized)) == 0)
mMediaPlayer->release(); mMediaPlayer->release();
QString mediaPath;
if (mediaContent.isNull()) { if (mediaContent.isNull()) {
setMediaStatus(QMediaPlayer::NoMedia); setMediaStatus(QMediaPlayer::NoMedia);
return;
}
if (mVideoOutput && !mVideoOutput->isReady()) {
// if a video output is set but the video texture is not ready, delay loading the media
// since it can cause problems on some hardware
mPendingSetMedia = true;
return;
}
const QUrl url = mediaContent.canonicalUrl();
QString mediaPath;
if (url.scheme() == QLatin1String("qrc")) {
const QString path = url.toString().mid(3);
mTempFile.reset(QTemporaryFile::createNativeFile(path));
if (!mTempFile.isNull())
mediaPath = QStringLiteral("file://") + mTempFile->fileName();
} else { } else {
mediaPath = url.toString(); if (mVideoOutput && !mVideoOutput->isReady()) {
// if a video output is set but the video texture is not ready, delay loading the media
// since it can cause problems on some hardware
mPendingSetMedia = true;
return;
}
const QUrl url = mediaContent.canonicalUrl();
if (url.scheme() == QLatin1String("qrc")) {
const QString path = url.toString().mid(3);
mTempFile.reset(QTemporaryFile::createNativeFile(path));
if (!mTempFile.isNull())
mediaPath = QStringLiteral("file://") + mTempFile->fileName();
} else {
mediaPath = url.toString();
}
if (mVideoSize.isValid() && mVideoOutput)
mVideoOutput->setVideoSize(mVideoSize);
if ((mMediaPlayer->display() == 0) && mVideoOutput)
mMediaPlayer->setDisplay(mVideoOutput->surfaceTexture());
mMediaPlayer->setDataSource(mediaPath);
mMediaPlayer->prepareAsync();
} }
if (mVideoSize.isValid() && mVideoOutput) if (!mReloadingMedia) {
mVideoOutput->setVideoSize(mVideoSize);
if ((mMediaPlayer->display() == 0) && mVideoOutput)
mMediaPlayer->setDisplay(mVideoOutput->surfaceTexture());
mMediaPlayer->setDataSource(mediaPath);
mMediaPlayer->prepareAsync();
if (!reloading) {
Q_EMIT mediaChanged(mMediaContent); Q_EMIT mediaChanged(mMediaContent);
Q_EMIT actualMediaLocationChanged(mediaPath); Q_EMIT actualMediaLocationChanged(mediaPath);
} }
resetBufferingProgress(); resetBufferingProgress();
mReloadingMedia = false;
} }
void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput) void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
@@ -567,7 +566,8 @@ void QAndroidMediaPlayerControl::onStateChanged(qint32 state)
case AndroidMediaPlayer::Initialized: case AndroidMediaPlayer::Initialized:
break; break;
case AndroidMediaPlayer::Preparing: case AndroidMediaPlayer::Preparing:
setMediaStatus(QMediaPlayer::LoadingMedia); if (!mReloadingMedia)
setMediaStatus(QMediaPlayer::LoadingMedia);
break; break;
case AndroidMediaPlayer::Prepared: case AndroidMediaPlayer::Prepared:
setMediaStatus(QMediaPlayer::LoadedMedia); setMediaStatus(QMediaPlayer::LoadedMedia);
@@ -588,6 +588,7 @@ void QAndroidMediaPlayerControl::onStateChanged(qint32 state)
} else { } else {
setMediaStatus(QMediaPlayer::BufferedMedia); setMediaStatus(QMediaPlayer::BufferedMedia);
} }
Q_EMIT positionChanged(position());
break; break;
case AndroidMediaPlayer::Paused: case AndroidMediaPlayer::Paused:
setState(QMediaPlayer::PausedState); setState(QMediaPlayer::PausedState);
@@ -596,27 +597,32 @@ void QAndroidMediaPlayerControl::onStateChanged(qint32 state)
setState(QMediaPlayer::StoppedState); setState(QMediaPlayer::StoppedState);
setMediaStatus(QMediaPlayer::UnknownMediaStatus); setMediaStatus(QMediaPlayer::UnknownMediaStatus);
mMediaPlayer->release(); mMediaPlayer->release();
Q_EMIT positionChanged(0);
break; break;
case AndroidMediaPlayer::Stopped: case AndroidMediaPlayer::Stopped:
setState(QMediaPlayer::StoppedState); setState(QMediaPlayer::StoppedState);
setMediaStatus(QMediaPlayer::LoadedMedia); setMediaStatus(QMediaPlayer::LoadedMedia);
setPosition(0); Q_EMIT positionChanged(0);
break; break;
case AndroidMediaPlayer::PlaybackCompleted: case AndroidMediaPlayer::PlaybackCompleted:
setState(QMediaPlayer::StoppedState); setState(QMediaPlayer::StoppedState);
setPosition(0);
setMediaStatus(QMediaPlayer::EndOfMedia); setMediaStatus(QMediaPlayer::EndOfMedia);
break; break;
case AndroidMediaPlayer::Uninitialized: case AndroidMediaPlayer::Uninitialized:
// reset some properties // reset some properties (unless we reload the same media)
resetBufferingProgress(); if (!mReloadingMedia) {
mPendingPosition = -1; resetBufferingProgress();
mPendingSetMedia = false; mPendingPosition = -1;
mPendingState = -1; mPendingSetMedia = false;
mPendingState = -1;
setAudioAvailable(false); Q_EMIT durationChanged(0);
setVideoAvailable(false); Q_EMIT positionChanged(0);
setSeekable(true);
setAudioAvailable(false);
setVideoAvailable(false);
setSeekable(true);
}
break; break;
default: default:
break; break;
@@ -655,13 +661,13 @@ void QAndroidMediaPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status
if (mCurrentMediaStatus == status) if (mCurrentMediaStatus == status)
return; return;
mCurrentMediaStatus = status;
if (status == QMediaPlayer::NoMedia || status == QMediaPlayer::InvalidMedia) if (status == QMediaPlayer::NoMedia || status == QMediaPlayer::InvalidMedia)
Q_EMIT durationChanged(0); Q_EMIT durationChanged(0);
if (status == QMediaPlayer::EndOfMedia) if (status == QMediaPlayer::EndOfMedia)
Q_EMIT durationChanged(duration()); Q_EMIT positionChanged(position());
mCurrentMediaStatus = status;
updateBufferStatus(); updateBufferStatus();
} }

View File

@@ -111,6 +111,7 @@ private:
bool mPendingSetMedia; bool mPendingSetMedia;
int mPendingVolume; int mPendingVolume;
int mPendingMute; int mPendingMute;
bool mReloadingMedia;
QScopedPointer<QTemporaryFile> mTempFile; QScopedPointer<QTemporaryFile> mTempFile;
int mActiveStateChangeNotifiers; int mActiveStateChangeNotifiers;

View File

@@ -71,6 +71,7 @@ private slots:
void volumeAcrossFiles(); void volumeAcrossFiles();
void initialVolume(); void initialVolume();
void seekPauseSeek(); void seekPauseSeek();
void seekInStoppedState();
void subsequentPlayback(); void subsequentPlayback();
void probes(); void probes();
void playlist(); void playlist();
@@ -79,10 +80,11 @@ private slots:
private: private:
QMediaContent selectVideoFile(const QStringList& mediaCandidates); QMediaContent selectVideoFile(const QStringList& mediaCandidates);
QMediaContent selectSoundFile(const QStringList& mediaCandidates); QMediaContent selectMediaFile(const QStringList& mediaCandidates);
//one second local wav file //one second local wav file
QMediaContent localWavFile; QMediaContent localWavFile;
QMediaContent localWavFile2;
QMediaContent localVideoFile; QMediaContent localVideoFile;
QMediaContent localCompressedSoundFile; QMediaContent localCompressedSoundFile;
@@ -169,17 +171,17 @@ QMediaContent tst_QMediaPlayerBackend::selectVideoFile(const QStringList& mediaC
return QMediaContent(); return QMediaContent();
} }
QMediaContent tst_QMediaPlayerBackend::selectSoundFile(const QStringList& mediaCandidates) QMediaContent tst_QMediaPlayerBackend::selectMediaFile(const QStringList& mediaCandidates)
{ {
QMediaPlayer player; QMediaPlayer player;
QSignalSpy errorSpy(&player, SIGNAL(error(QMediaPlayer::Error))); QSignalSpy errorSpy(&player, SIGNAL(error(QMediaPlayer::Error)));
foreach (QString s, mediaCandidates) { foreach (QString s, mediaCandidates) {
QFileInfo soundFile(s); QFileInfo mediaFile(s);
if (!soundFile.exists()) if (!mediaFile.exists())
continue; continue;
QMediaContent media = QMediaContent(QUrl::fromLocalFile(soundFile.absoluteFilePath())); QMediaContent media = QMediaContent(QUrl::fromLocalFile(mediaFile.absoluteFilePath()));
player.setMedia(media); player.setMedia(media);
player.play(); player.play();
@@ -205,17 +207,24 @@ void tst_QMediaPlayerBackend::initTestCase()
localWavFile = QMediaContent(QUrl::fromLocalFile(wavFile.absoluteFilePath())); localWavFile = QMediaContent(QUrl::fromLocalFile(wavFile.absoluteFilePath()));
const QString testFileName2 = QFINDTESTDATA("testdata/_test.wav");
QFileInfo wavFile2(testFileName2);
QVERIFY(wavFile2.exists());
localWavFile2 = QMediaContent(QUrl::fromLocalFile(wavFile2.absoluteFilePath()));
qRegisterMetaType<QMediaContent>(); qRegisterMetaType<QMediaContent>();
QStringList mediaCandidates; QStringList mediaCandidates;
mediaCandidates << QFINDTESTDATA("testdata/colors.ogv"); mediaCandidates << QFINDTESTDATA("testdata/colors.ogv");
mediaCandidates << QFINDTESTDATA("testdata/colors.mp4"); mediaCandidates << QFINDTESTDATA("testdata/colors.mp4");
localVideoFile = selectVideoFile(mediaCandidates); localVideoFile = selectMediaFile(mediaCandidates);
mediaCandidates.clear(); mediaCandidates.clear();
mediaCandidates << QFINDTESTDATA("testdata/nokia-tune.mkv"); mediaCandidates << QFINDTESTDATA("testdata/nokia-tune.mkv");
mediaCandidates << QFINDTESTDATA("testdata/nokia-tune.mp3"); mediaCandidates << QFINDTESTDATA("testdata/nokia-tune.mp3");
localCompressedSoundFile = selectSoundFile(mediaCandidates); localCompressedSoundFile = selectMediaFile(mediaCandidates);
qgetenv("QT_TEST_CI").toInt(&m_inCISystem,10); qgetenv("QT_TEST_CI").toInt(&m_inCISystem,10);
} }
@@ -239,6 +248,7 @@ void tst_QMediaPlayerBackend::loadMedia()
QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State)));
QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
QSignalSpy mediaSpy(&player, SIGNAL(mediaChanged(QMediaContent))); QSignalSpy mediaSpy(&player, SIGNAL(mediaChanged(QMediaContent)));
QSignalSpy currentMediaSpy(&player, SIGNAL(currentMediaChanged(QMediaContent)));
player.setMedia(localWavFile); player.setMedia(localWavFile);
@@ -247,11 +257,13 @@ void tst_QMediaPlayerBackend::loadMedia()
QVERIFY(player.mediaStatus() != QMediaPlayer::NoMedia); QVERIFY(player.mediaStatus() != QMediaPlayer::NoMedia);
QVERIFY(player.mediaStatus() != QMediaPlayer::InvalidMedia); QVERIFY(player.mediaStatus() != QMediaPlayer::InvalidMedia);
QVERIFY(player.media() == localWavFile); QVERIFY(player.media() == localWavFile);
QVERIFY(player.currentMedia() == localWavFile);
QCOMPARE(stateSpy.count(), 0); QCOMPARE(stateSpy.count(), 0);
QVERIFY(statusSpy.count() > 0); QVERIFY(statusSpy.count() > 0);
QCOMPARE(mediaSpy.count(), 1); QCOMPARE(mediaSpy.count(), 1);
QCOMPARE(mediaSpy.last()[0].value<QMediaContent>(), localWavFile); QCOMPARE(mediaSpy.last()[0].value<QMediaContent>(), localWavFile);
QCOMPARE(currentMediaSpy.last()[0].value<QMediaContent>(), localWavFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia); QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
@@ -267,6 +279,7 @@ void tst_QMediaPlayerBackend::unloadMedia()
QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State)));
QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
QSignalSpy mediaSpy(&player, SIGNAL(mediaChanged(QMediaContent))); QSignalSpy mediaSpy(&player, SIGNAL(mediaChanged(QMediaContent)));
QSignalSpy currentMediaSpy(&player, SIGNAL(currentMediaChanged(QMediaContent)));
QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64))); QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64)));
QSignalSpy durationSpy(&player, SIGNAL(positionChanged(qint64))); QSignalSpy durationSpy(&player, SIGNAL(positionChanged(qint64)));
@@ -285,6 +298,7 @@ void tst_QMediaPlayerBackend::unloadMedia()
stateSpy.clear(); stateSpy.clear();
statusSpy.clear(); statusSpy.clear();
mediaSpy.clear(); mediaSpy.clear();
currentMediaSpy.clear();
positionSpy.clear(); positionSpy.clear();
durationSpy.clear(); durationSpy.clear();
@@ -295,10 +309,12 @@ void tst_QMediaPlayerBackend::unloadMedia()
QCOMPARE(player.state(), QMediaPlayer::StoppedState); QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia); QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia);
QCOMPARE(player.media(), QMediaContent()); QCOMPARE(player.media(), QMediaContent());
QCOMPARE(player.currentMedia(), QMediaContent());
QVERIFY(!stateSpy.isEmpty()); QVERIFY(!stateSpy.isEmpty());
QVERIFY(!statusSpy.isEmpty()); QVERIFY(!statusSpy.isEmpty());
QVERIFY(!mediaSpy.isEmpty()); QVERIFY(!mediaSpy.isEmpty());
QVERIFY(!currentMediaSpy.isEmpty());
QVERIFY(!positionSpy.isEmpty()); QVERIFY(!positionSpy.isEmpty());
} }
@@ -327,7 +343,7 @@ void tst_QMediaPlayerBackend::playPauseStop()
QTRY_VERIFY(statusSpy.count() > 0 && QTRY_VERIFY(statusSpy.count() > 0 &&
statusSpy.last()[0].value<QMediaPlayer::MediaStatus>() == QMediaPlayer::BufferedMedia); statusSpy.last()[0].value<QMediaPlayer::MediaStatus>() == QMediaPlayer::BufferedMedia);
QTRY_VERIFY(player.position() > 0); QTRY_VERIFY(player.position() > 100);
QVERIFY(player.duration() > 0); QVERIFY(player.duration() > 0);
QVERIFY(positionSpy.count() > 0); QVERIFY(positionSpy.count() > 0);
QVERIFY(positionSpy.last()[0].value<qint64>() > 0); QVERIFY(positionSpy.last()[0].value<qint64>() > 0);
@@ -361,6 +377,63 @@ void tst_QMediaPlayerBackend::playPauseStop()
QCOMPARE(player.position(), qint64(0)); QCOMPARE(player.position(), qint64(0));
QCOMPARE(positionSpy.last()[0].value<qint64>(), qint64(0)); QCOMPARE(positionSpy.last()[0].value<qint64>(), qint64(0));
QVERIFY(player.duration() > 0); QVERIFY(player.duration() > 0);
stateSpy.clear();
statusSpy.clear();
positionSpy.clear();
player.play();
QCOMPARE(player.state(), QMediaPlayer::PlayingState);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
QCOMPARE(stateSpy.count(), 1);
QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::State>(), QMediaPlayer::PlayingState);
QCOMPARE(statusSpy.count(), 1); // Should not go through Loading again when play -> stop -> play
QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::BufferedMedia);
player.stop();
stateSpy.clear();
statusSpy.clear();
positionSpy.clear();
player.setMedia(localWavFile2);
QTRY_VERIFY(statusSpy.count() > 0);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::LoadedMedia);
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 0);
player.play();
QTRY_VERIFY(player.position() > 100);
player.setMedia(localWavFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::LoadedMedia);
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::State>(), QMediaPlayer::StoppedState);
QCOMPARE(player.position(), 0);
QCOMPARE(positionSpy.last()[0].value<qint64>(), 0);
stateSpy.clear();
statusSpy.clear();
positionSpy.clear();
player.play();
QTRY_VERIFY(player.position() > 100);
player.setMedia(QMediaContent());
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::NoMedia);
QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::NoMedia);
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::State>(), QMediaPlayer::StoppedState);
QCOMPARE(player.position(), 0);
QCOMPARE(positionSpy.last()[0].value<qint64>(), 0);
QCOMPARE(player.duration(), 0);
} }
@@ -383,17 +456,25 @@ void tst_QMediaPlayerBackend::processEOS()
QVERIFY(statusSpy.count() > 0); QVERIFY(statusSpy.count() > 0);
QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::EndOfMedia); QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::EndOfMedia);
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 2);
QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::State>(), QMediaPlayer::StoppedState);
//at EOS the position stays at the end of file //at EOS the position stays at the end of file
QVERIFY(player.position() > 900); QCOMPARE(player.position(), player.duration());
QVERIFY(positionSpy.count() > 0);
QCOMPARE(positionSpy.last()[0].value<qint64>(), player.duration());
stateSpy.clear(); stateSpy.clear();
statusSpy.clear(); statusSpy.clear();
positionSpy.clear();
player.play(); player.play();
//position is reset to start //position is reset to start
QTRY_VERIFY(player.position() < 100); QTRY_VERIFY(player.position() < 100);
QVERIFY(positionSpy.count() > 0);
QCOMPARE(positionSpy.first()[0].value<qint64>(), 0);
QCOMPARE(player.state(), QMediaPlayer::PlayingState); QCOMPARE(player.state(), QMediaPlayer::PlayingState);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia); QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
@@ -406,13 +487,16 @@ void tst_QMediaPlayerBackend::processEOS()
player.setPosition(900); player.setPosition(900);
//wait up to 5 seconds for EOS //wait up to 5 seconds for EOS
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia); QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
QVERIFY(statusSpy.count() > 0);
QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::EndOfMedia);
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 2);
QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::State>(), QMediaPlayer::StoppedState);
//ensure the positionChanged() signal is emitted
QVERIFY(positionSpy.count() > 0);
QCOMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
//position stays at the end of file //position stays at the end of file
QVERIFY(player.position() > 900); QCOMPARE(player.position(), player.duration());
QVERIFY(positionSpy.count() > 0);
QCOMPARE(positionSpy.last()[0].value<qint64>(), player.duration());
//after setPosition EndOfMedia status should be reset to Loaded //after setPosition EndOfMedia status should be reset to Loaded
stateSpy.clear(); stateSpy.clear();
@@ -608,7 +692,7 @@ void tst_QMediaPlayerBackend::initialVolume()
void tst_QMediaPlayerBackend::seekPauseSeek() void tst_QMediaPlayerBackend::seekPauseSeek()
{ {
if (localVideoFile.isNull()) if (localVideoFile.isNull())
QSKIP("Video format is not supported"); QSKIP("No supported video file");
QMediaPlayer player; QMediaPlayer player;
@@ -674,6 +758,125 @@ void tst_QMediaPlayerBackend::seekPauseSeek()
} }
} }
void tst_QMediaPlayerBackend::seekInStoppedState()
{
if (localVideoFile.isNull())
QSKIP("No supported video file");
QMediaPlayer player;
player.setNotifyInterval(500);
QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State)));
QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64)));
player.setMedia(localVideoFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(player.position(), 0);
QVERIFY(player.isSeekable());
stateSpy.clear();
positionSpy.clear();
qint64 position = 5000;
player.setPosition(position);
QTRY_VERIFY(qAbs(player.position() - position) < qint64(500));
QCOMPARE(positionSpy.count(), 1);
QVERIFY(qAbs(positionSpy.last()[0].value<qint64>() - position) < qint64(500));
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 0);
QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
positionSpy.clear();
player.play();
QCOMPARE(player.state(), QMediaPlayer::PlayingState);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
QVERIFY(qAbs(player.position() - position) < qint64(500));
QTest::qWait(2000);
// Check that it never played from the beginning
QVERIFY(player.position() > (position - 500));
for (int i = 0; i < positionSpy.count(); ++i)
QVERIFY(positionSpy.at(i)[0].value<qint64>() > (position - 500));
// ------
// Same tests but after play() --> stop()
player.stop();
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
QCOMPARE(player.position(), 0);
stateSpy.clear();
positionSpy.clear();
player.setPosition(position);
QTRY_VERIFY(qAbs(player.position() - position) < qint64(500));
QCOMPARE(positionSpy.count(), 1);
QVERIFY(qAbs(positionSpy.last()[0].value<qint64>() - position) < qint64(500));
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 0);
QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
positionSpy.clear();
player.play();
QCOMPARE(player.state(), QMediaPlayer::PlayingState);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
QVERIFY(qAbs(player.position() - position) < qint64(500));
QTest::qWait(2000);
// Check that it never played from the beginning
QVERIFY(player.position() > (position - 500));
for (int i = 0; i < positionSpy.count(); ++i)
QVERIFY(positionSpy.at(i)[0].value<qint64>() > (position - 500));
// ------
// Same tests but after reaching the end of the media
player.setPosition(player.duration() - 500);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(player.position(), player.duration());
stateSpy.clear();
positionSpy.clear();
player.setPosition(position);
QTRY_VERIFY(qAbs(player.position() - position) < qint64(500));
QCOMPARE(positionSpy.count(), 1);
QVERIFY(qAbs(positionSpy.last()[0].value<qint64>() - position) < qint64(500));
QCOMPARE(player.state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 0);
QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
positionSpy.clear();
player.play();
QCOMPARE(player.state(), QMediaPlayer::PlayingState);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
QVERIFY(qAbs(player.position() - position) < qint64(500));
QTest::qWait(2000);
// Check that it never played from the beginning
QVERIFY(player.position() > (position - 500));
for (int i = 0; i < positionSpy.count(); ++i)
QVERIFY(positionSpy.at(i)[0].value<qint64>() > (position - 500));
}
void tst_QMediaPlayerBackend::subsequentPlayback() void tst_QMediaPlayerBackend::subsequentPlayback()
{ {
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
@@ -717,7 +920,7 @@ void tst_QMediaPlayerBackend::subsequentPlayback()
void tst_QMediaPlayerBackend::probes() void tst_QMediaPlayerBackend::probes()
{ {
if (localVideoFile.isNull()) if (localVideoFile.isNull())
QSKIP("Video format is not supported"); QSKIP("No supported video file");
QMediaPlayer *player = new QMediaPlayer; QMediaPlayer *player = new QMediaPlayer;
@@ -733,8 +936,9 @@ void tst_QMediaPlayerBackend::probes()
connect(audioProbe, SIGNAL(audioBufferProbed(QAudioBuffer)), &probeHandler, SLOT(processBuffer(QAudioBuffer))); connect(audioProbe, SIGNAL(audioBufferProbed(QAudioBuffer)), &probeHandler, SLOT(processBuffer(QAudioBuffer)));
connect(audioProbe, SIGNAL(flush()), &probeHandler, SLOT(flushAudio())); connect(audioProbe, SIGNAL(flush()), &probeHandler, SLOT(flushAudio()));
QVERIFY(videoProbe->setSource(player)); if (!videoProbe->setSource(player))
QVERIFY(audioProbe->setSource(player)); QSKIP("QVideoProbe is not supported");
audioProbe->setSource(player);
player->setMedia(localVideoFile); player->setMedia(localVideoFile);
QTRY_COMPARE(player->mediaStatus(), QMediaPlayer::LoadedMedia); QTRY_COMPARE(player->mediaStatus(), QMediaPlayer::LoadedMedia);
@@ -831,7 +1035,7 @@ void tst_QMediaPlayerBackend::playlist()
errorSpy.clear(); errorSpy.clear();
// <<< Invalid2 - 1st pass >>> // <<< Invalid2 - 1st pass >>>
fileInfo.setFile((QFINDTESTDATA("testdata/invalid_media2.m3u"))); fileInfo.setFile(QFINDTESTDATA("/testdata/invalid_media2.m3u"));
player.setMedia(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); player.setMedia(QUrl::fromLocalFile(fileInfo.absoluteFilePath()));
player.play(); player.play();
@@ -864,7 +1068,7 @@ void tst_QMediaPlayerBackend::playlist()
errorSpy.clear(); errorSpy.clear();
// <<< Recursive - 1st pass >>> // <<< Recursive - 1st pass >>>
fileInfo.setFile((QFINDTESTDATA("testdata/recursive_master.m3u"))); fileInfo.setFile(QFINDTESTDATA("testdata/recursive_master.m3u"));
player.setMedia(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); player.setMedia(QUrl::fromLocalFile(fileInfo.absoluteFilePath()));
player.play(); player.play();
@@ -929,7 +1133,7 @@ void tst_QMediaPlayerBackend::surfaceTest()
{ {
// 25 fps video file // 25 fps video file
if (localVideoFile.isNull()) if (localVideoFile.isNull())
QSKIP("Video format is not supported"); QSKIP("No supported video file");
QFETCH(QList<QVideoFrame::PixelFormat>, formatsList); QFETCH(QList<QVideoFrame::PixelFormat>, formatsList);