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

PreCache HLS MediaSource #9337

Open jacknyc opened 3 years ago

jacknyc commented 3 years ago

Goal: We're attempting to precache hls audio streams with the goal of faster initial playback upon selection of a single stream.

References: We've looked at the prior ExoPlayer references including: https://github.com/google/ExoPlayer/issues/7887 and https://medium.com/google-exoplayer/downloading-adaptive-streams-37191f9776e

Initial Attempt: We initially tried using the CacheWriter approach and set up our player as:

SimpleExoPlayer.Builder(context)
            .setBandwidthMeter(bandwidthMeter)
            .setAudioAttributes(
                AudioAttributes.Builder()
                    .setContentType(C.CONTENT_TYPE_MUSIC)
                    .setUsage(C.USAGE_MEDIA)
                    .build(),
                true
            )
            .setTrackSelector(DefaultTrackSelector(context))
            .setLoadControl(DefaultLoadControl())
            .build()

and precache the streams (using no length in the DataSpec to prevent EOF crashes) as follows:

        val dataSpec = DataSpec(Uri.parse(uri))
        CacheWriter(
            cacheDataSource,
            dataSpec,
            true,
            null,
            progressListener
        ).cache()

Results: We find there is a minimal download of less than 100 bytes from the progress listener

Question: Can you please confirm that the CacheWriter is intended for progressive streams and that we must download the content for adaptive streams such as HLS? And if so, is there an option to only download a fraction of the HLS stream as we're simply looking for faster startup time? Thanks.

marcbaechinger commented 3 years ago

The CacheWriter can be used to fill the cache with data that is downloaded from the dataSpec you are passing to the the CacheWriter constructor. This is straightforward for progressive streams that consist of a single file only and hence has a single dataSpec only. You can cap the downloaded data by building a DataSpec that has an endPosition.

With HLS or addaptive streams in general this is different. For properly pre-cache you need to:

All of the above can be done with the Downloader for HLS but as you mention, there is no way to restrict this download to a certain number of seconds or an amount of bytes.

I don't think there is something in the library which can help you with this out of the box. There are useful classes that can help you (eg. HlsParser, CacheWriter) but it needs considerable code from the app to do that.

In your sample code I wonder what uri the dataSpec is pointing to? If this is just the HLS uri then it only caches the playlist and no media. An implementation that partially caches an adaptive HLS stream would roughly have to:

All of this is not a trivial task I'm afraid. Specifically with adaptive streams this adds significant complexity compared to progressive stream.

jacknyc commented 3 years ago

@marcbaechinger Thanks. That's really good advice. Any other recommendations on speeding startup times for hls audio streams when the streams are random, but only a small number exist (can't use concatenating in this case). I'm thinking about experimenting with minimum buffer durations. Thanks.

shubhamvashisht commented 1 year ago

@jacknyc were you able to come up with any solution to achieve this?

jacknyc commented 1 year ago

The downloader is the only solution.

On Wed, Oct 4, 2023, 2:56 PM Shubham Vashisht @.***> wrote:

@jacknyc https://github.com/jacknyc were you able to come up with any solution to achieve this?

— Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/9337#issuecomment-1747463684, or unsubscribe https://github.com/notifications/unsubscribe-auth/AS63SKEK3J63DPTBINE2THDX5WWMXAVCNFSM5CZL6KDKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCNZUG42DMMZWHA2A . You are receiving this because you were mentioned.Message ID: @.***>