From 6290d093c19cd3145f14cf6025379918677859a5 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 8 Sep 2020 10:44:24 +0100 Subject: [PATCH] Support ExtractorFactory in DefaultMediaSourceFactory. This allows to customize extractor flags more easily when setting up the player. In addition, we need to provide a way to pass in the ExtractorFactory through the constructor chain starting in SimpleExoPlayer so that removing the DefaultExtractorsFactory is possible for R8. PiperOrigin-RevId: 330472935 --- .../android/exoplayer2/SimpleExoPlayer.java | 36 ++++++++++++++--- .../exoplayer2/offline/DownloadHelper.java | 3 +- .../source/DefaultMediaSourceFactory.java | 40 ++++++++++++------- .../exoplayer2/source/MediaSourceFactory.java | 10 +++-- .../extractor/ExtractorsFactory.java | 6 +++ 5 files changed, 71 insertions(+), 24 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 787946d6a94..ba3a375a377 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -38,6 +38,8 @@ import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.device.DeviceInfo; import com.google.android.exoplayer2.device.DeviceListener; +import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; @@ -52,6 +54,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; +import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Log; @@ -115,9 +118,11 @@ public static final class Builder { /** * Creates a builder. * - *

Use {@link #Builder(Context, RenderersFactory)} instead, if you intend to provide a custom - * {@link RenderersFactory}. This is to ensure that ProGuard or R8 can remove ExoPlayer's {@link - * DefaultRenderersFactory} from the APK. + *

Use {@link #Builder(Context, RenderersFactory)} or {@link #Builder(Context, + * RenderersFactory, ExtractorsFactory)} instead, if you intend to provide a custom {@link + * RenderersFactory} or a custom {@link ExtractorsFactory}. This is to ensure that ProGuard or + * R8 can remove ExoPlayer's {@link DefaultRenderersFactory} and {@link + * DefaultExtractorsFactory} from the APK. * *

The builder uses the following default values: * @@ -146,7 +151,7 @@ public static final class Builder { * @param context A {@link Context}. */ public Builder(Context context) { - this(context, new DefaultRenderersFactory(context)); + this(context, new DefaultRenderersFactory(context), new DefaultExtractorsFactory()); } /** @@ -159,11 +164,30 @@ public Builder(Context context) { * player. */ public Builder(Context context, RenderersFactory renderersFactory) { + this(context, renderersFactory, new DefaultExtractorsFactory()); + } + + /** + * Creates a builder with a custom {@link RenderersFactory} and {@link ExtractorsFactory}. + * + *

See {@link #Builder(Context)} for a list of default values. + * + * @param context A {@link Context}. + * @param renderersFactory A factory for creating {@link Renderer Renderers} to be used by the + * player. + * @param extractorsFactory An {@link ExtractorsFactory} used to extract progressive media from + * its container. + */ + public Builder( + Context context, RenderersFactory renderersFactory, ExtractorsFactory extractorsFactory) { this( context, renderersFactory, new DefaultTrackSelector(context), - new DefaultMediaSourceFactory(context), + new DefaultMediaSourceFactory( + new DefaultDataSourceFactory( + context, Util.getUserAgent(context, ExoPlayerLibraryInfo.VERSION_SLASHY)), + extractorsFactory), new DefaultLoadControl(), DefaultBandwidthMeter.getSingletonInstance(context), new AnalyticsCollector(Clock.DEFAULT)); @@ -546,7 +570,7 @@ protected SimpleExoPlayer( Clock clock, Looper applicationLooper) { this( - new Builder(context, renderersFactory) + new Builder(context, renderersFactory, new DefaultExtractorsFactory()) .setTrackSelector(trackSelector) .setMediaSourceFactory(mediaSourceFactory) .setLoadControl(loadControl) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java index dd868f98225..ba8a799381a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; @@ -889,7 +890,7 @@ private static MediaSource createMediaSourceInternal( MediaItem mediaItem, DataSource.Factory dataSourceFactory, @Nullable DrmSessionManager drmSessionManager) { - return new DefaultMediaSourceFactory(dataSourceFactory) + return new DefaultMediaSourceFactory(dataSourceFactory, ExtractorsFactory.EMPTY) .setDrmSessionManager(drmSessionManager) .createMediaSource(mediaItem); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java index 89b4ffb6a59..df1f3e2cf04 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java @@ -23,13 +23,14 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; +import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.source.ads.AdsLoader; import com.google.android.exoplayer2.source.ads.AdsLoader.AdViewProvider; import com.google.android.exoplayer2.source.ads.AdsMediaSource; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; -import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.util.Assertions; @@ -64,9 +65,10 @@ *

  • {@link ProgressiveMediaSource.Factory} serves as a fallback if the item's {@link * MediaItem.PlaybackProperties#uri uri} doesn't match one of the above. It tries to infer the * required extractor by using the {@link - * com.google.android.exoplayer2.extractor.DefaultExtractorsFactory}. An {@link - * UnrecognizedInputFormatException} is thrown if none of the available extractors can read - * the stream. + * com.google.android.exoplayer2.extractor.DefaultExtractorsFactory} or the {@link + * ExtractorsFactory} provided in {@link #DefaultMediaSourceFactory(DataSource.Factory, + * ExtractorsFactory)}. An {@link UnrecognizedInputFormatException} is thrown if none of the + * available extractors can read the stream. * * *

    Ad support for media items with ad tag URIs

    @@ -105,6 +107,7 @@ public interface AdsLoaderProvider { @Nullable private AdViewProvider adViewProvider; @Nullable private DrmSessionManager drmSessionManager; @Nullable private List streamKeys; + @Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy; /** * Creates a new instance. @@ -124,9 +127,22 @@ public DefaultMediaSourceFactory(Context context) { * for requesting media data. */ public DefaultMediaSourceFactory(DataSource.Factory dataSourceFactory) { + this(dataSourceFactory, new DefaultExtractorsFactory()); + } + + /** + * Creates a new instance. + * + * @param dataSourceFactory A {@link DataSource.Factory} to create {@link DataSource} instances + * for requesting media data. + * @param extractorsFactory An {@link ExtractorsFactory} used to extract progressive media from + * its container. + */ + public DefaultMediaSourceFactory( + DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) { this.dataSourceFactory = dataSourceFactory; mediaSourceDrmHelper = new MediaSourceDrmHelper(); - mediaSourceFactories = loadDelegates(dataSourceFactory); + mediaSourceFactories = loadDelegates(dataSourceFactory, extractorsFactory); supportedTypes = new int[mediaSourceFactories.size()]; for (int i = 0; i < mediaSourceFactories.size(); i++) { supportedTypes[i] = mediaSourceFactories.keyAt(i); @@ -180,13 +196,7 @@ public DefaultMediaSourceFactory setDrmSessionManager( @Override public DefaultMediaSourceFactory setLoadErrorHandlingPolicy( @Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) { - LoadErrorHandlingPolicy newLoadErrorHandlingPolicy = - loadErrorHandlingPolicy != null - ? loadErrorHandlingPolicy - : new DefaultLoadErrorHandlingPolicy(); - for (int i = 0; i < mediaSourceFactories.size(); i++) { - mediaSourceFactories.valueAt(i).setLoadErrorHandlingPolicy(newLoadErrorHandlingPolicy); - } + this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; return this; } @@ -224,6 +234,7 @@ public MediaSource createMediaSource(MediaItem mediaItem) { !mediaItem.playbackProperties.streamKeys.isEmpty() ? mediaItem.playbackProperties.streamKeys : streamKeys); + mediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy); MediaSource mediaSource = mediaSourceFactory.createMediaSource(mediaItem); @@ -285,7 +296,7 @@ private MediaSource maybeWrapWithAdsMediaSource(MediaItem mediaItem, MediaSource } private static SparseArray loadDelegates( - DataSource.Factory dataSourceFactory) { + DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) { SparseArray factories = new SparseArray<>(); // LINT.IfChange try { @@ -320,7 +331,8 @@ private static SparseArray loadDelegates( // Expected if the app was built without the hls module. } // LINT.ThenChange(../../../../../../../../proguard-rules.txt) - factories.put(C.TYPE_OTHER, new ProgressiveMediaSource.Factory(dataSourceFactory)); + factories.put( + C.TYPE_OTHER, new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory)); return factories; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java index 4175121d385..204220e334e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java @@ -24,6 +24,7 @@ import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; +import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import java.util.List; @@ -59,7 +60,8 @@ default MediaSourceFactory setStreamKeys(@Nullable List streamKeys) { * Sets the {@link DrmSessionManager} to use for all media items regardless of their {@link * MediaItem.DrmConfiguration}. * - * @param drmSessionManager The {@link DrmSessionManager}. + * @param drmSessionManager The {@link DrmSessionManager}, or {@code null} to use the {@link + * DefaultDrmSessionManager}. * @return This factory, for convenience. */ MediaSourceFactory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager); @@ -85,7 +87,8 @@ MediaSourceFactory setDrmHttpDataSourceFactory( * #setDrmHttpDataSourceFactory(HttpDataSource.Factory)} or a {@link DrmSessionManager} has been * set by {@link #setDrmSessionManager(DrmSessionManager)}, this user agent is ignored. * - * @param userAgent The user agent to be used for DRM requests. + * @param userAgent The user agent to be used for DRM requests, or {@code null} to use the + * default. * @return This factory, for convenience. */ MediaSourceFactory setDrmUserAgent(@Nullable String userAgent); @@ -93,7 +96,8 @@ MediaSourceFactory setDrmHttpDataSourceFactory( /** * Sets an optional {@link LoadErrorHandlingPolicy}. * - * @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}. + * @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}, or {@code null} to use the + * {@link DefaultLoadErrorHandlingPolicy}. * @return This factory, for convenience. */ MediaSourceFactory setLoadErrorHandlingPolicy( diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java index d077b1b11ef..97ae74b9d23 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java @@ -22,6 +22,12 @@ /** Factory for arrays of {@link Extractor} instances. */ public interface ExtractorsFactory { + /** + * Extractor factory that returns an empty list of extractors. Can be used whenever {@link + * Extractor Extractors} are not required. + */ + ExtractorsFactory EMPTY = () -> new Extractor[] {}; + /** Returns an array of new {@link Extractor} instances. */ Extractor[] createExtractors();