-
Notifications
You must be signed in to change notification settings - Fork 575
Description
Problem/Background
Currently DefaultMediaSourceFactory
does two different things:
- It selects a delegate
MediaSourceFactory
instance based on the theuri
andmimeType
of the providedMediaItem
. - It then wraps the resulting delegate
MediaSource
in additional layers ofMediaSource
implementations in order to provide support for the ads, subtitle and clipping fields ofMediaItem
.
Specifically, (2) involves:
- Wrapping the delegate in an
AdsMediaSource
to support the ads config. - Wrapping the delegate in a
ClippingMediaSource
to support the clipping config. - Creating additional
SingleSampleMediaSource
(orProgressiveMediaSource
) instances for the sideloaded subtitle tracks, and wrapping all these and main delegate in aMergingMediaSource
.
Most other DefaultFoo
types in the ExoPlayer library that delegate to leaf implementations (e.g. DefaultDataSource
) only do the delegation (1), and don't provide additional business logic (2).
The current situation can lead to some developer confusion. If an app knows it only supports DASH content but wants to also support ads then this code works:
Player player = new ExoPlayer.Builder(context)
.setMediaSourceFactory(new DefaultMediaSourceFactory(context))
.build();
player.setMediaItem(
new MediaItem.Builder()
.setUri(mpdUri)
.setAdsConfiguration(...)
.build())
But changing the player
instantiation in a way that looks completely reasonable (since we only expect to play DASH content) stops the ads from working:
Player player = new ExoPlayer.Builder(context)
.setMediaSourceFactory(new DashMediaSource.Factory(context))
.build();
Proposal
Add support for all MediaItem
properties to all leaf MediaSourceFactory
implementations. This probably means putting the existing 'wrapping' code from DefaultMediaSourceFactory
into a shared utility that can be called by each leaf implementation. The exact API of this utility is TBD.
Potential problems/caveats
Currently leaf MediaSourceFactory
implementations are declared to return the specific type of MediaSource
they relate to (e.g. DashMediaSource.Factory#createMediaSource(MediaItem)
is declared to return DashMediaSource
). However the features described in this bug are all implemented by MediaSource
wrapping, so the returned type can no longer be guaranteed to be a DashMediaSource
(e.g. if the content is clipped the outer type will be ClippingMediaSource
).
Ideas
- Where a leaf
MediaSource
implementation provides an additional public API beyond that ofMediaSource
(e.g.DashMediaSource#replaceManifestUri(Uri)
):- Change all overrides of
MediaSourceFactory#createMediaSource(MediaItem)
to declare their return type as justMediaSource
- Provide separate methods on each leaf
MediaSourceFactory
implementation that return the concrete leaf implementation type (and don't support ads, subtitles or clipping). The naming of these methods would make their purpose clear.
- Change all overrides of
- Add a
DelegatingMediaSource<S extends MediaSource>
interface with aS getDelegateSource
method. Classes likeClippingMediaSource
would implement this interface and also have to become parameterized:class ClippingMediaSource<S extends MediaSource> implements DelegatingMediaSource<S> { private final S delegate; @Override S getDelegateSource() { return delegate; } } DelegatingMediaSource<DashMediaSource> source = new DashMediaSource.Factory().createMediaSource(mediaItem); source.getDelegate().replaceManifestUri(newManifestUri);
- This is more fiddly for
MergingMediaSource
because it means one of the childMediaSource
instances has to be the 'primary' one to be returned fromgetDelegateSource()
.
- This is more fiddly for
Given that most apps should be able to use the MediaItem
API and don't need to interact with MediaSource
instances directly, it seems reasonable to stick with (1) and force apps that do want to mess directly with MediaSource
instances (and need the specific leaf type for some reason) to call a different method on the leaf MediaSourceFactory
instance in order to get the concrete type they need, instead of 'just' a MediaSource
.