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 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
*/
@@ -257,8 +240,6 @@ public class QtAndroidMediaPlayer
try {
mMediaPlayer.start();
setState(State.Started);
Thread progressThread = new Thread(new ProgressWatcher());
progressThread.start();
} catch (final IllegalStateException e) {
Log.d(TAG, "" + e.getMessage());
}
@@ -309,7 +290,6 @@ public class QtAndroidMediaPlayer
try {
mMediaPlayer.seekTo(msec);
onProgressUpdateNative(msec, mID);
} catch (final IllegalStateException e) {
Log.d(TAG, "" + e.getMessage());
}

View File

@@ -86,6 +86,7 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent)
mPendingSetMedia(false),
mPendingVolume(-1),
mPendingMute(-1),
mReloadingMedia(false),
mActiveStateChangeNotifiers(0)
{
connect(mMediaPlayer,SIGNAL(bufferingChanged(qint32)),
@@ -138,17 +139,14 @@ qint64 QAndroidMediaPlayerControl::position() const
if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia)
return duration();
if ((mState & (AndroidMediaPlayer::Idle
| AndroidMediaPlayer::Initialized
| AndroidMediaPlayer::Prepared
if ((mState & (AndroidMediaPlayer::Prepared
| AndroidMediaPlayer::Started
| AndroidMediaPlayer::Paused
| AndroidMediaPlayer::Stopped
| AndroidMediaPlayer::PlaybackCompleted)) == 0) {
return (mPendingPosition == -1) ? 0 : mPendingPosition;
| AndroidMediaPlayer::PlaybackCompleted))) {
return mMediaPlayer->getCurrentPosition();
}
return (mCurrentState == QMediaPlayer::StoppedState) ? 0 : mMediaPlayer->getCurrentPosition();
return (mPendingPosition == -1) ? 0 : mPendingPosition;
}
void QAndroidMediaPlayerControl::setPosition(qint64 position)
@@ -158,26 +156,25 @@ void QAndroidMediaPlayerControl::setPosition(qint64 position)
const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
if ((mState & (AndroidMediaPlayer::Prepared
| AndroidMediaPlayer::Started
| AndroidMediaPlayer::Paused
| AndroidMediaPlayer::PlaybackCompleted)) == 0) {
if (mPendingPosition != seekPosition) {
mPendingPosition = seekPosition;
Q_EMIT positionChanged(seekPosition);
}
if (seekPosition == this->position())
return;
}
StateChangeNotifier notifier(this);
if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia)
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) {
mPendingPosition = -1;
if (mPendingPosition != -1) {
mPendingPosition = -1;
}
}
Q_EMIT positionChanged(seekPosition);
@@ -310,9 +307,9 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
{
StateChangeNotifier notifier(this);
const bool reloading = (mMediaContent == mediaContent);
mReloadingMedia = (mMediaContent == mediaContent);
if (!reloading) {
if (!mReloadingMedia) {
mMediaContent = mediaContent;
mMediaStream = stream;
}
@@ -321,43 +318,45 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
if ((mState & (AndroidMediaPlayer::Idle | AndroidMediaPlayer::Uninitialized)) == 0)
mMediaPlayer->release();
QString mediaPath;
if (mediaContent.isNull()) {
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 {
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)
mVideoOutput->setVideoSize(mVideoSize);
if ((mMediaPlayer->display() == 0) && mVideoOutput)
mMediaPlayer->setDisplay(mVideoOutput->surfaceTexture());
mMediaPlayer->setDataSource(mediaPath);
mMediaPlayer->prepareAsync();
if (!reloading) {
if (!mReloadingMedia) {
Q_EMIT mediaChanged(mMediaContent);
Q_EMIT actualMediaLocationChanged(mediaPath);
}
resetBufferingProgress();
mReloadingMedia = false;
}
void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
@@ -567,7 +566,8 @@ void QAndroidMediaPlayerControl::onStateChanged(qint32 state)
case AndroidMediaPlayer::Initialized:
break;
case AndroidMediaPlayer::Preparing:
setMediaStatus(QMediaPlayer::LoadingMedia);
if (!mReloadingMedia)
setMediaStatus(QMediaPlayer::LoadingMedia);
break;
case AndroidMediaPlayer::Prepared:
setMediaStatus(QMediaPlayer::LoadedMedia);
@@ -588,6 +588,7 @@ void QAndroidMediaPlayerControl::onStateChanged(qint32 state)
} else {
setMediaStatus(QMediaPlayer::BufferedMedia);
}
Q_EMIT positionChanged(position());
break;
case AndroidMediaPlayer::Paused:
setState(QMediaPlayer::PausedState);
@@ -596,27 +597,32 @@ void QAndroidMediaPlayerControl::onStateChanged(qint32 state)
setState(QMediaPlayer::StoppedState);
setMediaStatus(QMediaPlayer::UnknownMediaStatus);
mMediaPlayer->release();
Q_EMIT positionChanged(0);
break;
case AndroidMediaPlayer::Stopped:
setState(QMediaPlayer::StoppedState);
setMediaStatus(QMediaPlayer::LoadedMedia);
setPosition(0);
Q_EMIT positionChanged(0);
break;
case AndroidMediaPlayer::PlaybackCompleted:
setState(QMediaPlayer::StoppedState);
setPosition(0);
setMediaStatus(QMediaPlayer::EndOfMedia);
break;
case AndroidMediaPlayer::Uninitialized:
// reset some properties
resetBufferingProgress();
mPendingPosition = -1;
mPendingSetMedia = false;
mPendingState = -1;
// reset some properties (unless we reload the same media)
if (!mReloadingMedia) {
resetBufferingProgress();
mPendingPosition = -1;
mPendingSetMedia = false;
mPendingState = -1;
setAudioAvailable(false);
setVideoAvailable(false);
setSeekable(true);
Q_EMIT durationChanged(0);
Q_EMIT positionChanged(0);
setAudioAvailable(false);
setVideoAvailable(false);
setSeekable(true);
}
break;
default:
break;
@@ -655,13 +661,13 @@ void QAndroidMediaPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status
if (mCurrentMediaStatus == status)
return;
mCurrentMediaStatus = status;
if (status == QMediaPlayer::NoMedia || status == QMediaPlayer::InvalidMedia)
Q_EMIT durationChanged(0);
if (status == QMediaPlayer::EndOfMedia)
Q_EMIT durationChanged(duration());
mCurrentMediaStatus = status;
Q_EMIT positionChanged(position());
updateBufferStatus();
}

View File

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