androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.55k stars 373 forks source link

Avoid rebuffering when modifying TrackSelector parameters #1631

Open guidofranceschini opened 3 weeks ago

guidofranceschini commented 3 weeks ago

[REQUIRED] Use case description This is the exact same request raised time ago in the Exoplayer project (issue #6630). I have an app using adaptive media, where in certain circumstances I want to reduce the bandwidth consumed by the video/audio. I do so by setting new filtering criteria in the track selector, as follows:

    DefaultTrackSelector.Parameters currentParameters = ((DefaultTrackSelector) trackSelector).getParameters();
    DefaultTrackSelector.Parameters newParameters = currentParameters
            .buildUpon()
            .setForceLowestBitrate(true)
            .build();
    ((DefaultTrackSelector) trackSelector).setParameters(newParameters);

However this forces a reset in the playback (removal of chunks already available), with rebuff for a while. The same happens when I remove that limitaton. Of course rebuffering is more evident if I force the selection of a high bitrate track. I need instead an uninterrupted playback

Proposed solution I need something like:

trackSelector.SetParameters(newParameters, booleanWetherResetOrNot);

such that (in case of "don't reset") the playback is not interrupted, and chunks already downloaded or being downloaded are not removed; simply, the new trackSelector parameters would take effect at the next choice of the chunk to be downloaded.

Alternatives considered In Exoplayer #6630 Tonihei finally showed an application-level solution (at that time I already implemented a more invasive blacklist based solution and didn't revert to Tonihei's suggestion). I'd like to use that solution now, so I tried implementing it. I can inject my custom class, and I can see it being created and invoked. However, I have no mechanism to access the actual instances of that CustomTrackSelection in order to dynamically set the parameters I need. Would someone be able to complete Tonihei's solution by showing also how to actually set a parameter on that class, dynamically?

Thanks in advance

tonihei commented 3 weeks ago

This is still a duplicate of the issue in https://github.com/google/ExoPlayer/issues/2250. I'll use this new issue as the canonical one and close the old one to move the issue over to the Media3 tracker. Note that the workaround outlined in https://github.com/google/ExoPlayer/issues/6630#issuecomment-1023007702 should still work for the time being.

I need something like: trackSelector.SetParameters(newParameters, booleanWetherResetOrNot);

Your suggested API makes sense to me, but note that it would always be a best-effort approach (like applyNewParametersLazilyAndSeamlesslyIfSupported). We would probably make the parameter part of TrackSelectionParameters as well I think, but that's TBD.

tonihei commented 3 weeks ago

However, I have no mechanism to access the actual instances of that CustomTrackSelection in order to dynamically set the parameters I need.

The sample code provided in https://github.com/google/ExoPlayer/issues/6630#issuecomment-1023007702 should give you access to the class instances I think. See the shared field enabledSelections at the top that is updated whenever the selection is enabled/disabled and can be used to send updates to all enabled instances (as shown at the top of that code snippet). Have you tried this part? Or can you describe the issue in more detail and we may be able to point to the missing piece?

guidofranceschini commented 3 weeks ago

Hi Tonihei, thanks for the prompt support. My application uses multiple players to show multiple videos on the screen, and dynamically changes the size of each video. A sort of Picture-in-Picture. I would have therefore multiple concurrently running instances of CustomTrackSelection, one for each video stream. Whenever I modify the displacement and size of the videos on the screen, I'd like to alter the allowed bitrate range for each of the videos. Maybe I have not fully understood your technique of sharing "enabledSelections", and how to control it in case of multiple instances of CustomTrackSelection, so I didn't use it.

tonihei commented 3 weeks ago

If you have different players and need to know which selection belongs to which player, I'd suggest to use separate "enabledSelections" lists for each player. If you only ever have one item in a playlist of a single player, you can also reduce the list to a single item (as only one selection will be "enabled" at any one time anyway)

guidofranceschini commented 3 weeks ago

I must admit that I don't really understand how your solution works, since I was unable to let it compile. But I have implemented a tricky solution that works as well (a static array of params, written by the application logic and read by the CustomTrackSelection class, with each instance of CustomTrackSelection being initialized with an extra "int index" to read the correct params). Thanks again for your kindness!