Android: Make the Mediaplayer more robust
In some cases the the Android media player would get into a unexpected state and we where then not able to recover. With this patch we monitor the state changes more closely and recover when possible. Task-number: QTBUG-35651 Change-Id: I142c63fbbf716d3f94ebdcf016a7cadad7b13207 Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
committed by
The Qt Project
parent
ddd22fab2b
commit
dcf11bba3c
@@ -53,59 +53,56 @@ import android.util.Log;
|
|||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import android.content.res.AssetFileDescriptor;
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
|
||||||
public class QtAndroidMediaPlayer extends MediaPlayer
|
public class QtAndroidMediaPlayer
|
||||||
{
|
{
|
||||||
// Native callback functions for MediaPlayer
|
// Native callback functions for MediaPlayer
|
||||||
native public void onErrorNative(int what, int extra, long id);
|
native public void onErrorNative(int what, int extra, long id);
|
||||||
native public void onBufferingUpdateNative(int percent, long id);
|
native public void onBufferingUpdateNative(int percent, long id);
|
||||||
|
native public void onProgressUpdateNative(int progress, long id);
|
||||||
|
native public void onDurationChangedNative(int duration, long id);
|
||||||
native public void onInfoNative(int what, int extra, long id);
|
native public void onInfoNative(int what, int extra, long id);
|
||||||
native public void onMediaPlayerInfoNative(int what, int extra, long id);
|
|
||||||
native public void onVideoSizeChangedNative(int width, int height, long id);
|
native public void onVideoSizeChangedNative(int width, int height, long id);
|
||||||
|
native public void onStateChangedNative(int state, long id);
|
||||||
|
|
||||||
|
private MediaPlayer mMediaPlayer = null;
|
||||||
private Uri mUri = null;
|
private Uri mUri = null;
|
||||||
private final long mID;
|
private final long mID;
|
||||||
|
private final Activity mActivity;
|
||||||
private boolean mMuted = false;
|
private boolean mMuted = false;
|
||||||
private boolean mPreparing = false;
|
|
||||||
private boolean mInitialized = false;
|
|
||||||
private int mVolume = 100;
|
private int mVolume = 100;
|
||||||
private static final String TAG = "Qt MediaPlayer";
|
private static final String TAG = "Qt MediaPlayer";
|
||||||
private static Context mApplicationContext = null;
|
private SurfaceHolder mSurfaceHolder = null;
|
||||||
|
|
||||||
final int MEDIA_PLAYER_INVALID_STATE = 1;
|
private class State {
|
||||||
final int MEDIA_PLAYER_PREPARING = 2;
|
final static int Uninitialized = 0x1 /* End */;
|
||||||
final int MEDIA_PLAYER_READY = 3;
|
final static int Idle = 0x2;
|
||||||
final int MEDIA_PLAYER_DURATION = 4;
|
final static int Preparing = 0x4;
|
||||||
final int MEDIA_PLAYER_PROGRESS = 5;
|
final static int Prepared = 0x8;
|
||||||
final int MEDIA_PLAYER_FINISHED = 6;
|
final static int Initialized = 0x10;
|
||||||
|
final static int Started = 0x20;
|
||||||
// Activity set by Qt on load.
|
final static int Stopped = 0x40;
|
||||||
static public void setActivity(final Activity activity)
|
final static int Paused = 0x80;
|
||||||
{
|
final static int PlaybackCompleted = 0x100;
|
||||||
try {
|
final static int Error = 0x200;
|
||||||
mApplicationContext = activity.getApplicationContext();
|
|
||||||
} catch(final Exception e) {
|
|
||||||
Log.d(TAG, "" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProgressWatcher implements Runnable
|
private volatile int mState = State.Uninitialized;
|
||||||
|
|
||||||
|
private class ProgressWatcher
|
||||||
|
implements Runnable
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
final int duratation = getDuration();
|
|
||||||
int currentPosition = getCurrentPosition();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (duratation >= currentPosition && isPlaying()) {
|
while ((mState & (State.Started)) != 0) {
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, currentPosition, mID);
|
onProgressUpdateNative(getCurrentPosition(), mID);
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
currentPosition = getCurrentPosition();
|
|
||||||
}
|
}
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
// Ignore
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,7 +118,7 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
final int what,
|
final int what,
|
||||||
final int extra)
|
final int extra)
|
||||||
{
|
{
|
||||||
reset();
|
setState(State.Error);
|
||||||
onErrorNative(what, extra, mID);
|
onErrorNative(what, extra, mID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -158,7 +155,7 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void onCompletion(final MediaPlayer mp)
|
public void onCompletion(final MediaPlayer mp)
|
||||||
{
|
{
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_FINISHED, 0, mID);
|
setState(State.PlaybackCompleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -190,9 +187,8 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void onPrepared(final MediaPlayer mp)
|
public void onPrepared(final MediaPlayer mp)
|
||||||
{
|
{
|
||||||
mPreparing = false;
|
setState(State.Prepared);
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_READY, 0, mID);
|
onDurationChangedNative(getDuration(), mID);
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_DURATION, getDuration(), mID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -207,7 +203,7 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void onSeekComplete(final MediaPlayer mp)
|
public void onSeekComplete(final MediaPlayer mp)
|
||||||
{
|
{
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, getCurrentPosition(), mID);
|
onProgressUpdateNative(getCurrentPosition(), mID);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -229,98 +225,117 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public QtAndroidMediaPlayer(final long id)
|
public QtAndroidMediaPlayer(final Activity activity, final long id)
|
||||||
{
|
{
|
||||||
super();
|
|
||||||
mID = id;
|
mID = id;
|
||||||
setOnBufferingUpdateListener(new MediaPlayerBufferingListener());
|
mActivity = activity;
|
||||||
setOnCompletionListener(new MediaPlayerCompletionListener());
|
}
|
||||||
setOnInfoListener(new MediaPlayerInfoListener());
|
|
||||||
setOnSeekCompleteListener(new MediaPlayerSeekCompleteListener());
|
private void setState(int state)
|
||||||
setOnVideoSizeChangedListener(new MediaPlayerVideoSizeChangedListener());
|
{
|
||||||
setOnErrorListener(new MediaPlayerErrorListener());
|
if (mState == state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mState = state;
|
||||||
|
|
||||||
|
onStateChangedNative(mState, mID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void init()
|
||||||
|
{
|
||||||
|
if (mMediaPlayer == null) {
|
||||||
|
mMediaPlayer = new MediaPlayer();
|
||||||
|
setState(State.Idle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start()
|
public void start()
|
||||||
{
|
{
|
||||||
if (!mInitialized) {
|
if ((mState & (State.Prepared
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_INVALID_STATE, 0, mID);
|
| State.Started
|
||||||
|
| State.Paused
|
||||||
|
| State.PlaybackCompleted)) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mApplicationContext == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mPreparing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (isPlaying())
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
super.start();
|
mMediaPlayer.start();
|
||||||
|
setState(State.Started);
|
||||||
Thread progressThread = new Thread(new ProgressWatcher());
|
Thread progressThread = new Thread(new ProgressWatcher());
|
||||||
progressThread.start();
|
progressThread.start();
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
reset();
|
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pause()
|
public void pause()
|
||||||
{
|
{
|
||||||
if (!isPlaying())
|
if ((mState & (State.Started | State.Paused | State.PlaybackCompleted)) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
super.pause();
|
mMediaPlayer.pause();
|
||||||
|
setState(State.Paused);
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
reset();
|
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop()
|
public void stop()
|
||||||
{
|
{
|
||||||
if (!mInitialized)
|
if ((mState & (State.Prepared
|
||||||
|
| State.Started
|
||||||
|
| State.Stopped
|
||||||
|
| State.Paused
|
||||||
|
| State.PlaybackCompleted)) == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
super.stop();
|
mMediaPlayer.stop();
|
||||||
|
setState(State.Stopped);
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
} finally {
|
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekTo(final int msec)
|
public void seekTo(final int msec)
|
||||||
{
|
{
|
||||||
if (!mInitialized)
|
if ((mState & (State.Prepared
|
||||||
|
| State.Started
|
||||||
|
| State.Paused
|
||||||
|
| State.PlaybackCompleted)) == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
super.seekTo(msec);
|
mMediaPlayer.seekTo(msec);
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, msec, mID);
|
onProgressUpdateNative(msec, mID);
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPlaying()
|
public boolean isPlaying()
|
||||||
{
|
{
|
||||||
boolean playing = false;
|
boolean playing = false;
|
||||||
|
if ((mState & (State.Idle
|
||||||
if (!mInitialized)
|
| State.Initialized
|
||||||
|
| State.Prepared
|
||||||
|
| State.Started
|
||||||
|
| State.Paused
|
||||||
|
| State.Stopped
|
||||||
|
| State.PlaybackCompleted)) == 0) {
|
||||||
return playing;
|
return playing;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
playing = super.isPlaying();
|
playing = mMediaPlayer.isPlaying();
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -328,34 +343,56 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
return playing;
|
return playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMediaPath(final String path)
|
public void prepareAsync()
|
||||||
{
|
{
|
||||||
if (mInitialized)
|
if ((mState & (State.Initialized | State.Stopped)) == 0)
|
||||||
reset();
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mPreparing = true;
|
mMediaPlayer.prepareAsync();
|
||||||
onMediaPlayerInfoNative(MEDIA_PLAYER_PREPARING, 0, mID);
|
setState(State.Preparing);
|
||||||
|
} catch (final IllegalStateException e) {
|
||||||
|
Log.d(TAG, "" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataSource(final String path)
|
||||||
|
{
|
||||||
|
if ((mState & State.Uninitialized) != 0)
|
||||||
|
init();
|
||||||
|
|
||||||
|
if ((mState & State.Idle) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayerBufferingListener());
|
||||||
|
mMediaPlayer.setOnCompletionListener(new MediaPlayerCompletionListener());
|
||||||
|
mMediaPlayer.setOnInfoListener(new MediaPlayerInfoListener());
|
||||||
|
mMediaPlayer.setOnSeekCompleteListener(new MediaPlayerSeekCompleteListener());
|
||||||
|
mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayerVideoSizeChangedListener());
|
||||||
|
mMediaPlayer.setOnErrorListener(new MediaPlayerErrorListener());
|
||||||
|
mMediaPlayer.setOnPreparedListener(new MediaPlayerPreparedListener());
|
||||||
|
|
||||||
|
if (mSurfaceHolder != null)
|
||||||
|
mMediaPlayer.setDisplay(mSurfaceHolder);
|
||||||
|
|
||||||
|
AssetFileDescriptor afd = null;
|
||||||
|
try {
|
||||||
mUri = Uri.parse(path);
|
mUri = Uri.parse(path);
|
||||||
if (mUri.getScheme().compareTo("assets") == 0) {
|
final boolean inAssets = (mUri.getScheme().compareTo("assets") == 0);
|
||||||
|
if (inAssets) {
|
||||||
final String asset = mUri.getPath().substring(1 /* Remove first '/' */);
|
final String asset = mUri.getPath().substring(1 /* Remove first '/' */);
|
||||||
final AssetManager am = mApplicationContext.getAssets();
|
final AssetManager am = mActivity.getAssets();
|
||||||
final AssetFileDescriptor afd = am.openFd(asset);
|
afd = am.openFd(asset);
|
||||||
final long offset = afd.getStartOffset();
|
final long offset = afd.getStartOffset();
|
||||||
final long length = afd.getLength();
|
final long length = afd.getLength();
|
||||||
FileDescriptor fd = afd.getFileDescriptor();
|
FileDescriptor fd = afd.getFileDescriptor();
|
||||||
setDataSource(fd, offset, length);
|
mMediaPlayer.setDataSource(fd, offset, length);
|
||||||
} else {
|
} else {
|
||||||
setDataSource(mApplicationContext, mUri);
|
mMediaPlayer.setDataSource(mActivity, mUri);
|
||||||
}
|
}
|
||||||
mInitialized = true;
|
setState(State.Initialized);
|
||||||
setOnPreparedListener(new MediaPlayerPreparedListener());
|
|
||||||
prepareAsync();
|
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
mPreparing = false;
|
Log.d(TAG, "" + e.getMessage());
|
||||||
onErrorNative(MEDIA_ERROR_UNKNOWN,
|
|
||||||
/* MEDIA_ERROR_UNSUPPORTED= */ -1010,
|
|
||||||
mID);
|
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
} catch (final SecurityException e) {
|
} catch (final SecurityException e) {
|
||||||
@@ -364,19 +401,36 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
} catch (final NullPointerException e) {
|
} catch (final NullPointerException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
|
} finally {
|
||||||
|
if (afd !=null) {
|
||||||
|
try { afd.close(); } catch (final IOException ioe) { /* Ignore... */ }
|
||||||
|
}
|
||||||
|
if ((mState & State.Initialized) == 0) {
|
||||||
|
setState(State.Error);
|
||||||
|
onErrorNative(MediaPlayer.MEDIA_ERROR_UNKNOWN,
|
||||||
|
-1004 /*MEDIA_ERROR_IO*/,
|
||||||
|
mID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCurrentPosition()
|
public int getCurrentPosition()
|
||||||
{
|
{
|
||||||
int currentPosition = 0;
|
int currentPosition = 0;
|
||||||
|
if ((mState & (State.Idle
|
||||||
if (!mInitialized)
|
| State.Initialized
|
||||||
|
| State.Prepared
|
||||||
|
| State.Started
|
||||||
|
| State.Paused
|
||||||
|
| State.Stopped
|
||||||
|
| State.PlaybackCompleted)) == 0) {
|
||||||
return currentPosition;
|
return currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
currentPosition = super.getCurrentPosition();
|
currentPosition = mMediaPlayer.getCurrentPosition();
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -384,16 +438,20 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
return currentPosition;
|
return currentPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getDuration()
|
public int getDuration()
|
||||||
{
|
{
|
||||||
int duration = 0;
|
int duration = 0;
|
||||||
|
if ((mState & (State.Prepared
|
||||||
if (!mInitialized)
|
| State.Started
|
||||||
|
| State.Paused
|
||||||
|
| State.Stopped
|
||||||
|
| State.PlaybackCompleted)) == 0) {
|
||||||
return duration;
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
duration = super.getDuration();
|
duration = mMediaPlayer.getDuration();
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
Log.d(TAG, "" + e.getMessage());
|
Log.d(TAG, "" + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -414,6 +472,16 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
|
|
||||||
public void setVolume(int volume)
|
public void setVolume(int volume)
|
||||||
{
|
{
|
||||||
|
if ((mState & (State.Idle
|
||||||
|
| State.Initialized
|
||||||
|
| State.Stopped
|
||||||
|
| State.Prepared
|
||||||
|
| State.Started
|
||||||
|
| State.Paused
|
||||||
|
| State.PlaybackCompleted)) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (volume < 0)
|
if (volume < 0)
|
||||||
volume = 0;
|
volume = 0;
|
||||||
|
|
||||||
@@ -423,7 +491,7 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
float newVolume = adjustVolume(volume);
|
float newVolume = adjustVolume(volume);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
super.setVolume(newVolume, newVolume);
|
mMediaPlayer.setVolume(newVolume, newVolume);
|
||||||
if (!mMuted)
|
if (!mMuted)
|
||||||
mVolume = volume;
|
mVolume = volume;
|
||||||
} catch (final IllegalStateException e) {
|
} catch (final IllegalStateException e) {
|
||||||
@@ -431,6 +499,22 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SurfaceHolder display()
|
||||||
|
{
|
||||||
|
return mSurfaceHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplay(SurfaceHolder sh)
|
||||||
|
{
|
||||||
|
mSurfaceHolder = sh;
|
||||||
|
|
||||||
|
if ((mState & State.Uninitialized) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMediaPlayer.setDisplay(mSurfaceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getVolume()
|
public int getVolume()
|
||||||
{
|
{
|
||||||
return mVolume;
|
return mVolume;
|
||||||
@@ -447,11 +531,32 @@ public class QtAndroidMediaPlayer extends MediaPlayer
|
|||||||
return mMuted;
|
return mMuted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset()
|
public void reset()
|
||||||
{
|
{
|
||||||
mInitialized = false;
|
if ((mState & (State.Idle
|
||||||
super.reset();
|
| State.Initialized
|
||||||
|
| State.Prepared
|
||||||
|
| State.Started
|
||||||
|
| State.Paused
|
||||||
|
| State.Stopped
|
||||||
|
| State.PlaybackCompleted
|
||||||
|
| State.Error)) == 0) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMediaPlayer.reset();
|
||||||
|
setState(State.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release()
|
||||||
|
{
|
||||||
|
if (mMediaPlayer != null) {
|
||||||
|
mMediaPlayer.reset();
|
||||||
|
mMediaPlayer.release();
|
||||||
|
mMediaPlayer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(State.Uninitialized);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ public:
|
|||||||
|
|
||||||
virtual void setVideoSize(const QSize &) { }
|
virtual void setVideoSize(const QSize &) { }
|
||||||
virtual void stop() { }
|
virtual void stop() { }
|
||||||
|
virtual void reset() { }
|
||||||
|
|
||||||
// signals:
|
// signals:
|
||||||
// void readyChanged(bool);
|
// void readyChanged(bool);
|
||||||
|
|||||||
@@ -122,20 +122,8 @@ QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
|
|||||||
|
|
||||||
QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
|
QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
|
||||||
{
|
{
|
||||||
if (m_surfaceTexture) {
|
clearSurfaceTexture();
|
||||||
m_surfaceTexture->callMethod<void>("release");
|
|
||||||
delete m_surfaceTexture;
|
|
||||||
m_surfaceTexture = 0;
|
|
||||||
}
|
|
||||||
if (m_androidSurface) {
|
|
||||||
m_androidSurface->callMethod<void>("release");
|
|
||||||
delete m_androidSurface;
|
|
||||||
m_androidSurface = 0;
|
|
||||||
}
|
|
||||||
if (m_surfaceHolder) {
|
|
||||||
delete m_surfaceHolder;
|
|
||||||
m_surfaceHolder = 0;
|
|
||||||
}
|
|
||||||
if (m_glDeleter)
|
if (m_glDeleter)
|
||||||
m_glDeleter->deleteLater();
|
m_glDeleter->deleteLater();
|
||||||
}
|
}
|
||||||
@@ -202,6 +190,24 @@ bool QAndroidVideoRendererControl::initSurfaceTexture()
|
|||||||
return m_surfaceTexture != 0;
|
return m_surfaceTexture != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QAndroidVideoRendererControl::clearSurfaceTexture()
|
||||||
|
{
|
||||||
|
if (m_surfaceTexture) {
|
||||||
|
m_surfaceTexture->callMethod<void>("release");
|
||||||
|
delete m_surfaceTexture;
|
||||||
|
m_surfaceTexture = 0;
|
||||||
|
}
|
||||||
|
if (m_androidSurface) {
|
||||||
|
m_androidSurface->callMethod<void>("release");
|
||||||
|
delete m_androidSurface;
|
||||||
|
m_androidSurface = 0;
|
||||||
|
}
|
||||||
|
if (m_surfaceHolder) {
|
||||||
|
delete m_surfaceHolder;
|
||||||
|
m_surfaceHolder = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jobject QAndroidVideoRendererControl::surfaceHolder()
|
jobject QAndroidVideoRendererControl::surfaceHolder()
|
||||||
{
|
{
|
||||||
if (!initSurfaceTexture())
|
if (!initSurfaceTexture())
|
||||||
@@ -245,6 +251,11 @@ void QAndroidVideoRendererControl::stop()
|
|||||||
m_nativeSize = QSize();
|
m_nativeSize = QSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QAndroidVideoRendererControl::reset()
|
||||||
|
{
|
||||||
|
clearSurfaceTexture();
|
||||||
|
}
|
||||||
|
|
||||||
void QAndroidVideoRendererControl::onFrameAvailable()
|
void QAndroidVideoRendererControl::onFrameAvailable()
|
||||||
{
|
{
|
||||||
if (!m_nativeSize.isValid() || !m_surface)
|
if (!m_nativeSize.isValid() || !m_surface)
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ public:
|
|||||||
bool isReady() Q_DECL_OVERRIDE;
|
bool isReady() Q_DECL_OVERRIDE;
|
||||||
void setVideoSize(const QSize &size) Q_DECL_OVERRIDE;
|
void setVideoSize(const QSize &size) Q_DECL_OVERRIDE;
|
||||||
void stop() Q_DECL_OVERRIDE;
|
void stop() Q_DECL_OVERRIDE;
|
||||||
|
void reset() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
void customEvent(QEvent *) Q_DECL_OVERRIDE;
|
void customEvent(QEvent *) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
@@ -107,6 +108,7 @@ private:
|
|||||||
void createGLResources();
|
void createGLResources();
|
||||||
|
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
|
void clearSurfaceTexture();
|
||||||
|
|
||||||
QAbstractVideoSurface *m_surface;
|
QAbstractVideoSurface *m_surface;
|
||||||
QSize m_nativeSize;
|
QSize m_nativeSize;
|
||||||
|
|||||||
@@ -57,25 +57,31 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent)
|
|||||||
mAudioAvailable(false),
|
mAudioAvailable(false),
|
||||||
mVideoAvailable(false),
|
mVideoAvailable(false),
|
||||||
mBuffering(false),
|
mBuffering(false),
|
||||||
mMediaPlayerReady(false),
|
mState(JMediaPlayer::Uninitialized),
|
||||||
|
mPendingState(-1),
|
||||||
mPendingPosition(-1),
|
mPendingPosition(-1),
|
||||||
mPendingSetMedia(false)
|
mPendingSetMedia(false),
|
||||||
|
mPendingVolume(-1),
|
||||||
|
mPendingMute(-1)
|
||||||
{
|
{
|
||||||
connect(mMediaPlayer, SIGNAL(bufferingUpdate(qint32)),
|
connect(mMediaPlayer,SIGNAL(bufferingChanged(qint32)),
|
||||||
this, SLOT(onBufferChanged(qint32)));
|
this,SLOT(onBufferingChanged(qint32)));
|
||||||
connect(mMediaPlayer,SIGNAL(info(qint32,qint32)),
|
connect(mMediaPlayer,SIGNAL(info(qint32,qint32)),
|
||||||
this,SLOT(onInfo(qint32,qint32)));
|
this,SLOT(onInfo(qint32,qint32)));
|
||||||
connect(mMediaPlayer,SIGNAL(error(qint32,qint32)),
|
connect(mMediaPlayer,SIGNAL(error(qint32,qint32)),
|
||||||
this,SLOT(onError(qint32,qint32)));
|
this,SLOT(onError(qint32,qint32)));
|
||||||
connect(mMediaPlayer, SIGNAL(mediaPlayerInfo(qint32,qint32)),
|
connect(mMediaPlayer,SIGNAL(stateChanged(qint32)),
|
||||||
this, SLOT(onMediaPlayerInfo(qint32,qint32)));
|
this,SLOT(onStateChanged(qint32)));
|
||||||
connect(mMediaPlayer,SIGNAL(videoSizeChanged(qint32,qint32)),
|
connect(mMediaPlayer,SIGNAL(videoSizeChanged(qint32,qint32)),
|
||||||
this,SLOT(onVideoSizeChanged(qint32,qint32)));
|
this,SLOT(onVideoSizeChanged(qint32,qint32)));
|
||||||
|
connect(mMediaPlayer,SIGNAL(progressChanged(qint64)),
|
||||||
|
this,SIGNAL(positionChanged(qint64)));
|
||||||
|
connect(mMediaPlayer,SIGNAL(durationChanged(qint64)),
|
||||||
|
this,SIGNAL(durationChanged(qint64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QAndroidMediaPlayerControl::~QAndroidMediaPlayerControl()
|
QAndroidMediaPlayerControl::~QAndroidMediaPlayerControl()
|
||||||
{
|
{
|
||||||
mMediaPlayer->stop();
|
|
||||||
mMediaPlayer->release();
|
mMediaPlayer->release();
|
||||||
delete mMediaPlayer;
|
delete mMediaPlayer;
|
||||||
}
|
}
|
||||||
@@ -92,18 +98,33 @@ QMediaPlayer::MediaStatus QAndroidMediaPlayerControl::mediaStatus() const
|
|||||||
|
|
||||||
qint64 QAndroidMediaPlayerControl::duration() const
|
qint64 QAndroidMediaPlayerControl::duration() const
|
||||||
{
|
{
|
||||||
return (mCurrentMediaStatus == QMediaPlayer::InvalidMedia
|
if ((mState & (JMediaPlayer::Prepared
|
||||||
|| mCurrentMediaStatus == QMediaPlayer::NoMedia
|
| JMediaPlayer::Started
|
||||||
|| !mMediaPlayerReady) ? 0
|
| JMediaPlayer::Paused
|
||||||
: mMediaPlayer->getDuration();
|
| JMediaPlayer::Stopped
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mMediaPlayer->getDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QAndroidMediaPlayerControl::position() const
|
qint64 QAndroidMediaPlayerControl::position() const
|
||||||
{
|
{
|
||||||
if (!mMediaPlayerReady)
|
if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia)
|
||||||
return mPendingPosition < 0 ? 0 : mPendingPosition;
|
return duration();
|
||||||
|
|
||||||
return mMediaPlayer->getCurrentPosition();
|
if ((mState & (JMediaPlayer::Idle
|
||||||
|
| JMediaPlayer::Initialized
|
||||||
|
| JMediaPlayer::Prepared
|
||||||
|
| JMediaPlayer::Started
|
||||||
|
| JMediaPlayer::Paused
|
||||||
|
| JMediaPlayer::Stopped
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
|
return (mPendingPosition == -1) ? 0 : mPendingPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (mCurrentState == QMediaPlayer::StoppedState) ? 0 : mMediaPlayer->getCurrentPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::setPosition(qint64 position)
|
void QAndroidMediaPlayerControl::setPosition(qint64 position)
|
||||||
@@ -113,35 +134,88 @@ void QAndroidMediaPlayerControl::setPosition(qint64 position)
|
|||||||
|
|
||||||
const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
|
const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
|
||||||
|
|
||||||
if (!mMediaPlayerReady) {
|
if ((mState & (JMediaPlayer::Prepared
|
||||||
|
| JMediaPlayer::Started
|
||||||
|
| JMediaPlayer::Paused
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
|
if (mPendingPosition != seekPosition) {
|
||||||
mPendingPosition = seekPosition;
|
mPendingPosition = seekPosition;
|
||||||
Q_EMIT positionChanged(seekPosition);
|
Q_EMIT positionChanged(seekPosition);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mCurrentMediaStatus == QMediaPlayer::EndOfMedia)
|
||||||
|
setMediaStatus(QMediaPlayer::LoadedMedia);
|
||||||
|
|
||||||
mMediaPlayer->seekTo(seekPosition);
|
mMediaPlayer->seekTo(seekPosition);
|
||||||
|
|
||||||
|
if (mPendingPosition != -1) {
|
||||||
mPendingPosition = -1;
|
mPendingPosition = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_EMIT positionChanged(seekPosition);
|
||||||
|
}
|
||||||
|
|
||||||
int QAndroidMediaPlayerControl::volume() const
|
int QAndroidMediaPlayerControl::volume() const
|
||||||
{
|
{
|
||||||
return mMediaPlayer->volume();
|
return (mPendingVolume == -1) ? mMediaPlayer->volume() : mPendingVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::setVolume(int volume)
|
void QAndroidMediaPlayerControl::setVolume(int volume)
|
||||||
{
|
{
|
||||||
|
if ((mState & (JMediaPlayer::Idle
|
||||||
|
| JMediaPlayer::Initialized
|
||||||
|
| JMediaPlayer::Stopped
|
||||||
|
| JMediaPlayer::Prepared
|
||||||
|
| JMediaPlayer::Started
|
||||||
|
| JMediaPlayer::Paused
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
|
if (mPendingVolume != volume) {
|
||||||
|
mPendingVolume = volume;
|
||||||
|
Q_EMIT volumeChanged(volume);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mMediaPlayer->setVolume(volume);
|
mMediaPlayer->setVolume(volume);
|
||||||
|
|
||||||
|
if (mPendingVolume != -1) {
|
||||||
|
mPendingVolume = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Q_EMIT volumeChanged(volume);
|
Q_EMIT volumeChanged(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QAndroidMediaPlayerControl::isMuted() const
|
bool QAndroidMediaPlayerControl::isMuted() const
|
||||||
{
|
{
|
||||||
return mMediaPlayer->isMuted();
|
return (mPendingMute == -1) ? mMediaPlayer->isMuted() : (mPendingMute == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::setMuted(bool muted)
|
void QAndroidMediaPlayerControl::setMuted(bool muted)
|
||||||
{
|
{
|
||||||
|
if ((mState & (JMediaPlayer::Idle
|
||||||
|
| JMediaPlayer::Initialized
|
||||||
|
| JMediaPlayer::Stopped
|
||||||
|
| JMediaPlayer::Prepared
|
||||||
|
| JMediaPlayer::Started
|
||||||
|
| JMediaPlayer::Paused
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
|
if (mPendingMute != muted) {
|
||||||
|
mPendingMute = muted;
|
||||||
|
Q_EMIT mutedChanged(muted);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mMediaPlayer->setMuted(muted);
|
mMediaPlayer->setMuted(muted);
|
||||||
|
|
||||||
|
if (mPendingMute != -1) {
|
||||||
|
mPendingMute = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Q_EMIT mutedChanged(muted);
|
Q_EMIT mutedChanged(muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,10 +282,21 @@ const QIODevice *QAndroidMediaPlayerControl::mediaStream() const
|
|||||||
void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
|
void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
|
||||||
QIODevice *stream)
|
QIODevice *stream)
|
||||||
{
|
{
|
||||||
|
const bool reloading = (mMediaContent == mediaContent);
|
||||||
|
|
||||||
|
if (!reloading) {
|
||||||
mMediaContent = mediaContent;
|
mMediaContent = mediaContent;
|
||||||
mMediaStream = stream;
|
mMediaStream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
if (mVideoOutput && !mMediaPlayer->display()) {
|
mMediaPlayer->release();
|
||||||
|
|
||||||
|
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
|
// 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
|
// since it can cause problems on some hardware
|
||||||
mPendingSetMedia = true;
|
mPendingSetMedia = true;
|
||||||
@@ -229,68 +314,88 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
|
|||||||
mediaPath = url.toString();
|
mediaPath = url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mediaPath.isEmpty())
|
if (mVideoSize.isValid() && mVideoOutput)
|
||||||
mMediaPlayer->setDataSource(mediaPath);
|
mVideoOutput->setVideoSize(mVideoSize);
|
||||||
else
|
|
||||||
setMediaStatus(QMediaPlayer::NoMedia);
|
|
||||||
|
|
||||||
|
if (!mMediaPlayer->display() && mVideoOutput)
|
||||||
|
mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
|
||||||
|
mMediaPlayer->setDataSource(mediaPath);
|
||||||
|
mMediaPlayer->prepareAsync();
|
||||||
|
|
||||||
|
if (!reloading)
|
||||||
Q_EMIT mediaChanged(mMediaContent);
|
Q_EMIT mediaChanged(mMediaContent);
|
||||||
|
|
||||||
resetBufferingProgress();
|
resetBufferingProgress();
|
||||||
|
|
||||||
// reset some properties
|
|
||||||
setAudioAvailable(false);
|
|
||||||
setVideoAvailable(false);
|
|
||||||
setSeekable(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
|
void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
|
||||||
{
|
{
|
||||||
if (mVideoOutput)
|
if (mVideoOutput) {
|
||||||
|
mMediaPlayer->setDisplay(0);
|
||||||
mVideoOutput->stop();
|
mVideoOutput->stop();
|
||||||
|
mVideoOutput->reset();
|
||||||
|
}
|
||||||
|
|
||||||
mVideoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
|
mVideoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
|
||||||
|
|
||||||
if (mVideoOutput && !mMediaPlayer->display()) {
|
if (!mVideoOutput)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mVideoOutput->isReady())
|
if (mVideoOutput->isReady())
|
||||||
mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
|
mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
|
||||||
else
|
|
||||||
connect(videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
|
connect(videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::play()
|
void QAndroidMediaPlayerControl::play()
|
||||||
{
|
{
|
||||||
if (!mMediaPlayerReady) {
|
// We need to prepare the mediaplayer again.
|
||||||
mPendingState = QMediaPlayer::PlayingState;
|
if ((mState & JMediaPlayer::Stopped) && !mMediaContent.isNull()) {
|
||||||
if (mCurrentState == QMediaPlayer::StoppedState
|
setMedia(mMediaContent, mMediaStream);
|
||||||
&& !mMediaContent.isNull()
|
|
||||||
&& mCurrentMediaStatus != QMediaPlayer::LoadingMedia
|
|
||||||
&& !mPendingSetMedia) {
|
|
||||||
setMedia(mMediaContent, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setState(QMediaPlayer::PlayingState);
|
||||||
|
|
||||||
|
if ((mState & (JMediaPlayer::Prepared
|
||||||
|
| JMediaPlayer::Started
|
||||||
|
| JMediaPlayer::Paused
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
|
mPendingState = QMediaPlayer::PlayingState;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mMediaPlayer->play();
|
mMediaPlayer->play();
|
||||||
setState(QMediaPlayer::PlayingState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::pause()
|
void QAndroidMediaPlayerControl::pause()
|
||||||
{
|
{
|
||||||
if (!mMediaPlayerReady) {
|
setState(QMediaPlayer::PausedState);
|
||||||
|
|
||||||
|
if ((mState & (JMediaPlayer::Started
|
||||||
|
| JMediaPlayer::Paused
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
mPendingState = QMediaPlayer::PausedState;
|
mPendingState = QMediaPlayer::PausedState;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mMediaPlayer->pause();
|
mMediaPlayer->pause();
|
||||||
setState(QMediaPlayer::PausedState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::stop()
|
void QAndroidMediaPlayerControl::stop()
|
||||||
{
|
{
|
||||||
mMediaPlayer->stop();
|
|
||||||
setState(QMediaPlayer::StoppedState);
|
setState(QMediaPlayer::StoppedState);
|
||||||
|
|
||||||
|
if ((mState & (JMediaPlayer::Prepared
|
||||||
|
| JMediaPlayer::Started
|
||||||
|
| JMediaPlayer::Stopped
|
||||||
|
| JMediaPlayer::Paused
|
||||||
|
| JMediaPlayer::PlaybackCompleted)) == 0) {
|
||||||
|
if ((mState & (JMediaPlayer::Idle | JMediaPlayer::Uninitialized | JMediaPlayer::Error)) == 0)
|
||||||
|
mPendingState = QMediaPlayer::StoppedState;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMediaPlayer->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::onInfo(qint32 what, qint32 extra)
|
void QAndroidMediaPlayerControl::onInfo(qint32 what, qint32 extra)
|
||||||
@@ -310,7 +415,7 @@ void QAndroidMediaPlayerControl::onInfo(qint32 what, qint32 extra)
|
|||||||
setMediaStatus(QMediaPlayer::StalledMedia);
|
setMediaStatus(QMediaPlayer::StalledMedia);
|
||||||
break;
|
break;
|
||||||
case JMediaPlayer::MEDIA_INFO_BUFFERING_END:
|
case JMediaPlayer::MEDIA_INFO_BUFFERING_END:
|
||||||
setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia : QMediaPlayer::BufferingMedia);
|
if (mCurrentState != QMediaPlayer::StoppedState)
|
||||||
flushPendingStates();
|
flushPendingStates();
|
||||||
break;
|
break;
|
||||||
case JMediaPlayer::MEDIA_INFO_BAD_INTERLEAVING:
|
case JMediaPlayer::MEDIA_INFO_BAD_INTERLEAVING:
|
||||||
@@ -324,41 +429,6 @@ void QAndroidMediaPlayerControl::onInfo(qint32 what, qint32 extra)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::onMediaPlayerInfo(qint32 what, qint32 extra)
|
|
||||||
{
|
|
||||||
switch (what) {
|
|
||||||
case JMediaPlayer::MEDIA_PLAYER_INVALID_STATE:
|
|
||||||
setError(what, QStringLiteral("Error: Invalid state"));
|
|
||||||
break;
|
|
||||||
case JMediaPlayer::MEDIA_PLAYER_PREPARING:
|
|
||||||
setMediaStatus(QMediaPlayer::LoadingMedia);
|
|
||||||
setState(QMediaPlayer::StoppedState);
|
|
||||||
break;
|
|
||||||
case JMediaPlayer::MEDIA_PLAYER_READY:
|
|
||||||
setMediaStatus(QMediaPlayer::LoadedMedia);
|
|
||||||
if (mBuffering) {
|
|
||||||
setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia
|
|
||||||
: QMediaPlayer::BufferingMedia);
|
|
||||||
} else {
|
|
||||||
onBufferChanged(100);
|
|
||||||
}
|
|
||||||
setAudioAvailable(true);
|
|
||||||
mMediaPlayerReady = true;
|
|
||||||
flushPendingStates();
|
|
||||||
break;
|
|
||||||
case JMediaPlayer::MEDIA_PLAYER_DURATION:
|
|
||||||
Q_EMIT durationChanged(extra);
|
|
||||||
break;
|
|
||||||
case JMediaPlayer::MEDIA_PLAYER_PROGRESS:
|
|
||||||
Q_EMIT positionChanged(extra);
|
|
||||||
break;
|
|
||||||
case JMediaPlayer::MEDIA_PLAYER_FINISHED:
|
|
||||||
stop();
|
|
||||||
setMediaStatus(QMediaPlayer::EndOfMedia);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::onError(qint32 what, qint32 extra)
|
void QAndroidMediaPlayerControl::onError(qint32 what, qint32 extra)
|
||||||
{
|
{
|
||||||
QString errorString;
|
QString errorString;
|
||||||
@@ -372,6 +442,10 @@ void QAndroidMediaPlayerControl::onError(qint32 what, qint32 extra)
|
|||||||
errorString = QLatin1String("Error: Server died");
|
errorString = QLatin1String("Error: Server died");
|
||||||
error = QMediaPlayer::ServiceMissingError;
|
error = QMediaPlayer::ServiceMissingError;
|
||||||
break;
|
break;
|
||||||
|
case JMediaPlayer::MEDIA_ERROR_INVALID_STATE:
|
||||||
|
errorString = QLatin1String("Error: Invalid state");
|
||||||
|
error = QMediaPlayer::ServiceMissingError;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (extra) {
|
switch (extra) {
|
||||||
@@ -398,12 +472,16 @@ void QAndroidMediaPlayerControl::onError(qint32 what, qint32 extra)
|
|||||||
error = QMediaPlayer::FormatError;
|
error = QMediaPlayer::FormatError;
|
||||||
setMediaStatus(QMediaPlayer::InvalidMedia);
|
setMediaStatus(QMediaPlayer::InvalidMedia);
|
||||||
break;
|
break;
|
||||||
|
case JMediaPlayer::MEDIA_ERROR_BAD_THINGS_ARE_GOING_TO_HAPPEN:
|
||||||
|
errorString += QLatin1String(" (Unknown error/Insufficient resources)");
|
||||||
|
error = QMediaPlayer::ServiceMissingError;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setError(error, errorString);
|
Q_EMIT QMediaPlayerControl::error(error, errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::onBufferChanged(qint32 percent)
|
void QAndroidMediaPlayerControl::onBufferingChanged(qint32 percent)
|
||||||
{
|
{
|
||||||
mBuffering = percent != 100;
|
mBuffering = percent != 100;
|
||||||
mBufferPercent = percent;
|
mBufferPercent = percent;
|
||||||
@@ -411,8 +489,8 @@ void QAndroidMediaPlayerControl::onBufferChanged(qint32 percent)
|
|||||||
|
|
||||||
updateAvailablePlaybackRanges();
|
updateAvailablePlaybackRanges();
|
||||||
|
|
||||||
if (mBufferPercent == 100)
|
if (mCurrentState != QMediaPlayer::StoppedState)
|
||||||
setMediaStatus(QMediaPlayer::BufferedMedia);
|
setMediaStatus(mBuffering ? QMediaPlayer::BufferingMedia : QMediaPlayer::BufferedMedia);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::onVideoSizeChanged(qint32 width, qint32 height)
|
void QAndroidMediaPlayerControl::onVideoSizeChanged(qint32 width, qint32 height)
|
||||||
@@ -429,27 +507,98 @@ void QAndroidMediaPlayerControl::onVideoSizeChanged(qint32 width, qint32 height)
|
|||||||
mVideoOutput->setVideoSize(mVideoSize);
|
mVideoOutput->setVideoSize(mVideoSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QAndroidMediaPlayerControl::onStateChanged(qint32 state)
|
||||||
|
{
|
||||||
|
// If reloading, don't report state changes unless the new state is Prepared or Error.
|
||||||
|
if ((mState & JMediaPlayer::Stopped) && !(state & (JMediaPlayer::Prepared | JMediaPlayer::Error)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mState = state;
|
||||||
|
switch (mState) {
|
||||||
|
case JMediaPlayer::Idle:
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Initialized:
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Preparing:
|
||||||
|
setMediaStatus(QMediaPlayer::LoadingMedia);
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Prepared:
|
||||||
|
setMediaStatus(QMediaPlayer::LoadedMedia);
|
||||||
|
if (mBuffering) {
|
||||||
|
setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia
|
||||||
|
: QMediaPlayer::BufferingMedia);
|
||||||
|
} else {
|
||||||
|
onBufferingChanged(100);
|
||||||
|
}
|
||||||
|
setAudioAvailable(true);
|
||||||
|
flushPendingStates();
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Started:
|
||||||
|
setState(QMediaPlayer::PlayingState);
|
||||||
|
if (mBuffering) {
|
||||||
|
setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia
|
||||||
|
: QMediaPlayer::BufferingMedia);
|
||||||
|
} else {
|
||||||
|
setMediaStatus(QMediaPlayer::BufferedMedia);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Paused:
|
||||||
|
setState(QMediaPlayer::PausedState);
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Error:
|
||||||
|
setState(QMediaPlayer::StoppedState);
|
||||||
|
setMediaStatus(QMediaPlayer::UnknownMediaStatus);
|
||||||
|
mMediaPlayer->release();
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Stopped:
|
||||||
|
setState(QMediaPlayer::StoppedState);
|
||||||
|
setMediaStatus(QMediaPlayer::LoadedMedia);
|
||||||
|
setPosition(0);
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::PlaybackCompleted:
|
||||||
|
setState(QMediaPlayer::StoppedState);
|
||||||
|
setPosition(0);
|
||||||
|
setMediaStatus(QMediaPlayer::EndOfMedia);
|
||||||
|
break;
|
||||||
|
case JMediaPlayer::Uninitialized:
|
||||||
|
// reset some properties
|
||||||
|
resetBufferingProgress();
|
||||||
|
mPendingPosition = -1;
|
||||||
|
mPendingSetMedia = false;
|
||||||
|
mPendingState = -1;
|
||||||
|
|
||||||
|
setAudioAvailable(false);
|
||||||
|
setVideoAvailable(false);
|
||||||
|
setSeekable(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mState & (JMediaPlayer::Stopped | JMediaPlayer::Uninitialized)) != 0) {
|
||||||
|
mMediaPlayer->setDisplay(0);
|
||||||
|
if (mVideoOutput) {
|
||||||
|
mVideoOutput->stop();
|
||||||
|
mVideoOutput->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::onVideoOutputReady(bool ready)
|
void QAndroidMediaPlayerControl::onVideoOutputReady(bool ready)
|
||||||
{
|
{
|
||||||
if (!mMediaPlayer->display() && mVideoOutput && ready) {
|
if (!mMediaPlayer->display() && mVideoOutput && ready)
|
||||||
mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
|
mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
|
||||||
|
|
||||||
flushPendingStates();
|
flushPendingStates();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::setState(QMediaPlayer::State state)
|
void QAndroidMediaPlayerControl::setState(QMediaPlayer::State state)
|
||||||
{
|
{
|
||||||
if (mCurrentState == state)
|
if (mCurrentState == state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (state == QMediaPlayer::StoppedState) {
|
if (mCurrentState == QMediaPlayer::StoppedState && state == QMediaPlayer::PausedState)
|
||||||
if (mVideoOutput)
|
return;
|
||||||
mVideoOutput->stop();
|
|
||||||
resetBufferingProgress();
|
|
||||||
mMediaPlayerReady = false;
|
|
||||||
mPendingPosition = -1;
|
|
||||||
Q_EMIT positionChanged(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
mCurrentState = state;
|
mCurrentState = state;
|
||||||
Q_EMIT stateChanged(mCurrentState);
|
Q_EMIT stateChanged(mCurrentState);
|
||||||
@@ -463,17 +612,13 @@ void QAndroidMediaPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus 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)
|
||||||
|
Q_EMIT durationChanged(duration());
|
||||||
|
|
||||||
mCurrentMediaStatus = status;
|
mCurrentMediaStatus = status;
|
||||||
Q_EMIT mediaStatusChanged(mCurrentMediaStatus);
|
Q_EMIT mediaStatusChanged(mCurrentMediaStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::setError(int error,
|
|
||||||
const QString &errorString)
|
|
||||||
{
|
|
||||||
setState(QMediaPlayer::StoppedState);
|
|
||||||
Q_EMIT QMediaPlayerControl::error(error, errorString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QAndroidMediaPlayerControl::setSeekable(bool seekable)
|
void QAndroidMediaPlayerControl::setSeekable(bool seekable)
|
||||||
{
|
{
|
||||||
if (mSeekable == seekable)
|
if (mSeekable == seekable)
|
||||||
@@ -515,15 +660,23 @@ void QAndroidMediaPlayerControl::resetBufferingProgress()
|
|||||||
void QAndroidMediaPlayerControl::flushPendingStates()
|
void QAndroidMediaPlayerControl::flushPendingStates()
|
||||||
{
|
{
|
||||||
if (mPendingSetMedia) {
|
if (mPendingSetMedia) {
|
||||||
setMedia(mMediaContent, 0);
|
|
||||||
mPendingSetMedia = false;
|
mPendingSetMedia = false;
|
||||||
|
setMedia(mMediaContent, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mPendingState) {
|
const int newState = mPendingState;
|
||||||
case QMediaPlayer::PlayingState:
|
mPendingState = -1;
|
||||||
if (mPendingPosition > -1)
|
|
||||||
|
if (mPendingPosition != -1)
|
||||||
setPosition(mPendingPosition);
|
setPosition(mPendingPosition);
|
||||||
|
if (mPendingVolume != -1)
|
||||||
|
setVolume(mPendingVolume);
|
||||||
|
if (mPendingMute != -1)
|
||||||
|
setMuted((mPendingMute == 1));
|
||||||
|
|
||||||
|
switch (newState) {
|
||||||
|
case QMediaPlayer::PlayingState:
|
||||||
play();
|
play();
|
||||||
break;
|
break;
|
||||||
case QMediaPlayer::PausedState:
|
case QMediaPlayer::PausedState:
|
||||||
@@ -532,6 +685,8 @@ void QAndroidMediaPlayerControl::flushPendingStates()
|
|||||||
case QMediaPlayer::StoppedState:
|
case QMediaPlayer::StoppedState:
|
||||||
stop();
|
stop();
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,9 +93,9 @@ private Q_SLOTS:
|
|||||||
void onVideoOutputReady(bool ready);
|
void onVideoOutputReady(bool ready);
|
||||||
void onError(qint32 what, qint32 extra);
|
void onError(qint32 what, qint32 extra);
|
||||||
void onInfo(qint32 what, qint32 extra);
|
void onInfo(qint32 what, qint32 extra);
|
||||||
void onMediaPlayerInfo(qint32 what, qint32 extra);
|
void onBufferingChanged(qint32 percent);
|
||||||
void onBufferChanged(qint32 percent);
|
|
||||||
void onVideoSizeChanged(qint32 width, qint32 height);
|
void onVideoSizeChanged(qint32 width, qint32 height);
|
||||||
|
void onStateChanged(qint32 state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JMediaPlayer *mMediaPlayer;
|
JMediaPlayer *mMediaPlayer;
|
||||||
@@ -111,15 +111,16 @@ private:
|
|||||||
QSize mVideoSize;
|
QSize mVideoSize;
|
||||||
bool mBuffering;
|
bool mBuffering;
|
||||||
QMediaTimeRange mAvailablePlaybackRange;
|
QMediaTimeRange mAvailablePlaybackRange;
|
||||||
bool mMediaPlayerReady;
|
int mState;
|
||||||
QMediaPlayer::State mPendingState;
|
int mPendingState;
|
||||||
qint64 mPendingPosition;
|
qint64 mPendingPosition;
|
||||||
bool mPendingSetMedia;
|
bool mPendingSetMedia;
|
||||||
|
int mPendingVolume;
|
||||||
|
int mPendingMute;
|
||||||
QScopedPointer<QTemporaryFile> mTempFile;
|
QScopedPointer<QTemporaryFile> mTempFile;
|
||||||
|
|
||||||
void setState(QMediaPlayer::State state);
|
void setState(QMediaPlayer::State state);
|
||||||
void setMediaStatus(QMediaPlayer::MediaStatus status);
|
void setMediaStatus(QMediaPlayer::MediaStatus status);
|
||||||
void setError(int error, const QString &errorString);
|
|
||||||
void setSeekable(bool seekable);
|
void setSeekable(bool seekable);
|
||||||
void setAudioAvailable(bool available);
|
void setAudioAvailable(bool available);
|
||||||
void setVideoAvailable(bool available);
|
void setVideoAvailable(bool available);
|
||||||
|
|||||||
@@ -46,135 +46,113 @@
|
|||||||
#include <QtCore/private/qjnihelpers_p.h>
|
#include <QtCore/private/qjnihelpers_p.h>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
|
||||||
namespace {
|
static jclass mediaPlayerClass = Q_NULLPTR;
|
||||||
|
typedef QMap<jlong, JMediaPlayer *> MediaPlayerMap;
|
||||||
jclass mediaPlayerClass = 0;
|
Q_GLOBAL_STATIC(MediaPlayerMap, mediaPlayers)
|
||||||
|
|
||||||
QMap<jlong, JMediaPlayer *> mplayers;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
bool JMediaPlayer::mActivitySet = false;
|
|
||||||
|
|
||||||
JMediaPlayer::JMediaPlayer()
|
JMediaPlayer::JMediaPlayer()
|
||||||
: QObject()
|
: QObject()
|
||||||
, QJNIObjectPrivate(mediaPlayerClass, "(J)V", reinterpret_cast<jlong>(this))
|
|
||||||
, mId(reinterpret_cast<jlong>(this))
|
|
||||||
, mDisplay(0)
|
|
||||||
{
|
{
|
||||||
mplayers.insert(mId, this);
|
|
||||||
|
|
||||||
if (!mActivitySet) {
|
const jlong id = reinterpret_cast<jlong>(this);
|
||||||
QJNIObjectPrivate::callStaticMethod<void>(mediaPlayerClass,
|
mMediaPlayer = QJNIObjectPrivate(mediaPlayerClass,
|
||||||
"setActivity",
|
"(Landroid/app/Activity;J)V",
|
||||||
"(Landroid/app/Activity;)V",
|
QtAndroidPrivate::activity(),
|
||||||
QtAndroidPrivate::activity());
|
id);
|
||||||
mActivitySet = true;
|
(*mediaPlayers)[id] = this;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JMediaPlayer::~JMediaPlayer()
|
JMediaPlayer::~JMediaPlayer()
|
||||||
{
|
{
|
||||||
mplayers.remove(mId);
|
mediaPlayers->remove(reinterpret_cast<jlong>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::release()
|
void JMediaPlayer::release()
|
||||||
{
|
{
|
||||||
callMethod<void>("release");
|
mMediaPlayer.callMethod<void>("release");
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::onError(qint32 what, qint32 extra)
|
void JMediaPlayer::reset()
|
||||||
{
|
{
|
||||||
Q_EMIT error(what, extra);
|
mMediaPlayer.callMethod<void>("reset");
|
||||||
}
|
|
||||||
|
|
||||||
void JMediaPlayer::onBufferingUpdate(qint32 percent)
|
|
||||||
{
|
|
||||||
Q_EMIT bufferingUpdate(percent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JMediaPlayer::onInfo(qint32 what, qint32 extra)
|
|
||||||
{
|
|
||||||
Q_EMIT info(what, extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JMediaPlayer::onMediaPlayerInfo(qint32 what, qint32 extra)
|
|
||||||
{
|
|
||||||
Q_EMIT mediaPlayerInfo(what, extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JMediaPlayer::onVideoSizeChanged(qint32 width, qint32 height)
|
|
||||||
{
|
|
||||||
Q_EMIT videoSizeChanged(width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int JMediaPlayer::getCurrentPosition()
|
int JMediaPlayer::getCurrentPosition()
|
||||||
{
|
{
|
||||||
return callMethod<jint>("getCurrentPosition");
|
return mMediaPlayer.callMethod<jint>("getCurrentPosition");
|
||||||
}
|
}
|
||||||
|
|
||||||
int JMediaPlayer::getDuration()
|
int JMediaPlayer::getDuration()
|
||||||
{
|
{
|
||||||
return callMethod<jint>("getDuration");
|
return mMediaPlayer.callMethod<jint>("getDuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JMediaPlayer::isPlaying()
|
bool JMediaPlayer::isPlaying()
|
||||||
{
|
{
|
||||||
return callMethod<jboolean>("isPlaying");
|
return mMediaPlayer.callMethod<jboolean>("isPlaying");
|
||||||
}
|
}
|
||||||
|
|
||||||
int JMediaPlayer::volume()
|
int JMediaPlayer::volume()
|
||||||
{
|
{
|
||||||
return callMethod<jint>("getVolume");
|
return mMediaPlayer.callMethod<jint>("getVolume");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JMediaPlayer::isMuted()
|
bool JMediaPlayer::isMuted()
|
||||||
{
|
{
|
||||||
return callMethod<jboolean>("isMuted");
|
return mMediaPlayer.callMethod<jboolean>("isMuted");
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject JMediaPlayer::display()
|
||||||
|
{
|
||||||
|
return mMediaPlayer.callObjectMethod("display", "()Landroid/view/SurfaceHolder;").object();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::play()
|
void JMediaPlayer::play()
|
||||||
{
|
{
|
||||||
callMethod<void>("start");
|
mMediaPlayer.callMethod<void>("start");
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::pause()
|
void JMediaPlayer::pause()
|
||||||
{
|
{
|
||||||
callMethod<void>("pause");
|
mMediaPlayer.callMethod<void>("pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::stop()
|
void JMediaPlayer::stop()
|
||||||
{
|
{
|
||||||
callMethod<void>("stop");
|
mMediaPlayer.callMethod<void>("stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::seekTo(qint32 msec)
|
void JMediaPlayer::seekTo(qint32 msec)
|
||||||
{
|
{
|
||||||
callMethod<void>("seekTo", "(I)V", jint(msec));
|
mMediaPlayer.callMethod<void>("seekTo", "(I)V", jint(msec));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::setMuted(bool mute)
|
void JMediaPlayer::setMuted(bool mute)
|
||||||
{
|
{
|
||||||
callMethod<void>("mute", "(Z)V", jboolean(mute));
|
mMediaPlayer.callMethod<void>("mute", "(Z)V", jboolean(mute));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::setDataSource(const QString &path)
|
void JMediaPlayer::setDataSource(const QString &path)
|
||||||
{
|
{
|
||||||
QJNIObjectPrivate string = QJNIObjectPrivate::fromString(path);
|
QJNIObjectPrivate string = QJNIObjectPrivate::fromString(path);
|
||||||
callMethod<void>("setMediaPath", "(Ljava/lang/String;)V", string.object());
|
mMediaPlayer.callMethod<void>("setDataSource", "(Ljava/lang/String;)V", string.object());
|
||||||
|
}
|
||||||
|
|
||||||
|
void JMediaPlayer::prepareAsync()
|
||||||
|
{
|
||||||
|
mMediaPlayer.callMethod<void>("prepareAsync");
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::setVolume(int volume)
|
void JMediaPlayer::setVolume(int volume)
|
||||||
{
|
{
|
||||||
callMethod<void>("setVolume", "(I)V", jint(volume));
|
mMediaPlayer.callMethod<void>("setVolume", "(I)V", jint(volume));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMediaPlayer::setDisplay(jobject surfaceHolder)
|
void JMediaPlayer::setDisplay(jobject surfaceHolder)
|
||||||
{
|
{
|
||||||
mDisplay = surfaceHolder;
|
mMediaPlayer.callMethod<void>("setDisplay", "(Landroid/view/SurfaceHolder;)V", surfaceHolder);
|
||||||
callMethod<void>("setDisplay", "(Landroid/view/SurfaceHolder;)V", mDisplay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
@@ -183,44 +161,66 @@ static void onErrorNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlon
|
|||||||
{
|
{
|
||||||
Q_UNUSED(env);
|
Q_UNUSED(env);
|
||||||
Q_UNUSED(thiz);
|
Q_UNUSED(thiz);
|
||||||
JMediaPlayer *const mp = mplayers[id];
|
JMediaPlayer *const mp = (*mediaPlayers)[id];
|
||||||
if (!mp)
|
if (!mp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mp->onError(what, extra);
|
Q_EMIT mp->error(what, extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onBufferingUpdateNative(JNIEnv *env, jobject thiz, jint percent, jlong id)
|
static void onBufferingUpdateNative(JNIEnv *env, jobject thiz, jint percent, jlong id)
|
||||||
{
|
{
|
||||||
Q_UNUSED(env);
|
Q_UNUSED(env);
|
||||||
Q_UNUSED(thiz);
|
Q_UNUSED(thiz);
|
||||||
JMediaPlayer *const mp = mplayers[id];
|
JMediaPlayer *const mp = (*mediaPlayers)[id];
|
||||||
if (!mp)
|
if (!mp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mp->onBufferingUpdate(percent);
|
Q_EMIT mp->bufferingChanged(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onProgressUpdateNative(JNIEnv *env, jobject thiz, jint progress, jlong id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(env);
|
||||||
|
Q_UNUSED(thiz);
|
||||||
|
JMediaPlayer *const mp = (*mediaPlayers)[id];
|
||||||
|
if (!mp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Q_EMIT mp->progressChanged(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onDurationChangedNative(JNIEnv *env, jobject thiz, jint duration, jlong id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(env);
|
||||||
|
Q_UNUSED(thiz);
|
||||||
|
JMediaPlayer *const mp = (*mediaPlayers)[id];
|
||||||
|
if (!mp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Q_EMIT mp->durationChanged(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onInfoNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
|
static void onInfoNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
|
||||||
{
|
{
|
||||||
Q_UNUSED(env);
|
Q_UNUSED(env);
|
||||||
Q_UNUSED(thiz);
|
Q_UNUSED(thiz);
|
||||||
JMediaPlayer *const mp = mplayers[id];
|
JMediaPlayer *const mp = (*mediaPlayers)[id];
|
||||||
if (!mp)
|
if (!mp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mp->onInfo(what, extra);
|
Q_EMIT mp->info(what, extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onMediaPlayerInfoNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
|
static void onStateChangedNative(JNIEnv *env, jobject thiz, jint state, jlong id)
|
||||||
{
|
{
|
||||||
Q_UNUSED(env);
|
Q_UNUSED(env);
|
||||||
Q_UNUSED(thiz);
|
Q_UNUSED(thiz);
|
||||||
JMediaPlayer *const mp = mplayers[id];
|
JMediaPlayer *const mp = (*mediaPlayers)[id];
|
||||||
if (!mp)
|
if (!mp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mp->onMediaPlayerInfo(what, extra);
|
Q_EMIT mp->stateChanged(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onVideoSizeChangedNative(JNIEnv *env,
|
static void onVideoSizeChangedNative(JNIEnv *env,
|
||||||
@@ -231,11 +231,11 @@ static void onVideoSizeChangedNative(JNIEnv *env,
|
|||||||
{
|
{
|
||||||
Q_UNUSED(env);
|
Q_UNUSED(env);
|
||||||
Q_UNUSED(thiz);
|
Q_UNUSED(thiz);
|
||||||
JMediaPlayer *const mp = mplayers[id];
|
JMediaPlayer *const mp = (*mediaPlayers)[id];
|
||||||
if (!mp)
|
if (!mp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mp->onVideoSizeChanged(width, height);
|
Q_EMIT mp->videoSizeChanged(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@@ -250,9 +250,11 @@ bool JMediaPlayer::initJNI(JNIEnv *env)
|
|||||||
JNINativeMethod methods[] = {
|
JNINativeMethod methods[] = {
|
||||||
{"onErrorNative", "(IIJ)V", reinterpret_cast<void *>(onErrorNative)},
|
{"onErrorNative", "(IIJ)V", reinterpret_cast<void *>(onErrorNative)},
|
||||||
{"onBufferingUpdateNative", "(IJ)V", reinterpret_cast<void *>(onBufferingUpdateNative)},
|
{"onBufferingUpdateNative", "(IJ)V", reinterpret_cast<void *>(onBufferingUpdateNative)},
|
||||||
|
{"onProgressUpdateNative", "(IJ)V", reinterpret_cast<void *>(onProgressUpdateNative)},
|
||||||
|
{"onDurationChangedNative", "(IJ)V", reinterpret_cast<void *>(onDurationChangedNative)},
|
||||||
{"onInfoNative", "(IIJ)V", reinterpret_cast<void *>(onInfoNative)},
|
{"onInfoNative", "(IIJ)V", reinterpret_cast<void *>(onInfoNative)},
|
||||||
{"onMediaPlayerInfoNative", "(IIJ)V", reinterpret_cast<void *>(onMediaPlayerInfoNative)},
|
{"onVideoSizeChangedNative", "(IIJ)V", reinterpret_cast<void *>(onVideoSizeChangedNative)},
|
||||||
{"onVideoSizeChangedNative", "(IIJ)V", reinterpret_cast<void *>(onVideoSizeChangedNative)}
|
{"onStateChangedNative", "(IJ)V", reinterpret_cast<void *>(onStateChangedNative)}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (env->RegisterNatives(mediaPlayerClass,
|
if (env->RegisterNatives(mediaPlayerClass,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class JMediaPlayer : public QObject, public QJNIObjectPrivate
|
class JMediaPlayer : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -59,12 +59,14 @@ public:
|
|||||||
// What
|
// What
|
||||||
MEDIA_ERROR_UNKNOWN = 1,
|
MEDIA_ERROR_UNKNOWN = 1,
|
||||||
MEDIA_ERROR_SERVER_DIED = 100,
|
MEDIA_ERROR_SERVER_DIED = 100,
|
||||||
|
MEDIA_ERROR_INVALID_STATE = -38, // Undocumented
|
||||||
// Extra
|
// Extra
|
||||||
MEDIA_ERROR_IO = -1004,
|
MEDIA_ERROR_IO = -1004,
|
||||||
MEDIA_ERROR_MALFORMED = -1007,
|
MEDIA_ERROR_MALFORMED = -1007,
|
||||||
MEDIA_ERROR_UNSUPPORTED = -1010,
|
MEDIA_ERROR_UNSUPPORTED = -1010,
|
||||||
MEDIA_ERROR_TIMED_OUT = -110,
|
MEDIA_ERROR_TIMED_OUT = -110,
|
||||||
MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200
|
MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
|
||||||
|
MEDIA_ERROR_BAD_THINGS_ARE_GOING_TO_HAPPEN = -2147483648 // Undocumented
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MediaInfo
|
enum MediaInfo
|
||||||
@@ -79,24 +81,29 @@ public:
|
|||||||
MEDIA_INFO_METADATA_UPDATE = 802
|
MEDIA_INFO_METADATA_UPDATE = 802
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MediaPlayerInfo
|
enum MediaPlayerState
|
||||||
{
|
{
|
||||||
MEDIA_PLAYER_INVALID_STATE = 1,
|
Uninitialized = 0x1, /* End */
|
||||||
MEDIA_PLAYER_PREPARING = 2,
|
Idle = 0x2,
|
||||||
MEDIA_PLAYER_READY = 3,
|
Preparing = 0x4,
|
||||||
MEDIA_PLAYER_DURATION = 4,
|
Prepared = 0x8,
|
||||||
MEDIA_PLAYER_PROGRESS = 5,
|
Initialized = 0x10,
|
||||||
MEDIA_PLAYER_FINISHED = 6
|
Started = 0x20,
|
||||||
|
Stopped = 0x40,
|
||||||
|
Paused = 0x80,
|
||||||
|
PlaybackCompleted = 0x100,
|
||||||
|
Error = 0x200
|
||||||
};
|
};
|
||||||
|
|
||||||
void release();
|
void release();
|
||||||
|
void reset();
|
||||||
|
|
||||||
int getCurrentPosition();
|
int getCurrentPosition();
|
||||||
int getDuration();
|
int getDuration();
|
||||||
bool isPlaying();
|
bool isPlaying();
|
||||||
int volume();
|
int volume();
|
||||||
bool isMuted();
|
bool isMuted();
|
||||||
jobject display() { return mDisplay; }
|
jobject display();
|
||||||
|
|
||||||
void play();
|
void play();
|
||||||
void pause();
|
void pause();
|
||||||
@@ -104,30 +111,23 @@ public:
|
|||||||
void seekTo(qint32 msec);
|
void seekTo(qint32 msec);
|
||||||
void setMuted(bool mute);
|
void setMuted(bool mute);
|
||||||
void setDataSource(const QString &path);
|
void setDataSource(const QString &path);
|
||||||
|
void prepareAsync();
|
||||||
void setVolume(int volume);
|
void setVolume(int volume);
|
||||||
void setDisplay(jobject surfaceHolder);
|
void setDisplay(jobject surfaceHolder);
|
||||||
|
|
||||||
void onError(qint32 what, qint32 extra);
|
|
||||||
void onBufferingUpdate(qint32 percent);
|
|
||||||
void onInfo(qint32 what, qint32 extra);
|
|
||||||
void onMediaPlayerInfo(qint32 what, qint32 extra);
|
|
||||||
void onVideoSizeChanged(qint32 width, qint32 height);
|
|
||||||
|
|
||||||
static bool initJNI(JNIEnv *env);
|
static bool initJNI(JNIEnv *env);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void error(qint32 what, qint32 extra);
|
void error(qint32 what, qint32 extra);
|
||||||
void bufferingUpdate(qint32 percent);
|
void bufferingChanged(qint32 percent);
|
||||||
void completion();
|
void durationChanged(qint64 duration);
|
||||||
|
void progressChanged(qint64 progress);
|
||||||
|
void stateChanged(qint32 state);
|
||||||
void info(qint32 what, qint32 extra);
|
void info(qint32 what, qint32 extra);
|
||||||
void mediaPlayerInfo(qint32 what, qint32 extra);
|
|
||||||
void videoSizeChanged(qint32 width, qint32 height);
|
void videoSizeChanged(qint32 width, qint32 height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
jlong mId;
|
QJNIObjectPrivate mMediaPlayer;
|
||||||
jobject mDisplay;
|
|
||||||
|
|
||||||
static bool mActivitySet;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
Reference in New Issue
Block a user