From f103a2dcf565a311b94171e5714e4ee8ad8c5f65 Mon Sep 17 00:00:00 2001 From: jbibik Date: Wed, 24 Jan 2024 15:17:14 -0800 Subject: [PATCH] Add a setter of `SubtitleParser.Factory` to `MediaSource.Factory` DASH: `DashMediaSource.Factory` would only propagate it to `DashChunkSource.Factory` -> `BundledChunkExtractor.Factory` SS: `SSMediaSource.Factory` -> `SsChunkSource.Factory` HLS: `HlsMediaSource.Factory` -> `HlsExtractorFactory` Remove nullability of SubtitleParser.Factory across the stack #minor-release PiperOrigin-RevId: 601250013 --- RELEASENOTES.md | 3 ++ .../source/DefaultMediaSourceFactory.java | 31 ++++++++++++++++--- .../media3/exoplayer/source/MediaSource.java | 14 +++++++++ .../exoplayer/dash/DashMediaSource.java | 8 +++++ .../media3/exoplayer/hls/HlsMediaSource.java | 8 +++++ .../smoothstreaming/SsMediaSource.java | 8 +++++ .../extractor/DefaultExtractorsFactory.java | 13 ++------ .../media3/extractor/ExtractorsFactory.java | 14 +++++++++ 8 files changed, 84 insertions(+), 15 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 787b026ed1..cb3281e077 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -20,6 +20,9 @@ `setSubtitleParserFactory` and disallow passing `null`. Use the new `experimentalParseSubtitlesDuringExtraction(boolean)` methods to control parsing behaviour. + * Add support for customising the `SubtitleParser.Factory` used during + extraction. This can be achieved with + `MediaSource.Factory.setSubtitleParserFactory()`. * Transformer: * Track Selection: * Extractors: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/DefaultMediaSourceFactory.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/DefaultMediaSourceFactory.java index 5099ded718..a3cad75df2 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/DefaultMediaSourceFactory.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/DefaultMediaSourceFactory.java @@ -52,6 +52,7 @@ import androidx.media3.extractor.TrackOutput; import androidx.media3.extractor.jpeg.JpegExtractor; import androidx.media3.extractor.text.DefaultSubtitleParserFactory; import androidx.media3.extractor.text.SubtitleExtractor; +import androidx.media3.extractor.text.SubtitleParser; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Ints; @@ -115,6 +116,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { private final DelegateFactoryLoader delegateFactoryLoader; private DataSource.Factory dataSourceFactory; + private SubtitleParser.Factory subtitleParserFactory; @Nullable private MediaSource.Factory serverSideAdInsertionMediaSourceFactory; @Nullable private ExternalLoader externalImageLoader; @Nullable private AdsLoader.Provider adsLoaderProvider; @@ -181,7 +183,8 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { public DefaultMediaSourceFactory( DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) { this.dataSourceFactory = dataSourceFactory; - delegateFactoryLoader = new DelegateFactoryLoader(extractorsFactory); + this.subtitleParserFactory = new DefaultSubtitleParserFactory(); + delegateFactoryLoader = new DelegateFactoryLoader(extractorsFactory, subtitleParserFactory); delegateFactoryLoader.setDataSourceFactory(dataSourceFactory); liveTargetOffsetMs = C.TIME_UNSET; liveMinOffsetMs = C.TIME_UNSET; @@ -200,6 +203,16 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { return this; } + @CanIgnoreReturnValue + @Override + @UnstableApi + public DefaultMediaSourceFactory setSubtitleParserFactory( + SubtitleParser.Factory subtitleParserFactory) { + this.subtitleParserFactory = checkNotNull(subtitleParserFactory); + delegateFactoryLoader.setSubtitleParserFactory(subtitleParserFactory); + return this; + } + /** * Sets the {@link AdsLoader.Provider} that provides {@link AdsLoader} instances for media items * that have {@link MediaItem.LocalConfiguration#adsConfiguration ads configurations}. @@ -509,7 +522,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { .setLabel(subtitleConfigurations.get(i).label) .setId(subtitleConfigurations.get(i).id) .build(); - DefaultSubtitleParserFactory subtitleParserFactory = new DefaultSubtitleParserFactory(); ExtractorsFactory extractorsFactory = () -> new Extractor[] { @@ -602,12 +614,15 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { private DataSource.@MonotonicNonNull Factory dataSourceFactory; private boolean parseSubtitlesDuringExtraction; + private SubtitleParser.Factory subtitleParserFactory; @Nullable private CmcdConfiguration.Factory cmcdConfigurationFactory; @Nullable private DrmSessionManagerProvider drmSessionManagerProvider; @Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy; - public DelegateFactoryLoader(ExtractorsFactory extractorsFactory) { + public DelegateFactoryLoader( + ExtractorsFactory extractorsFactory, SubtitleParser.Factory subtitleParserFactory) { this.extractorsFactory = extractorsFactory; + this.subtitleParserFactory = subtitleParserFactory; mediaSourceFactorySuppliers = new HashMap<>(); supportedTypes = new HashSet<>(); mediaSourceFactories = new HashMap<>(); @@ -641,6 +656,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { if (loadErrorHandlingPolicy != null) { mediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy); } + mediaSourceFactory.setSubtitleParserFactory(subtitleParserFactory); mediaSourceFactory.experimentalParseSubtitlesDuringExtraction(parseSubtitlesDuringExtraction); mediaSourceFactories.put(contentType, mediaSourceFactory); return mediaSourceFactory; @@ -665,6 +681,14 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { } } + public void setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) { + this.subtitleParserFactory = subtitleParserFactory; + extractorsFactory.setSubtitleParserFactory(subtitleParserFactory); + for (MediaSource.Factory mediaSourceFactory : mediaSourceFactories.values()) { + mediaSourceFactory.setSubtitleParserFactory(subtitleParserFactory); + } + } + public void setCmcdConfigurationFactory(CmcdConfiguration.Factory cmcdConfigurationFactory) { this.cmcdConfigurationFactory = cmcdConfigurationFactory; for (MediaSource.Factory mediaSourceFactory : mediaSourceFactories.values()) { @@ -736,7 +760,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { mediaSourceFactorySupplier = () -> newInstance(clazz); break; case C.CONTENT_TYPE_OTHER: - // TODO(181312195): potential setter on Default/ExtractorsFactory for subtitles mediaSourceFactorySupplier = () -> new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory); break; diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java index df11e91827..8bed520e77 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java @@ -30,6 +30,7 @@ import androidx.media3.exoplayer.drm.DrmSessionManagerProvider; import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.CmcdConfiguration; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; +import androidx.media3.extractor.text.SubtitleParser; import java.io.IOException; /** @@ -116,6 +117,19 @@ public interface MediaSource { return this; } + /** + * Sets the {@link SubtitleParser.Factory} to be used for parsing subtitles during extraction if + * {@link #experimentalParseSubtitlesDuringExtraction} is enabled. + * + * @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during + * extraction. + * @return This factory, for convenience. + */ + @UnstableApi + default Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) { + return this; + } + /** * Returns the {@link C.ContentType content types} supported by media sources created by this * factory. diff --git a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaSource.java b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaSource.java index 6a1527d8bc..7a8b305b1a 100644 --- a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaSource.java +++ b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaSource.java @@ -77,6 +77,7 @@ import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction; import androidx.media3.exoplayer.upstream.LoaderErrorThrower; import androidx.media3.exoplayer.upstream.ParsingLoadable; import androidx.media3.exoplayer.util.SntpClient; +import androidx.media3.extractor.text.SubtitleParser; import com.google.common.base.Charsets; import com.google.common.math.LongMath; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -196,6 +197,13 @@ public final class DashMediaSource extends BaseMediaSource { return this; } + @Override + @CanIgnoreReturnValue + public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) { + chunkSourceFactory.setSubtitleParserFactory(checkNotNull(subtitleParserFactory)); + return this; + } + @Override @CanIgnoreReturnValue public Factory experimentalParseSubtitlesDuringExtraction( diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaSource.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaSource.java index 4cf377982e..6a0d18cdc2 100644 --- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaSource.java +++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaSource.java @@ -58,6 +58,7 @@ import androidx.media3.exoplayer.upstream.CmcdConfiguration; import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; import androidx.media3.extractor.Extractor; +import androidx.media3.extractor.text.SubtitleParser; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; import java.lang.annotation.Documented; @@ -197,6 +198,13 @@ public final class HlsMediaSource extends BaseMediaSource return this; } + @CanIgnoreReturnValue + @Override + public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) { + extractorFactory.setSubtitleParserFactory(checkNotNull(subtitleParserFactory)); + return this; + } + @Override @CanIgnoreReturnValue public Factory experimentalParseSubtitlesDuringExtraction( diff --git a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaSource.java b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaSource.java index ca252621f3..b198aaedae 100644 --- a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaSource.java +++ b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaSource.java @@ -65,6 +65,7 @@ import androidx.media3.exoplayer.upstream.Loader; import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction; import androidx.media3.exoplayer.upstream.LoaderErrorThrower; import androidx.media3.exoplayer.upstream.ParsingLoadable; +import androidx.media3.extractor.text.SubtitleParser; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; @@ -152,6 +153,13 @@ public final class SsMediaSource extends BaseMediaSource return this; } + @Override + @CanIgnoreReturnValue + public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) { + chunkSourceFactory.setSubtitleParserFactory(checkNotNull(subtitleParserFactory)); + return this; + } + @Override @CanIgnoreReturnValue public Factory experimentalParseSubtitlesDuringExtraction( diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java index 2cc408f825..d32a71ea6d 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java @@ -368,23 +368,14 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { } @Override - public DefaultExtractorsFactory experimentalSetTextTrackTranscodingEnabled( + public synchronized DefaultExtractorsFactory experimentalSetTextTrackTranscodingEnabled( boolean textTrackTranscodingEnabled) { this.textTrackTranscodingEnabled = textTrackTranscodingEnabled; return this; } - /** - * Sets a {@link SubtitleParser.Factory} to use when transcoding text tracks. - * - *

This is only used if {@link #setTextTrackTranscodingEnabled(boolean)} is enabled. - * - *

The default value is {@link DefaultSubtitleParserFactory}. - * - * @param subtitleParserFactory The factory for {@link SubtitleParser} instances. - * @return The factory, for convenience. - */ @CanIgnoreReturnValue + @Override public synchronized DefaultExtractorsFactory setSubtitleParserFactory( SubtitleParser.Factory subtitleParserFactory) { this.subtitleParserFactory = subtitleParserFactory; diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java index a37b36d3dc..525dbb7a79 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java @@ -18,6 +18,7 @@ package androidx.media3.extractor; import android.net.Uri; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; +import androidx.media3.extractor.text.SubtitleParser; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.List; import java.util.Map; @@ -50,6 +51,19 @@ public interface ExtractorsFactory { return this; } + /** + * Sets a {@link SubtitleParser.Factory} to use when transcoding text tracks. + * + *

This is only works if {@link #experimentalSetTextTrackTranscodingEnabled(boolean)} is + * enabled. + * + * @param subtitleParserFactory The factory for {@link SubtitleParser} instances. + * @return The factory, for convenience. + */ + default ExtractorsFactory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) { + return this; + } + /** Returns an array of new {@link Extractor} instances. */ Extractor[] createExtractors();