Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 903eee45 authored by huiy's avatar huiy Committed by Steve Kondik
Browse files

Add 2 APIs (suspend and resume) in MediaPlayer

- API:suspend() will just pause the player and release all the decoders
- instead of release the whole player
- API:resume() will just init the decoders again
- Add a check in onVideoEvent()
- to make sure the first seek operation will seek the next i-frame

Change-Id: Ia4716f7fb3a412eb19c6ded9c0f3056d0490546c

Implement the suspend/resume operation in VideoView

- Using the new APIs in Mediaplayer
  to implement the suspend/resume operation in VideoView
- Add a new status "SUSPENDED"

Change-Id: I00f9daa2d34b3b125b8c3b968bc581708ab2cdf4

HTML5 VideoView change to use the new APIs: suspend/resume

- While suspend and resume, using the new APIs in Mediaplayer

Change-Id: I8530b533501607f681145853d7923fdf2009150b
parent 9a20a522
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -54,6 +54,9 @@ public class HTML5VideoInline extends HTML5VideoView{

    @Override
    public void decideDisplayMode() {
        if (mCurrentState == STATE_SUSPENDED) {
            mSurfaceTexture = null;
        }
        SurfaceTexture surfaceTexture = getSurfaceTexture(getVideoLayerId());
        Surface surface = new Surface(surfaceTexture);
        mPlayer.setSurface(surface);
+59 −3
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
    static final int STATE_PLAYING            = 3;
    static final int STATE_RESETTED           = 4;
    static final int STATE_RELEASED           = 5;
    static final int STATE_SUSPENDED          = 6;

    protected HTML5VideoViewProxy mProxy;

@@ -108,6 +109,34 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
        }
    }

    public boolean suspend() {
        if (mPlayer.suspend()) {
            // Delete the Timer to stop it since there is no stop call.
            if (mTimer != null) {
                mTimer.purge();
                mTimer.cancel();
                mTimer = null;
            }
            return true;
        }
        return false;
    }

    public boolean resume() {
        if (mPlayer.resume()) {
            mCurrentState = STATE_PREPARED;
            if (mSaveSeekTime > 0) {
                seekTo(mSaveSeekTime);
            }

            if (mProxy != null) {
                mProxy.resume(mPlayer);
            }
            return true;
        }
        return false;
    }

    public int getDuration() {
        if (mCurrentState == STATE_PREPARED) {
            return mPlayer.getDuration();
@@ -124,14 +153,14 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
    }

    public void seekTo(int pos) {
        if (mCurrentState == STATE_PREPARED)
        if (mCurrentState == STATE_PREPARED || mCurrentState == STATE_SUSPENDED)
            mPlayer.seekTo(pos);
        else
            mSaveSeekTime = pos;
    }

    public boolean isPlaying() {
        if (mCurrentState == STATE_PREPARED) {
        if (mCurrentState == STATE_PREPARED || mCurrentState == STATE_SUSPENDED) {
            return mPlayer.isPlaying();
        } else {
            return false;
@@ -246,8 +275,15 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
            // don't need to call prepare again, we just need to call onPrepared
            // to refresh the state here.
            if (mCurrentState >= STATE_PREPARED) {
                if (mCurrentState == STATE_SUSPENDED) {
                    if (!resume()) {
                        mSkipPrepare = false;
                        prepareDataCommon(proxy);
                    }
                } else {
                    onPrepared(mPlayer);
                }
            }
            mSkipPrepare = false;
        }
    }
@@ -301,6 +337,10 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {

    @Override
    public void onPrepared(MediaPlayer mp) {
        if (mCurrentState ==  STATE_SUSPENDED) {
            suspend();
            return;
        }
        mCurrentState = STATE_PREPARED;
        seekTo(mSaveSeekTime);
        if (mProxy != null) {
@@ -320,6 +360,19 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
        }
    }

    // Suspend the player and update the play/pause button
    public void suspendAndDispatch(HTML5VideoViewProxy proxy) {
        if (suspend()) {
            mCurrentState = STATE_SUSPENDED;
            mSkipPrepare = true;
            if (proxy != null) {
                proxy.dispatchOnPaused();
            }
        } else {
            release();
        }
    }

    // Below are functions that are different implementation on inline and full-
    // screen mode. Some are specific to one type, but currently are called
    // directly from the proxy.
@@ -380,4 +433,7 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
    public void showControllerInFullScreen() {
    }

    public boolean isSuspended() {
        return (mCurrentState == STATE_SUSPENDED);
    }
}
+25 −1
Original line number Diff line number Diff line
@@ -130,13 +130,20 @@ class HTML5VideoViewProxy extends Handler
            }
        }

        // When a WebView is paused, we also want to pause the video in it.
        // When a WebView is paused, we also want to pause the video in it. (won't be used any more, use suspendAndDispatch())
        public static void pauseAndDispatch() {
            if (mHTML5VideoView != null) {
                mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
            }
        }

        // When a WebView is paused, we need to suspend the player (release the decoder only)
        public static void suspendAndDispatch() {
            if (mHTML5VideoView != null) {
                mHTML5VideoView.suspendAndDispatch(mCurrentProxy);
            }
        }

        public static void enterFullScreenVideo(int layerId, String url,
                HTML5VideoViewProxy proxy, WebViewClassic webView) {
                // Save the inline video info and inherit it in the full screen
@@ -247,6 +254,9 @@ class HTML5VideoViewProxy extends Handler
            if (mCurrentProxy == proxy) {
                // Here, we handle the case when we keep playing with one video
                if (!mHTML5VideoView.isPlaying()) {
                    if (mHTML5VideoView.isSuspended()) {
                        mHTML5VideoView.prepareDataAndDisplayMode(proxy);
                    }
                    mHTML5VideoView.seekTo(time);
                    mHTML5VideoView.start();
                }
@@ -314,6 +324,16 @@ class HTML5VideoViewProxy extends Handler
        mWebCoreHandler.sendMessage(msg);
    }

    public void resume(MediaPlayer mp) {
        Message msg = Message.obtain(mWebCoreHandler, PREPARED);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("dur", new Integer(mp.getDuration()));
        map.put("width", new Integer(mp.getVideoWidth()));
        map.put("height", new Integer(mp.getVideoHeight()));
        msg.obj = map;
        mWebCoreHandler.sendMessage(msg);
    }

    // MediaPlayer.OnCompletionListener;
    @Override
    public void onCompletion(MediaPlayer mp) {
@@ -762,6 +782,10 @@ class HTML5VideoViewProxy extends Handler
        VideoPlayer.pauseAndDispatch();
    }

    public void suspendAndDispatch() {
        VideoPlayer.suspendAndDispatch();
    }

    public void enterFullScreenVideo(int layerId, String url) {
        VideoPlayer.enterFullScreenVideo(layerId, url, this, mWebView);
    }
+2 −1
Original line number Diff line number Diff line
@@ -3520,7 +3520,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
            // We want to pause the current playing video when switching out
            // from the current WebView/tab.
            if (mHTML5VideoViewProxy != null) {
                mHTML5VideoViewProxy.pauseAndDispatch();
                // Use suspend instead of pause to release the decoder
                mHTML5VideoViewProxy.suspendAndDispatch();
            }
            if (mNativeClass != 0) {
                nativeSetPauseDrawing(mNativeClass, true);
+73 −2
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
    private static final int STATE_PLAYING            = 3;
    private static final int STATE_PAUSED             = 4;
    private static final int STATE_PLAYBACK_COMPLETED = 5;
    private static final int STATE_SUSPENDED          = 6;

    // mCurrentState is a VideoView object's current state.
    // mTargetState is the state that a method caller intends to reach.
@@ -298,6 +299,22 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
        }
    }

    private boolean isHTTPStreaming(Uri mUri) {
        if (mUri != null){
            String scheme = mUri.toString();
            if (scheme.startsWith("http://") || scheme.startsWith("https://")) {
                if (scheme.endsWith(".m3u8") || scheme.endsWith(".m3u")
                    || scheme.contains("m3u8") || scheme.endsWith(".mpd")) {
                    // HLS or DASH streaming source
                    return false;
                }
                // HTTP streaming
                return true;
            }
        }
        return false;
    }

    MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
        new MediaPlayer.OnVideoSizeChangedListener() {
            public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
@@ -343,7 +360,6 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
                seekTo(seekToPosition);
            }
            if (mVideoWidth != 0 && mVideoHeight != 0) {
                //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
                getHolder().setFixedSize(mVideoWidth, mVideoHeight);
                if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
                    // We didn't actually change the size (it was already at the size
@@ -509,6 +525,22 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {

        public void surfaceCreated(SurfaceHolder holder)
        {
            if (mCurrentState == STATE_SUSPENDED) {
                mSurfaceHolder = holder;
                mMediaPlayer.setDisplay(mSurfaceHolder);
                if (mMediaPlayer.resume()) {
                    mCurrentState = STATE_PREPARED;
                    if (mSeekWhenPrepared != 0) {
                        seekTo(mSeekWhenPrepared);
                    }
                    if (mTargetState == STATE_PLAYING) {
                        start();
                    }
                    return;
                } else {
                    release(false);
                }
            }
            mSurfaceHolder = holder;
            openVideo();
        }
@@ -518,6 +550,10 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
            // after we return from this we can't use the surface any more
            mSurfaceHolder = null;
            if (mMediaController != null) mMediaController.hide();
            if (isHTTPStreaming(mUri) && mCurrentState == STATE_SUSPENDED) {
                // Don't call release() while run suspend operation
                return;
            }
            release(true);
        }
    };
@@ -624,10 +660,44 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
    }

    public void suspend() {
        // HTTP streaming will call mMediaPlayer->suspend(), others will call release()

        if (isHTTPStreaming(mUri) && mCurrentState != STATE_PREPARING) {
            if (mMediaPlayer.suspend()) {
                mTargetState = mCurrentState;
                mCurrentState = STATE_SUSPENDED;
                return;
            }
        }

        release(false);
    }

    public void resume() {
        // HTTP streaming (with suspended status) will call mMediaPlayer->resume(), others will call openVideo()

        if (mCurrentState == STATE_SUSPENDED) {
            if (mSurfaceHolder != null) {
                // The surface hasn't been destroyed
                if (mMediaPlayer.resume()) {
                    mCurrentState = STATE_PREPARED;
                    if (mSeekWhenPrepared !=0) {
                        seekTo(mSeekWhenPrepared);
                    }
                    if (mTargetState == STATE_PLAYING) {
                        start();
                    }
                    return;
                } else {
                    // resume failed, so call release() before openVideo()
                    release(false);
                }
            } else {
                // The surface has been destroyed, resume operation will be done after surface created
                return;
            }
        }

        openVideo();
    }

@@ -675,7 +745,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
        return (mMediaPlayer != null &&
                mCurrentState != STATE_ERROR &&
                mCurrentState != STATE_IDLE &&
                mCurrentState != STATE_PREPARING);
                mCurrentState != STATE_PREPARING &&
                mCurrentState != STATE_SUSPENDED);
    }

    @Override
Loading