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
This commit is contained in:
tonihei 2020-09-08 10:44:24 +01:00 committed by Oliver Woodman
parent 3110587fbe
commit bfe17aee3e
5 changed files with 71 additions and 24 deletions

View File

@ -38,6 +38,8 @@ import com.google.android.exoplayer2.audio.AuxEffectInfo;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.device.DeviceInfo; import com.google.android.exoplayer2.device.DeviceInfo;
import com.google.android.exoplayer2.device.DeviceListener; 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.Metadata;
import com.google.android.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.metadata.MetadataOutput;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
@ -52,6 +54,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; 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.Assertions;
import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
@ -115,9 +118,11 @@ public class SimpleExoPlayer extends BasePlayer
/** /**
* Creates a builder. * Creates a builder.
* *
* <p>Use {@link #Builder(Context, RenderersFactory)} instead, if you intend to provide a custom * <p>Use {@link #Builder(Context, RenderersFactory)} or {@link #Builder(Context,
* {@link RenderersFactory}. This is to ensure that ProGuard or R8 can remove ExoPlayer's {@link * RenderersFactory, ExtractorsFactory)} instead, if you intend to provide a custom {@link
* DefaultRenderersFactory} from the APK. * 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.
* *
* <p>The builder uses the following default values: * <p>The builder uses the following default values:
* *
@ -146,7 +151,7 @@ public class SimpleExoPlayer extends BasePlayer
* @param context A {@link Context}. * @param context A {@link Context}.
*/ */
public Builder(Context context) { public Builder(Context context) {
this(context, new DefaultRenderersFactory(context)); this(context, new DefaultRenderersFactory(context), new DefaultExtractorsFactory());
} }
/** /**
@ -159,11 +164,30 @@ public class SimpleExoPlayer extends BasePlayer
* player. * player.
*/ */
public Builder(Context context, RenderersFactory renderersFactory) { public Builder(Context context, RenderersFactory renderersFactory) {
this(context, renderersFactory, new DefaultExtractorsFactory());
}
/**
* Creates a builder with a custom {@link RenderersFactory} and {@link ExtractorsFactory}.
*
* <p>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( this(
context, context,
renderersFactory, renderersFactory,
new DefaultTrackSelector(context), new DefaultTrackSelector(context),
new DefaultMediaSourceFactory(context), new DefaultMediaSourceFactory(
new DefaultDataSourceFactory(
context, Util.getUserAgent(context, ExoPlayerLibraryInfo.VERSION_SLASHY)),
extractorsFactory),
new DefaultLoadControl(), new DefaultLoadControl(),
DefaultBandwidthMeter.getSingletonInstance(context), DefaultBandwidthMeter.getSingletonInstance(context),
new AnalyticsCollector(Clock.DEFAULT)); new AnalyticsCollector(Clock.DEFAULT));
@ -546,7 +570,7 @@ public class SimpleExoPlayer extends BasePlayer
Clock clock, Clock clock,
Looper applicationLooper) { Looper applicationLooper) {
this( this(
new Builder(context, renderersFactory) new Builder(context, renderersFactory, new DefaultExtractorsFactory())
.setTrackSelector(trackSelector) .setTrackSelector(trackSelector)
.setMediaSourceFactory(mediaSourceFactory) .setMediaSourceFactory(mediaSourceFactory)
.setLoadControl(loadControl) .setLoadControl(loadControl)

View File

@ -34,6 +34,7 @@ import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.drm.DrmSessionManager; 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.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
@ -889,7 +890,7 @@ public final class DownloadHelper {
MediaItem mediaItem, MediaItem mediaItem,
DataSource.Factory dataSourceFactory, DataSource.Factory dataSourceFactory,
@Nullable DrmSessionManager drmSessionManager) { @Nullable DrmSessionManager drmSessionManager) {
return new DefaultMediaSourceFactory(dataSourceFactory) return new DefaultMediaSourceFactory(dataSourceFactory, ExtractorsFactory.EMPTY)
.setDrmSessionManager(drmSessionManager) .setDrmSessionManager(drmSessionManager)
.createMediaSource(mediaItem); .createMediaSource(mediaItem);
} }

View File

@ -23,13 +23,14 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.drm.DrmSessionManager; 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.offline.StreamKey;
import com.google.android.exoplayer2.source.ads.AdsLoader; import com.google.android.exoplayer2.source.ads.AdsLoader;
import com.google.android.exoplayer2.source.ads.AdsLoader.AdViewProvider; import com.google.android.exoplayer2.source.ads.AdsLoader.AdViewProvider;
import com.google.android.exoplayer2.source.ads.AdsMediaSource; import com.google.android.exoplayer2.source.ads.AdsMediaSource;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; 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.HttpDataSource;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
@ -64,9 +65,10 @@ import java.util.List;
* <li>{@link ProgressiveMediaSource.Factory} serves as a fallback if the item's {@link * <li>{@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 * MediaItem.PlaybackProperties#uri uri} doesn't match one of the above. It tries to infer the
* required extractor by using the {@link * required extractor by using the {@link
* com.google.android.exoplayer2.extractor.DefaultExtractorsFactory}. An {@link * com.google.android.exoplayer2.extractor.DefaultExtractorsFactory} or the {@link
* UnrecognizedInputFormatException} is thrown if none of the available extractors can read * ExtractorsFactory} provided in {@link #DefaultMediaSourceFactory(DataSource.Factory,
* the stream. * ExtractorsFactory)}. An {@link UnrecognizedInputFormatException} is thrown if none of the
* available extractors can read the stream.
* </ul> * </ul>
* *
* <h3>Ad support for media items with ad tag URIs</h3> * <h3>Ad support for media items with ad tag URIs</h3>
@ -105,6 +107,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
@Nullable private AdViewProvider adViewProvider; @Nullable private AdViewProvider adViewProvider;
@Nullable private DrmSessionManager drmSessionManager; @Nullable private DrmSessionManager drmSessionManager;
@Nullable private List<StreamKey> streamKeys; @Nullable private List<StreamKey> streamKeys;
@Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
/** /**
* Creates a new instance. * Creates a new instance.
@ -124,9 +127,22 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* for requesting media data. * for requesting media data.
*/ */
public DefaultMediaSourceFactory(DataSource.Factory dataSourceFactory) { 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; this.dataSourceFactory = dataSourceFactory;
mediaSourceDrmHelper = new MediaSourceDrmHelper(); mediaSourceDrmHelper = new MediaSourceDrmHelper();
mediaSourceFactories = loadDelegates(dataSourceFactory); mediaSourceFactories = loadDelegates(dataSourceFactory, extractorsFactory);
supportedTypes = new int[mediaSourceFactories.size()]; supportedTypes = new int[mediaSourceFactories.size()];
for (int i = 0; i < mediaSourceFactories.size(); i++) { for (int i = 0; i < mediaSourceFactories.size(); i++) {
supportedTypes[i] = mediaSourceFactories.keyAt(i); supportedTypes[i] = mediaSourceFactories.keyAt(i);
@ -180,13 +196,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
@Override @Override
public DefaultMediaSourceFactory setLoadErrorHandlingPolicy( public DefaultMediaSourceFactory setLoadErrorHandlingPolicy(
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) { @Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
LoadErrorHandlingPolicy newLoadErrorHandlingPolicy = this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
loadErrorHandlingPolicy != null
? loadErrorHandlingPolicy
: new DefaultLoadErrorHandlingPolicy();
for (int i = 0; i < mediaSourceFactories.size(); i++) {
mediaSourceFactories.valueAt(i).setLoadErrorHandlingPolicy(newLoadErrorHandlingPolicy);
}
return this; return this;
} }
@ -224,6 +234,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
!mediaItem.playbackProperties.streamKeys.isEmpty() !mediaItem.playbackProperties.streamKeys.isEmpty()
? mediaItem.playbackProperties.streamKeys ? mediaItem.playbackProperties.streamKeys
: streamKeys); : streamKeys);
mediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
MediaSource mediaSource = mediaSourceFactory.createMediaSource(mediaItem); MediaSource mediaSource = mediaSourceFactory.createMediaSource(mediaItem);
@ -285,7 +296,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
} }
private static SparseArray<MediaSourceFactory> loadDelegates( private static SparseArray<MediaSourceFactory> loadDelegates(
DataSource.Factory dataSourceFactory) { DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) {
SparseArray<MediaSourceFactory> factories = new SparseArray<>(); SparseArray<MediaSourceFactory> factories = new SparseArray<>();
// LINT.IfChange // LINT.IfChange
try { try {
@ -320,7 +331,8 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
// Expected if the app was built without the hls module. // Expected if the app was built without the hls module.
} }
// LINT.ThenChange(../../../../../../../../proguard-rules.txt) // 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; return factories;
} }
} }

View File

@ -24,6 +24,7 @@ import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; 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.HttpDataSource;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import java.util.List; import java.util.List;
@ -59,7 +60,8 @@ public interface MediaSourceFactory {
* Sets the {@link DrmSessionManager} to use for all media items regardless of their {@link * Sets the {@link DrmSessionManager} to use for all media items regardless of their {@link
* MediaItem.DrmConfiguration}. * 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. * @return This factory, for convenience.
*/ */
MediaSourceFactory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager); MediaSourceFactory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager);
@ -85,7 +87,8 @@ public interface MediaSourceFactory {
* #setDrmHttpDataSourceFactory(HttpDataSource.Factory)} or a {@link DrmSessionManager} has been * #setDrmHttpDataSourceFactory(HttpDataSource.Factory)} or a {@link DrmSessionManager} has been
* set by {@link #setDrmSessionManager(DrmSessionManager)}, this user agent is ignored. * 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. * @return This factory, for convenience.
*/ */
MediaSourceFactory setDrmUserAgent(@Nullable String userAgent); MediaSourceFactory setDrmUserAgent(@Nullable String userAgent);
@ -93,7 +96,8 @@ public interface MediaSourceFactory {
/** /**
* Sets an optional {@link LoadErrorHandlingPolicy}. * 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. * @return This factory, for convenience.
*/ */
MediaSourceFactory setLoadErrorHandlingPolicy( MediaSourceFactory setLoadErrorHandlingPolicy(

View File

@ -22,6 +22,12 @@ import java.util.Map;
/** Factory for arrays of {@link Extractor} instances. */ /** Factory for arrays of {@link Extractor} instances. */
public interface ExtractorsFactory { 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. */ /** Returns an array of new {@link Extractor} instances. */
Extractor[] createExtractors(); Extractor[] createExtractors();