google / ExoPlayer

An extensible media player for Android
Apache License 2.0
21.65k stars 6.01k forks source link

Filtering what data is cached with DASH media. #4050

Closed 0c6a183d closed 6 years ago

0c6a183d commented 6 years ago

Hi.

I have implemented a cache for Exoplayer to store DASH audio chunks as the online content is static / on-demand. It works very well during playback always retrieving from cache if possible. Exoplayer is configured for a quick start and starts playing audio at 28Kbps until the BandwidthMeter has generated a reading (~4 seconds) and then Exo switches up to the higher quality, if possible.

During the initial playback, the first 4 seconds of low quality audio is cached prior to the quality increase to say 320Kbps. The second time it plays, Exo has to grab an additional 4 seconds of low quality chunks as the Bandwidth meter has not seen any fresh data downloaded, only the 4 seconds stored in the local cache. On the third playback, 8 seconds of low quality have to play before BandwidthMeter can start seeing fresh data. It increases each time the track is played, where 10 plays cause a 40 second delay in BandwidthMeter generating its reading, so the audio is stuck on 28Kbps. In theory with enough playbacks, the whole track would only ever play at 28Kbps.

Assuming you do not have another recommendation, I am curious as to whether there is some kind of cache policy / filters that can prevent the first 10 seconds of audio chunks being cached, so BandwidthMeter always has fresh data to download in the first few seconds. Another way would be to only cache the higher quality stream(s) or chunks over _x_KB. Is there a way to configure this, or similar?

I am not looking to download the whole track at this stage (as some are 2 hours long), just a cache to occasionally help with the users data charges and our server charges.

Thank you in advance.

0c6a183d commented 6 years ago

Alternatively to the above questions, could Exoplayer be set to ignore the cache for the first x seconds of DASH playback?

erdemguven commented 6 years ago

Unfortunately those are not possible.

Not ideal but one thing you can do is to delete the cached data for the first content you will play that way you can get a correct estimation. To delete DASH content you can use DashDownloader.remove method. It will remove the whole content. Unfortunately there isn't an easy way to just remove initial part.

Another solution might be increasing your initial bandwidth estimation which would make the experience better in this specific case.

0c6a183d commented 6 years ago

Thank you for your reply. I have not used DashDownloader yet so I will try that in the future to implement your method. Based on your reply, I have used a similar approach by using the components I am familiar with. I have used two simpleExoplayer instances, one builds without a cache, the other with. They both share a BandwidthMeter instance. Exo instance one plays 2 seconds of muted audio and provides bandwidth meter with its initial estimate, on STATE_ENDED, its killed and kicks off the second exoplayer instance that plays the main media. Seems to work well and as the main media can start at high quality so less caching of low quality audio.

Can you see any problem with using this method, seems to work OK?

ojw28 commented 6 years ago

That sounds like a pretty hacky way of initializing the bandwidth estimate. It probably adds significant startup latency to your playbacks, and consumes bandwidth unnecessarily. Instead, you can just specify a higher bandwidth estimate directly. In the next release you'll be able to do this when building the BandwidthMeter instance. See here:

https://github.com/google/ExoPlayer/blob/6e5ae87cae43ebc9794f8d075e0fda1267900213/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java#L85

You could simply pass a high enough value to cause the best quality to be selected as the starting quality. Alternatively, you could be a bit more clever about it, store the estimate from a previous BandwidthMeter instance when your app is going away, and restore that estimate back into a new BandwidthMeter when the app is next used. That would probably give you nice stability properties.

Obviously, for as long as your process is alive, you should use the same BandwidthMeter throughout, so estimates are carried forward from one playback to the next. My suggestion above allows you to extend this behavior across the process being killed and restarted as well.

--

In the current release providing the initial bandwidth estimate is less intuitive, but still possible. You can pass it when creating the AdaptiveTrackSelection.Factory. See here:

https://github.com/google/ExoPlayer/blob/88dea59cd225e424dc360e3fd7f412441ec3dc21/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java#L80