summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartlomiej Moskal <bartlomiej.moskal@qt.io>2022-09-22 20:59:40 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-10-13 23:07:08 +0000
commitc4c8f90ece84f36cd6a0252391e70065e66d0e1f (patch)
tree91a3cd6212e0b885c13de8c4e8b39925e8f7c513
parent274ade6e542b6948f8f99e2fe1a60cb6ad74573a (diff)
Android: Fix for setting video playback rate
According to doc[0], setting playback params may change the state of the player. Calling it on a prepared MediaPlayer with non-zero speed is equivalent to calling start(). This behavior is not expected in the Qt implementation. Therefore, changing the input speed should only be done in the Playing state or instead of calling play(). In such case, QtAndroidMediaPlayer need to handle state change, notification and start progress watcher. Therefore, setting playback params has been moved to QtAndroidMediaPlayer. Also playbackRate() should not rely on value from Android MediaPlayer. The value can be wrong for example when Video is in Pause state. [0]https://developer.android.com/reference/android/media/MediaPlayer#setPlaybackParams(android.media.PlaybackParams) Fixes: QTBUG-104670 Change-Id: I5ce7696cf986a1e1e2aaa0035df806e172a5b7b7 Reviewed-by: Samuel Mira <samuel.mira@qt.io> Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> (cherry picked from commit 98a2c27bf443e42c46afc5f9e9f26f0bb5f9ad09) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java25
-rw-r--r--src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer.cpp49
-rw-r--r--src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer_p.h2
-rw-r--r--src/plugins/multimedia/android/wrappers/jni/androidmediaplayer.cpp29
4 files changed, 47 insertions, 58 deletions
diff --git a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java
index cac26d357..6ddc64dc2 100644
--- a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java
+++ b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java
@@ -12,6 +12,7 @@ import java.io.FileInputStream;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaFormat;
+import android.media.PlaybackParams;
import android.media.AudioAttributes;
import android.media.TimedText;
import android.net.Uri;
@@ -723,4 +724,28 @@ public class QtAndroidMediaPlayer
Log.w(TAG, exception);
}
}
+
+ public boolean setPlaybackRate(float rate)
+ {
+ PlaybackParams playbackParams = mMediaPlayer.getPlaybackParams();
+ playbackParams.setSpeed(rate);
+ // According to discussion under the patch from QTBUG-61115: At least with DirectShow
+ // and GStreamer, it changes both speed and pitch. (...) need to be consistent
+ if (rate != 0.0)
+ playbackParams.setPitch(Math.abs(rate));
+
+ try {
+ mMediaPlayer.setPlaybackParams(playbackParams);
+ } catch (IllegalStateException | IllegalArgumentException e) {
+ Log.e(TAG, "Cannot set playback rate " + rate + " :" + e.toString());
+ return false;
+ }
+
+ if ((mState & State.Started) == 0 && mMediaPlayer.isPlaying()) {
+ setState(State.Started);
+ startProgressWatcher();
+ }
+
+ return true;
+ }
}
diff --git a/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer.cpp b/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer.cpp
index 1243b1e6f..1eea0a09f 100644
--- a/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer.cpp
+++ b/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer.cpp
@@ -213,43 +213,24 @@ void QAndroidMediaPlayer::updateAvailablePlaybackRanges()
qreal QAndroidMediaPlayer::playbackRate() const
{
- if (mHasPendingPlaybackRate ||
- (mState & (AndroidMediaPlayer::Initialized
- | AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted
- | AndroidMediaPlayer::Error)) == 0) {
- return mPendingPlaybackRate;
- }
-
- return mMediaPlayer->playbackRate();
+ return mCurrentPlaybackRate;
}
void QAndroidMediaPlayer::setPlaybackRate(qreal rate)
{
- if ((mState & (AndroidMediaPlayer::Initialized
- | AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted
- | AndroidMediaPlayer::Error)) == 0) {
- if (mPendingPlaybackRate != rate) {
- mPendingPlaybackRate = rate;
+ if (mState != AndroidMediaPlayer::Started) {
+ // If video isn't playing, changing speed rate may start it automatically
+ // It need to be postponed
+ if (mCurrentPlaybackRate != rate) {
+ mCurrentPlaybackRate = rate;
mHasPendingPlaybackRate = true;
Q_EMIT playbackRateChanged(rate);
}
return;
}
- bool succeeded = mMediaPlayer->setPlaybackRate(rate);
-
- if (mHasPendingPlaybackRate) {
- mHasPendingPlaybackRate = false;
- mPendingPlaybackRate = qreal(1.0);
- if (!succeeded)
- Q_EMIT playbackRateChanged(playbackRate());
- } else if (succeeded) {
+ if (mMediaPlayer->setPlaybackRate(rate)) {
+ mCurrentPlaybackRate = rate;
Q_EMIT playbackRateChanged(rate);
}
}
@@ -378,6 +359,14 @@ void QAndroidMediaPlayer::play()
updateAudioDevice();
+ if (mHasPendingPlaybackRate) {
+ mHasPendingPlaybackRate = false;
+ if (mMediaPlayer->setPlaybackRate(mCurrentPlaybackRate))
+ return;
+ mCurrentPlaybackRate = mMediaPlayer->playbackRate();
+ Q_EMIT playbackRateChanged(mCurrentPlaybackRate);
+ }
+
mMediaPlayer->play();
}
@@ -422,6 +411,10 @@ void QAndroidMediaPlayer::stop()
return;
}
+ if (mCurrentPlaybackRate != 1.)
+ // Playback rate need to by reapplied
+ mHasPendingPlaybackRate = true;
+
if (mVideoOutput)
mVideoOutput->stop();
@@ -941,8 +934,6 @@ void QAndroidMediaPlayer::flushPendingStates()
setVolume(mPendingVolume);
if (mPendingMute != -1)
setMuted((mPendingMute == 1));
- if (mHasPendingPlaybackRate)
- setPlaybackRate(mPendingPlaybackRate);
switch (newState) {
case QMediaPlayer::PlayingState:
diff --git a/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer_p.h b/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer_p.h
index a9ce78992..08d1a33fc 100644
--- a/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer_p.h
+++ b/src/plugins/multimedia/android/mediaplayer/qandroidmediaplayer_p.h
@@ -102,7 +102,7 @@ private:
int mPendingMute = -1;
bool mReloadingMedia = false;
int mActiveStateChangeNotifiers = 0;
- qreal mPendingPlaybackRate = 1.;
+ qreal mCurrentPlaybackRate = 1.;
bool mHasPendingPlaybackRate = false; // we need this because the rate can theoretically be negative
QMap<TrackType, QList<QAndroidMetaData>> mTracksMetadata;
diff --git a/src/plugins/multimedia/android/wrappers/jni/androidmediaplayer.cpp b/src/plugins/multimedia/android/wrappers/jni/androidmediaplayer.cpp
index 3476d2676..58a546710 100644
--- a/src/plugins/multimedia/android/wrappers/jni/androidmediaplayer.cpp
+++ b/src/plugins/multimedia/android/wrappers/jni/androidmediaplayer.cpp
@@ -260,34 +260,7 @@ bool AndroidMediaPlayer::setPlaybackRate(qreal rate)
return false;
}
- QJniObject player = mMediaPlayer.callObjectMethod("getMediaPlayerHandle",
- "()Landroid/media/MediaPlayer;");
- if (player.isValid()) {
- QJniObject playbackParams = player.callObjectMethod("getPlaybackParams",
- "()Landroid/media/PlaybackParams;");
- if (playbackParams.isValid()) {
- playbackParams.callObjectMethod("setSpeed", "(F)Landroid/media/PlaybackParams;",
- jfloat(rate));
- // pitch can only be > 0
- if (!qFuzzyIsNull(rate))
- playbackParams.callObjectMethod("setPitch", "(F)Landroid/media/PlaybackParams;",
- jfloat(qAbs(rate)));
-
- QJniEnvironment env;
- auto methodId = env->GetMethodID(player.objectClass(), "setPlaybackParams",
- "(Landroid/media/PlaybackParams;)V");
- env->CallVoidMethod(player.object(), methodId, playbackParams.object());
-
- if (env.checkAndClearExceptions()) {
- qWarning() << "Invalid playback rate" << rate;
- return false;
- } else {
- return true;
- }
- }
- }
-
- return false;
+ return mMediaPlayer.callMethod<jboolean>("setPlaybackRate", jfloat(rate));
}
void AndroidMediaPlayer::setDisplay(AndroidSurfaceTexture *surfaceTexture)