这是indexloc提供的服务,不要输入任何密码
Skip to content

Move ads, clipping & subtitle support from DefaultMediaSourceFactory into 'leaf' MediaSource.Factory implementations #185

@icbaker

Description

@icbaker

Problem/Background

Currently DefaultMediaSourceFactory does two different things:

  1. It selects a delegate MediaSourceFactory instance based on the the uri and mimeType of the provided MediaItem.
  2. It then wraps the resulting delegate MediaSource in additional layers of MediaSource implementations in order to provide support for the ads, subtitle and clipping fields of MediaItem.

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 (or ProgressiveMediaSource) instances for the sideloaded subtitle tracks, and wrapping all these and main delegate in a MergingMediaSource.

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

  1. Where a leaf MediaSource implementation provides an additional public API beyond that of MediaSource (e.g. DashMediaSource#replaceManifestUri(Uri)):
    • Change all overrides of MediaSourceFactory#createMediaSource(MediaItem) to declare their return type as just MediaSource
    • 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.
  2. Add a DelegatingMediaSource<S extends MediaSource> interface with a S getDelegateSource method. Classes like ClippingMediaSource 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 child MediaSource instances has to be the 'primary' one to be returned from getDelegateSource().

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions