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.74k stars 6.03k forks source link

Allow SingleSampleMediaSource not to block playback from starting #8566

Open MagicUnderHood opened 3 years ago

MagicUnderHood commented 3 years ago

Description

I am using exoplayer 2.11.4 and am adding multiple .srt subtitles to a video using SingleSampleMediaSource and MergingMediaSource. When the video starts, the player always sends a request for the first subtitles from the list. If delay (timeout) is set on this request (I use Fiddler for this), then the player waits for a response and does not start playing. The player is in BUFFERING state and the user cannot watch the video. I want the subtitle request delay not to interfere with the video playback.

I already ignore 404 subtitle request errors by setting setTreatLoadErrorsAsEndOfStream(true), but that doesn't help in case of a delay. I also do not allow subtitle re-requests via CaptionsLoadErrorPolicy.

  1. Is it possible to turn off the sending of the request for the first subtitles until the user has explicitly selected them?
  2. If not, is it possible to make the player allow the video to be played without waiting for the subtitle response?

My code:

class CaptionsLoadErrorPolicy : DefaultLoadErrorHandlingPolicy() {
    override fun getRetryDelayMsFor(
        dataType: Int,
        loadDurationMs: Long,
        exception: IOException?,
        errorCount: Int
    ) = C.TIME_UNSET
}

const val SUBS_REQUEST_TIMEOUT = 15000

val captionsHttpDataSourceFactory = DefaultHttpDataSourceFactory(
    Util.getUserAgent(context, APP_NAME),
    SUBS_REQUEST_TIMEOUT,
    SUBS_REQUEST_TIMEOUT,
    false
)

val format  = Format.createTextSampleFormat(
        "English",
        MimeTypes.APPLICATION_SUBRIP,
        Format.NO_VALUE,
        "English"
)

val captionsMediaSources = SingleSampleMediaSource.Factory(captionsHttpDataSourceFactory)
    .setTreatLoadErrorsAsEndOfStream(true)
    .setLoadErrorHandlingPolicy(CaptionsLoadErrorPolicy())
    .createMediaSource(uri, format, C.TIME_UNSET)

val videoMediaSource: MediaSource = //video source

val mediaSource = MergingMediaSource(videoMediaSource, captionsMediaSources)

exoPlayer.prepareContent(source = mediaSource, resetPosition = false, resetState = true)

Reproduction steps

  1. Merging video source and multiple .srt subtitles
  2. Delay via Fiddler to request the first subtitles (https://some_site/media/subtitle/1f/75/1f75a28e7608df33c786946f39da9b7f.srt)
  3. See that the player went to the BUFFERING state, waiting for the subtitle response, during SUBS_REQUEST_TIMEOUT (15 seconds if the response does not come earlier)

A full bug report captured from the device No bug report required as the player does not produce any errors.

Version of ExoPlayer being used ExoPlayer version 2.11.4

Device(s) and version(s) of Android being used Pixel 2 android emulator, Android version 10

icbaker commented 3 years ago

I can reproduce what you're seeing on the dev-v2 branch. I modified DefaultDataSource#read() as below to simulate a slow load, then played the "Subtitles > WebVTT positioning" sample in the Demo app. Video playback is delayed until the subtitles are available:

@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
  if (getUri().getPath().endsWith(".vtt")) {
    try {
      Thread.sleep(3_000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }
  return Assertions.checkNotNull(dataSource).read(buffer, offset, readLength);
}

This is happening because SingleSampleMediaPeriod reports its buffered position as 0 until loading is complete, then it reports C.TIME_END_OF_SOURCE: https://github.com/google/ExoPlayer/blob/7d3f54a375fac04a746ca76a8f2e1ad32c8b45b2/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java#L195-L197

I changed this locally to always return C.TIME_END_OF_SOURCE and it allows video playback to start immediately, with the subtitles appearing as soon as their load completes.

There's currently no toggle on SingleSampleMediaSource to change this behaviour - I'll keep this issue open to track that as a possible enhancement. In the meantime if you want to change this behaviour yourself you can either directly edit a local copy of ExoPlayer or fork SingleSampleMediaSource and Period into your own project and make the change there.

MagicUnderHood commented 3 years ago

Thanks for your reply! I will wait for enhancement and try the suggested options.