google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.72k stars 6.03k forks source link

Fail to seek in buffered part without internet connection. #7413

Open RamilGabdrakhmanov opened 4 years ago

RamilGabdrakhmanov commented 4 years ago

Issue description

Im trying to seek in buffered part without internet connection. Expected result: it is possible to start playback Actual result: Exception

Video: device-2020-05-22-130034.mp4.zip

Click listener for "2 SEC FORWARD": new OnClickListener() { int initial = 4000; @Override public void onClick(View v) { player.seekTo(0, initial); initial += 2000; } }

Reproduction steps

Steps: 1) Open ExoPlayer demo app; 2) Start to play Widevine Dash: MP4, H264 -> WV: Clear SD(MP4, H264) 3) Pause immediately before playback will start; 4) Turn off internet connection 5) Seek to 4000 6) Seek to 6000

Link to test content

WV: Clear SD (MP4,H264) https://storage.googleapis.com/wvmedia/clear/h264/tears/tears_sd.mpd

A full bug report captured from the device

I sent Bugreport to dev.exoplayer@gmail.com

Version of ExoPlayer being used

2.11.4; Version from release-v2 branch;

Device(s) and version(s) of Android being used

Xiaomi Mi A1 (Android 9)

christosts commented 4 years ago

Just an update.

I can repro the behavior using the button you added, and also by seeking through the progress bar. Sometimes it takes more than 2 seeks to raise the error, but the error is likely to be reproduced with a 3rd or 4th seek while paused.

In all cases, there's an exception thrown from ExoPlayerImplInternal.doSomeWork(). The renderers report they are not ready a few lines above, and then renderer.maybeThrowStreamError() raises the exception because the stream has stopped downloading due to the network being disconnected.

I need to dig this a bit further though, in my repros I've seen a few different reasons why a renderer reports it is not ready and need to verify which cases are buggy and which are working as expected.

christosts commented 4 years ago

[update with more findings]

I have found at least two ways to consistently trigger the behavior:

  1. Seeking at points very close to each other while the player is paused and the network is disconnected. This is the case described at the issue above, e.g.
    seekTo(0, 2000);
    seekTo(0, 4000);

    (cc @ojw28) Seeking to 4000 requires to search for a video key-frame before 4000 which is needed by the video decoder in order to decode samples (a video decoder cannot start decoding video frames at arbitrary positions). In at least one DASH video in the demo app, the key frame needed to seek to 4000 is actually before 2000. However, the previous seek at 2000 has discarded samples before 2000, because by default the player doesn't hold data before the current position. Seeking at 4000 requires the player to look for samples before 2000 which have been dropped already, therefore needs to fetch them from the network.

This can be mitigated setting the retainBackBufferFromKeyframe flag at the DefaultLoadControl, e.g. in the demo app, when creating the player, you may set the LoadControl as follows

player =
          new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory)
              .setMediaSourceFactory(
                  DefaultMediaSourceFactory.newInstance(
                      /* context= */ this, dataSourceFactory, new AdSupportProvider()))
              .setTrackSelector(trackSelector)
              .setLoadControl(new DefaultLoadControl.Builder().setBackBuffer(0, /* retainBackBufferFromKeyframe= */ true).createDefaultLoadControl())
              .build();
  1. There is second path that triggers this error though, either by the seeking with the UI in more distant points or by enabling the retainBackBufferFromKeyframe and seeking at close points. When reaching ExoPlayerImplInternal.doSomeWork(), the MediaCodecRenderer reports it is not ready here, but not because there are missing data from the sample queue.

I'm not sure yet if the renderer should report it is ready, or ExoPlayerImplInternal should handle this more delicately. I will update the ticket with more findings.

christosts commented 4 years ago

This looks like a bug that's been here for a while. I will leave this issue open and we will track this in our backlog. At the moment, I cannot share a timeline for a when a fix will be available.