ExoPlayer resume on same position on rotate screen
Asked Answered
M

4

22

I am using ExoPlayer in my activity,What i want is to smoothly play video in portrait and landscape mode.For this purpose what I am doing is in onpause I save the currentPlayerPosition and seek player to that position in onresume but while rotating it face a jerk and video is stopped for a while and played to the saved position.

My code is below please help me how i can smoothly switch the mode portrait and landscape.Thanks

     @Override
public void onPause() {

    super.onPause();

    if (mExoPlayerView != null && mExoPlayerView.getPlayer() != null) {
        mResumeWindow = mExoPlayerView.getPlayer().getCurrentWindowIndex();
        mResumePosition = Math.max(0, mExoPlayerView.getPlayer().getContentPosition());
        mExoPlayerView.getPlayer().release();
    }
}


@Override
public void onDestroy() {
    super.onDestroy();
    if (mExoPlayerView.getPlayer() != null)
        mExoPlayerView.getPlayer().release();
}


  @Override
public void onSaveInstanceState(Bundle outState) {

    outState.putInt(STATE_RESUME_WINDOW, mResumeWindow);
    outState.putLong(STATE_RESUME_POSITION, mResumePosition);
    outState.putBoolean(STATE_PLAYER_FULLSCREEN, mExoPlayerFullscreen);
    super.onSaveInstanceState(outState);
}



   @Override
protected void onResume() {

    super.onResume();

    if (mExoPlayerView == null) {

        mExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.exoplayer);

        videoURL = getIntent().getStringExtra("url");
        postID = getIntent().getIntExtra("UserID", 0);

        String userAgent = Util.getUserAgent(Vid.this, getApplicationContext().getApplicationInfo().packageName);
        DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory(userAgent, null, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, true);
        DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(Vid.this, null, httpDataSourceFactory);
        Uri daUri = Uri.parse(videoURL);

        ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

        if (daUri.toString().startsWith("https://player.vimeo"))
            mVideoSource = new HlsMediaSource(daUri, dataSourceFactory, 1, null, null);
        else
            mVideoSource = new ExtractorMediaSource(daUri, dataSourceFactory, extractorsFactory, null, null);

        initExoPlayer();

    } else {
        resumeExoPlayer();
    }

}


   private void resumeExoPlayer() {

    boolean haveResumePosition = mResumeWindow != C.INDEX_UNSET;

    if (haveResumePosition) {
        hideKeyboard();
        hideProgress();
        mExoPlayerView.getPlayer().seekTo(mResumeWindow, mResumePosition);
    }
}

private void initExoPlayer() {
    BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
    LoadControl loadControl = new DefaultLoadControl();
    SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(this), trackSelector, loadControl);
    mExoPlayerView.setPlayer(player);

    boolean haveResumePosition = mResumeWindow != C.INDEX_UNSET;

    if (haveResumePosition) {
        hideKeyboard();
        hideProgress();
        mExoPlayerView.getPlayer().seekTo(mResumeWindow, mResumePosition);

    }

    mExoPlayerView.getPlayer().prepare(mVideoSource);
    mExoPlayerView.getPlayer().setPlayWhenReady(true);

    mExoPlayerView.getPlayer().addListener(new Player.EventListener() {
        @Override
        public void onTimelineChanged(Timeline timeline, Object manifest) {

        }

        @Override
        public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

        }

        @Override
        public void onLoadingChanged(boolean isLoading) {

        }

        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

            if (playbackState == ExoPlayer.STATE_ENDED) {
                hideProgress();
                mExoPlayerView.getPlayer().seekTo(0);
                mExoPlayerView.getPlayer().setPlayWhenReady(false);
            } else if (playbackState == ExoPlayer.STATE_BUFFERING) {
            } else if (playbackState == ExoPlayer.STATE_READY) {
                hideProgress();

                if (preferenceManager.getLoggedIn()) {
                    APIGetComment();
                }
            }
        }

        @Override
        public void onRepeatModeChanged(int repeatMode) {

        }

        @Override
        public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {

        }

        @Override
        public void onPlayerError(ExoPlaybackException error) {
            hideProgress();
            finish();
        }

        @Override
        public void onPositionDiscontinuity(int reason) {

        }

        @Override
        public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {

        }

        @Override
        public void onSeekProcessed() {

        }
    });
}
Morette answered 15/3, 2018 at 15:17 Comment(1)
Player preparation takes time. You cant do much about it.Passionate
M
49

Finally, After wasting 2 days I found it. Simple add it in the manifest and will work on all android version ?

android:configChanges="orientation|screenSize|layoutDirection"

cheers!

Morette answered 19/3, 2018 at 5:25 Comment(3)
thanks you, Yes, it solves the problem, for newbie like me, you will need to look for your video-activity in 'AndroidManifest.xml' and place it in the "<activity ... " definition.Glamorous
Yeah please don't do this. This 'workaround' results in lots of other issues in your app including wrong layouts being displayed when rotating the device or enabling split screen.Tiebold
You shouldn't need to prevent configuration changes for this to work. This solution should work https://mcmap.net/q/587381/-exoplayer-save-and-restore-state-on-rotation-within-fragmentComportment
S
3

No need of any additional coding, simply add this line

android:configChanges="keyboardHidden|orientation|screenSize"

in your AndroidManifest.xml's activity section.

Sofar answered 9/8, 2018 at 9:8 Comment(0)
E
2

If you want the video to resume on orientation change, you can add this to your manifest android:configChanges="keyboardHidden|orientation|screenSize"

     <activity
     <activity
         android:name=".MainActivity"
         android:name=".MainActivity"
         android:label="@string/app_name"
         android:label="@string/app_name"
+            android:configChanges="keyboardHidden|orientation|screenSize"
         android:theme="@style/AppTheme.NoActionBar"
         android:theme="@style/AppTheme.NoActionBar"
         android:icon="@mipmap/ic_launcher_2">
         android:icon="@mipmap/ic_launcher_2">
         <intent-filter>
         <intent-filter>
Envision answered 17/3, 2018 at 21:53 Comment(0)
A
0

I also wasted quite a lot time in this. Take a look at it EXO PLAYER 2.11.2

    implementation 'com.google.android.exoplayer:exoplayer:2.11.2'

STEP - 1 Make an activity in which string url is passed as intent.

  public class VideoPlayerActivity extends Activity {

  public static final String sURL_KEY = "STREAMING_URL_KEY";
  public static final String sTOAST_TEXT = "Unable to stream, no media found";
  static final String LOADING = "PLAYER_LOADING";
  static final String STOPPED = "PLAYER_STOPPED";
  static final String PAUSED = "PLAYER_PAUSED";
  static final String PLAYING = "PLAYER_PLAYING";
  static final String IDLE = "PLAYER_IDLE";
  private static final String TAG = "StreamMediaActivity";
  int orientation;
  private Uri streamUrl;
  private SimpleExoPlayer mPlayer;
  private PlayerView playerView;
  private ProgressBar progressBar;
  private String mPlayerStatus;
  private long mPlaybackPosition = 0L;
  private boolean mIsPlayWhenReady = true;
  private int mCurrentWindow = 0;
  private Display display;
  private String STATE_RESUME_WINDOW = "resumeWindow";
  private String STATE_RESUME_POSITION = "resumePosition";
  private String STATE_PLAYER_FULLSCREEN = "playerFullscreen";
  private boolean mExoPlayerFullscreen = false;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    fullScreen();
    display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
    orientation = display.getRotation();
    setContentView(R.layout.activity_video_player);
    playerView = findViewById(R.id.player_view);
    progressBar = findViewById(R.id.progressBar_player);

// Pass a string uri to this class
    String urlString = getIntent().getStringExtra(sURL_KEY);
    if (urlString != null) {
      streamUrl = Uri.parse(urlString);
    } else {
      Toast.makeText(this, sTOAST_TEXT, Toast.LENGTH_LONG).show();
      finish();
    }
  }

  @Override
  protected void onStart() {
    super.onStart();
    initPlayer();
  }

  @Override
  protected void onResume() {
    super.onResume();
    if (mPlaybackPosition != 0L && mPlayer != null) {
      mPlayer.seekTo(mCurrentWindow, mPlaybackPosition);
    }
  }

  @Override
  protected void onStop() {
    super.onStop();
  }

  @Override protected void onPause() {
    super.onPause();
    releasePlayer();
  }



    private void initPlayer() {
        // ESTABLISH THE DATA SOURCE FROM URL
    // here i'm playing local video file that's
 // why using the DefaultDataSourceFactory but you 
//may use DefaultHttpDataSourceFactory to stream 
//online videos 
        DataSource.Factory dataSourceFactory =
            new DefaultDataSourceFactory(this, Util.getUserAgent(this, getApplicationInfo().name));

    MediaSource mediaSource =
        new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(
            streamUrl);


    // CREATE A NEW INSTANCE OF EXO PLAYER
    if (mPlayer == null) {
      mPlayer = new SimpleExoPlayer.Builder(this, new DefaultRenderersFactory(this)).build();
      playerView.setPlayer(mPlayer);
      progressBar.setVisibility(View.VISIBLE);
    }
    mPlayer.setPlayWhenReady(mIsPlayWhenReady);
    mPlayer.seekTo(mCurrentWindow, mPlaybackPosition);

    // PREPARE MEDIA PLAYER
    mPlayer.prepare(mediaSource, true, false);
    mPlayer.addListener(new Player.EventListener() {
      @Override
      public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
        switch (playbackState) {
          case Player.STATE_BUFFERING:
            mPlayerStatus = LOADING;
            runOnUiThread(() -> progressBar.setVisibility(View.VISIBLE));
            break;
          case Player.STATE_ENDED:
            mPlayerStatus = STOPPED;
            break;
          case Player.STATE_READY:
            mPlayerStatus = (playWhenReady) ? PLAYING : PAUSED;
            runOnUiThread(() -> progressBar.setVisibility(View.INVISIBLE));
            break;
          default:
            mPlayerStatus = IDLE;
            break;
        }
      }

      @Override
      public void onPlayerError(ExoPlaybackException error) {
        Toast.makeText(VideoPlayerActivity.this, "Something went wrong", Toast.LENGTH_SHORT).show();
        finish();
      }
    });
  }

  @Override protected void onSaveInstanceState(Bundle outState) {
    mExoPlayerFullscreen = !mExoPlayerFullscreen;
    super.onSaveInstanceState(outState);
    outState.putInt(STATE_RESUME_WINDOW, mCurrentWindow);
    outState.putLong(STATE_RESUME_POSITION, mPlaybackPosition);
    outState.putBoolean(STATE_PLAYER_FULLSCREEN, mExoPlayerFullscreen);
    super.onSaveInstanceState(outState);
  }

  public void fullScreen() {
    View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
  }

  private void releasePlayer() {
    if (mPlayer != null) {
      mPlayer.stop();
      mPlaybackPosition = mPlayer.getCurrentPosition();
      mCurrentWindow = mPlayer.getCurrentWindowIndex();
      mIsPlayWhenReady = mPlayer.getPlayWhenReady();
      playerView.setPlayer(null);
      mPlayer.release();
      mPlayer = null;
    }
  }
}

Step 2 : Make the XML layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black">

  <FrameLayout
      android:layout_width="0dp"
      android:layout_height="0dp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent">

    <com.google.android.exoplayer2.ui.PlayerView
        android:id="@+id/player_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:keepScreenOn="true"
        app:use_controller="true"
        app:resize_mode="fit"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/progressBar_player"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

  </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

STEP 3: start VideoPlayerActivity using intent from another activity

Intent streamVideoIntent = new Intent(context, VideoPlayerActivity.class);
                        streamVideoIntent.putExtra(sURL_KEY, stringUrl);
                        context.startActivity(streamVideoIntent);

STEP 4 : Lastly add activity to manifest

<activity android:name=".ui.videoplayer.VideoPlayerActivity"
        android:configChanges="orientation|screenSize|layoutDirection"
        />
Amalee answered 14/5, 2020 at 6:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.