Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

seekTo(0) followed by a TrackSelection jumps back to live point. #9347

Open
stevemayhew opened this issue Aug 27, 2021 · 3 comments
Open

seekTo(0) followed by a TrackSelection jumps back to live point. #9347

stevemayhew opened this issue Aug 27, 2021 · 3 comments
Assignees

Comments

@stevemayhew
Copy link
Contributor

stevemayhew commented Aug 27, 2021

Steps To Reproduce

Add this code to the demo PlayerActivity:

  private static boolean bug_triggered = false;

  private class PlayerEventListener implements Player.Listener {

    @Override
    public void onPlaybackStateChanged(@Player.State int playbackState) {
      Log.d(TAG, "onPlaybackStateChanged() - " + playbackState);

      if (getIntent().getBooleanExtra("trigger_bug", false) && ! bug_triggered) {
        playerView.setControllerAutoShow(false);
        playerView.setControllerShowTimeoutMs(-1);
        playerView.showController();
        if (playbackState == Player.STATE_READY) {
          bug_triggered = true;
          DefaultTrackSelector.Parameters savedParameters = trackSelector.getParameters();
          DefaultTrackSelector.Parameters disableTracksParameters =
              savedParameters
              .buildUpon()
              .setMaxVideoBitrate(3000000 - 1)
              .build();
          trackSelector.setParameters(disableTracksParameters);
          long pos = player.getCurrentPosition();
          while (pos > 0) {
            Log.d(TAG, "seekTo - " + pos);
            player.seekTo(pos);
            pos -= 600_000L;
            android.os.SystemClock.sleep(500);
          }
          Log.d(TAG, "seekTo final to 0");
          player.seekTo(0);
          Log.d(TAG, "run track selection");
          trackSelector.setParameters(savedParameters);
        }
      }

Run it sending the intent to the player:

adb shell am start -n com.google.android.exoplayer2.demo/.PlayerActivity -a com.google.android.exoplayer.demo.action.VIEW --ez trigger_bug true -d <live-url>

Issue Analysis

The MaskingMediaPeriod forces position back to live start when TrackSelection is triggered following a seek to 0.
I believe this issue is related to issue #7975, specifically the code that handles changing the position, source here.

For the 2.12.x ExoPlayer this results in the player hangs in BUFFERING state but believing there is way more buffer then there is because position does not change. Changes since 2.12 (e.g. dynamic live edge) appear to have changed that behavior so now it simply jumps from position 0 (the expected position) to live edge. We will be fixing this for 2.12 (our current version) and will try to provide a forward port pull request for dev-v2

Plan is to only apply the override position on the initial playback start, not every track selection as it is done now.

Logging

08-27 15:50:44.165 16684 16684 D Demo    : onPlaybackStateChanged() - 2
08-27 15:50:44.166 16684 16775 W MaskingMediaPeriod: <construct>() - 66568544 preparePositionUs: 0
08-27 15:50:45.584 16684 16775 D MaskingMediaPeriod: overridePreparePositionUs() - 66568544  preparePositionUs: 3571568, preparePositionOverrideUs: -9223372036854775807
08-27 15:50:45.584 16684 16775 D MaskingMediaPeriod: getPreparePositionWithOverride() - preparePositionMs: 0 preparePositionOverride: 3571568
08-27 15:50:47.272 16684 16684 D Demo    : onPlaybackStateChanged() - 3
08-27 15:50:47.274 16684 16684 D Demo    : seekTo - 3571600
08-27 15:50:47.781 16684 16684 D Demo    : seekTo - 2971600
08-27 15:50:48.287 16684 16684 D Demo    : seekTo - 2371600
08-27 15:50:48.793 16684 16684 D Demo    : seekTo - 1771600
08-27 15:50:49.299 16684 16684 D Demo    : seekTo - 1171600
08-27 15:50:49.807 16684 16684 D Demo    : seekTo - 571600
08-27 15:50:50.311 16684 16684 D Demo    : seekTo final to 0
08-27 15:50:50.316 16684 16684 D Demo    : run track selection
08-27 15:50:50.336 16684 16684 D EventLogger: positionDiscontinuity [eventTime=6.22, mediaPos=0.00, window=0, period=0, reason=SEEK, PositionInfo:old [window=0, period=0, pos=3571600], PositionInfo:new [window=0, period=0, pos=3571600]]
08-27 15:50:50.346 16684 16684 D Demo    : onPlaybackStateChanged() - 2
08-27 15:50:50.360 16684 16684 D EventLogger: positionDiscontinuity [eventTime=6.24, mediaPos=0.00, window=0, period=0, reason=SEEK, PositionInfo:old [window=0, period=0, pos=3571600], PositionInfo:new [window=0, period=0, pos=2971600]]
08-27 15:50:50.368 16684 16684 D EventLogger: positionDiscontinuity [eventTime=6.25, mediaPos=0.00, window=0, period=0, reason=SEEK, PositionInfo:old [window=0, period=0, pos=2971600], PositionInfo:new [window=0, period=0, pos=2371600]]
08-27 15:50:50.376 16684 16684 D EventLogger: positionDiscontinuity [eventTime=6.26, mediaPos=0.00, window=0, period=0, reason=SEEK, PositionInfo:old [window=0, period=0, pos=2371600], PositionInfo:new [window=0, period=0, pos=1771600]]
08-27 15:50:50.384 16684 16684 D EventLogger: positionDiscontinuity [eventTime=6.27, mediaPos=0.00, window=0, period=0, reason=SEEK, PositionInfo:old [window=0, period=0, pos=1771600], PositionInfo:new [window=0, period=0, pos=1171600]]
08-27 15:50:50.391 16684 16684 D EventLogger: positionDiscontinuity [eventTime=6.28, mediaPos=0.00, window=0, period=0, reason=SEEK, PositionInfo:old [window=0, period=0, pos=1171600], PositionInfo:new [window=0, period=0, pos=571600]]
08-27 15:50:50.399 16684 16684 D EventLogger: positionDiscontinuity [eventTime=6.28, mediaPos=0.00, window=0, period=0, reason=SEEK, PositionInfo:old [window=0, period=0, pos=571600], PositionInfo:new [window=0, period=0, pos=0]]

Here's where the error occurs, MMP overrides the position and returns it from selectTracks()

08-27 15:50:50.410 16684 16775 D MaskingMediaPeriod: selectTracks() - 66568544 override positionMs: 0 to preparePositionOverrideMs: 3571568, preparePositionMs: 0
08-27 15:50:51.128 16684 16684 D Demo    : onPlaybackStateChanged() - 3
08-27 15:50:52.727 16684 16775 D MaskingMediaPeriod: overridePreparePositionUs() - 66568544  preparePositionUs: -9223372036854775807, preparePositionOverrideUs: -9223372036854775807
@stevemayhew
Copy link
Contributor Author

Also noticed... The position discontinuity caused by the MaskingMediaPeriod here:

08-27 15:50:50.410 16684 16775 D MaskingMediaPeriod: selectTracks() - 66568544 override positionMs: 0 to preparePositionOverrideMs: 3571568, preparePositionMs: 0

Is propagated all the way to EPII handlePlaybackInfo() but does not get reported to Player.onPositionDiscontinuity() because of logic introduced in this commit dc4148d

@marcbaechinger is there something I've missed here?

@stevemayhew
Copy link
Contributor Author

@marcbaechinger I've got the fix for this, writing up a pull request now. I have the code change, just want to add test cases too.

stevemayhew added a commit to TiVo/ExoPlayer that referenced this issue Sep 3, 2021
This is a fix for issue google#9347

Once the MaskingMediaPeriod completes `prepare()` (when the masked HlsMediaPeriod reports the
first real Timeline with a duration and window start position) and the `preparePositionUs` is used
by the player in the `onPrepared()` callback to set the render position it should not use it again.

The bug is a track selection causes a jump to live if you are at position 0
 in the timeline, even after playback was started from the live point (the prepare position override).

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Thu Sep 2 11:30:31 2021 -0700
#
# On branch p-fix-exo-issue-9347
# Changes to be committed:
#	modified:   library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaPeriod.java
#	modified:   library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java
#
# Untracked files:
#	validation_data.json
#
stevemayhew added a commit to TiVo/ExoPlayer that referenced this issue Sep 3, 2021
This is a fix for issue google#9347

Once the MaskingMediaPeriod completes `prepare()` (when the masked HlsMediaPeriod reports the
first real Timeline with a duration and window start position) and the `preparePositionUs` is used
by the player in the `onPrepared()` callback to set the render position it should not use it again.

The bug is a track selection causes a jump to live if you are at position 0
in the timeline, even after playback was started from the live point (the prepare position override).
stevemayhew added a commit to TiVo/ExoPlayer that referenced this issue Sep 8, 2021
This is a fix for issue google#9347

Once the MaskingMediaPeriod completes `prepare()` (when the masked HlsMediaPeriod reports the
first real Timeline with a duration and window start position) and the `preparePositionUs` is used
by the player in the `onPrepared()` callback to set the render position it should not use it again.

The bug is a track selection causes a jump to live if you are at position 0
in the timeline, even after playback was started from the live point (the prepare position override).
@tonihei
Copy link
Collaborator

tonihei commented Sep 29, 2021

There are a couple of issues/PRs evolving around the same problem, let me consolidate this a bit by marking this as a duplicate of #7975 as they both have the same root cause.

stevemayhew referenced this issue Jul 25, 2023
MaskingMediaSource needs to resolve the prepare position set for a MaskingPeriod
while the source was still unprepared to the first actual prepare position.

It currently assumes that the period-window offset and the default position is
zero. This assumption is correct when a PlaceholderTimeline is used, but it
may not be true if the real timeline is already known (e.g. when re-preparing
a live stream after a playback error).

Fix this by using the known timeline at the time of the preparation.
Also:
 - Update a test that should have caught this to use lazy re-preparation.
 - Change the demo app code to use the recommended way to restart playback
   after a BehindLiveWindowException.

Issue: #8675
PiperOrigin-RevId: 361604191
copybara-service bot pushed a commit that referenced this issue Dec 14, 2023
Using 0 as the unset prepare position is the root cause of a number of issues,
as outliine in the ExoPlayer issue #7975

The premise of this fix is that once the prepare override is used (the initial call
to `selectTracks()`) it is never needed again, so simply invalidate it after use.
psharma676 pushed a commit to psharma676/ExoPlayer that referenced this issue Dec 14, 2023
Once the MaskingMediaPeriod completes `prepare()` (when the masked HlsMediaPeriod reports the first real Timeline with a duration and window start position) it should not use it again.

The bug is a track selection causes a jump to live if you are at position 0 in the timeline, even after playback was started from the live point (the prepare position override).
psharma676 pushed a commit to psharma676/ExoPlayer that referenced this issue Dec 14, 2023
This is a fix for issue google#9347

Once the MaskingMediaPeriod completes `prepare()` (when the masked HlsMediaPeriod reports the
first real Timeline with a duration and window start position) and the `preparePositionUs` is used
by the player in the `onPrepared()` callback to set the render position it should not use it again.

The bug is a track selection causes a jump to live if you are at position 0
in the timeline, even after playback was started from the live point (the prepare position override).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants