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
This commit is contained in:
jbibik 2024-01-24 15:17:14 -08:00 committed by Copybara-Service
parent 85db94782a
commit f103a2dcf5
8 changed files with 84 additions and 15 deletions

View file

@ -20,6 +20,9 @@
`setSubtitleParserFactory` and disallow passing `null`. Use the new `setSubtitleParserFactory` and disallow passing `null`. Use the new
`experimentalParseSubtitlesDuringExtraction(boolean)` methods to control `experimentalParseSubtitlesDuringExtraction(boolean)` methods to control
parsing behaviour. parsing behaviour.
* Add support for customising the `SubtitleParser.Factory` used during
extraction. This can be achieved with
`MediaSource.Factory.setSubtitleParserFactory()`.
* Transformer: * Transformer:
* Track Selection: * Track Selection:
* Extractors: * Extractors:

View file

@ -52,6 +52,7 @@ import androidx.media3.extractor.TrackOutput;
import androidx.media3.extractor.jpeg.JpegExtractor; import androidx.media3.extractor.jpeg.JpegExtractor;
import androidx.media3.extractor.text.DefaultSubtitleParserFactory; import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
import androidx.media3.extractor.text.SubtitleExtractor; import androidx.media3.extractor.text.SubtitleExtractor;
import androidx.media3.extractor.text.SubtitleParser;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
@ -115,6 +116,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
private final DelegateFactoryLoader delegateFactoryLoader; private final DelegateFactoryLoader delegateFactoryLoader;
private DataSource.Factory dataSourceFactory; private DataSource.Factory dataSourceFactory;
private SubtitleParser.Factory subtitleParserFactory;
@Nullable private MediaSource.Factory serverSideAdInsertionMediaSourceFactory; @Nullable private MediaSource.Factory serverSideAdInsertionMediaSourceFactory;
@Nullable private ExternalLoader externalImageLoader; @Nullable private ExternalLoader externalImageLoader;
@Nullable private AdsLoader.Provider adsLoaderProvider; @Nullable private AdsLoader.Provider adsLoaderProvider;
@ -181,7 +183,8 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
public DefaultMediaSourceFactory( public DefaultMediaSourceFactory(
DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) { DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) {
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
delegateFactoryLoader = new DelegateFactoryLoader(extractorsFactory); this.subtitleParserFactory = new DefaultSubtitleParserFactory();
delegateFactoryLoader = new DelegateFactoryLoader(extractorsFactory, subtitleParserFactory);
delegateFactoryLoader.setDataSourceFactory(dataSourceFactory); delegateFactoryLoader.setDataSourceFactory(dataSourceFactory);
liveTargetOffsetMs = C.TIME_UNSET; liveTargetOffsetMs = C.TIME_UNSET;
liveMinOffsetMs = C.TIME_UNSET; liveMinOffsetMs = C.TIME_UNSET;
@ -200,6 +203,16 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
return this; 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 * Sets the {@link AdsLoader.Provider} that provides {@link AdsLoader} instances for media items
* that have {@link MediaItem.LocalConfiguration#adsConfiguration ads configurations}. * that have {@link MediaItem.LocalConfiguration#adsConfiguration ads configurations}.
@ -509,7 +522,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
.setLabel(subtitleConfigurations.get(i).label) .setLabel(subtitleConfigurations.get(i).label)
.setId(subtitleConfigurations.get(i).id) .setId(subtitleConfigurations.get(i).id)
.build(); .build();
DefaultSubtitleParserFactory subtitleParserFactory = new DefaultSubtitleParserFactory();
ExtractorsFactory extractorsFactory = ExtractorsFactory extractorsFactory =
() -> () ->
new Extractor[] { new Extractor[] {
@ -602,12 +614,15 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
private DataSource.@MonotonicNonNull Factory dataSourceFactory; private DataSource.@MonotonicNonNull Factory dataSourceFactory;
private boolean parseSubtitlesDuringExtraction; private boolean parseSubtitlesDuringExtraction;
private SubtitleParser.Factory subtitleParserFactory;
@Nullable private CmcdConfiguration.Factory cmcdConfigurationFactory; @Nullable private CmcdConfiguration.Factory cmcdConfigurationFactory;
@Nullable private DrmSessionManagerProvider drmSessionManagerProvider; @Nullable private DrmSessionManagerProvider drmSessionManagerProvider;
@Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy; @Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
public DelegateFactoryLoader(ExtractorsFactory extractorsFactory) { public DelegateFactoryLoader(
ExtractorsFactory extractorsFactory, SubtitleParser.Factory subtitleParserFactory) {
this.extractorsFactory = extractorsFactory; this.extractorsFactory = extractorsFactory;
this.subtitleParserFactory = subtitleParserFactory;
mediaSourceFactorySuppliers = new HashMap<>(); mediaSourceFactorySuppliers = new HashMap<>();
supportedTypes = new HashSet<>(); supportedTypes = new HashSet<>();
mediaSourceFactories = new HashMap<>(); mediaSourceFactories = new HashMap<>();
@ -641,6 +656,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
if (loadErrorHandlingPolicy != null) { if (loadErrorHandlingPolicy != null) {
mediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy); mediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
} }
mediaSourceFactory.setSubtitleParserFactory(subtitleParserFactory);
mediaSourceFactory.experimentalParseSubtitlesDuringExtraction(parseSubtitlesDuringExtraction); mediaSourceFactory.experimentalParseSubtitlesDuringExtraction(parseSubtitlesDuringExtraction);
mediaSourceFactories.put(contentType, mediaSourceFactory); mediaSourceFactories.put(contentType, mediaSourceFactory);
return 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) { public void setCmcdConfigurationFactory(CmcdConfiguration.Factory cmcdConfigurationFactory) {
this.cmcdConfigurationFactory = cmcdConfigurationFactory; this.cmcdConfigurationFactory = cmcdConfigurationFactory;
for (MediaSource.Factory mediaSourceFactory : mediaSourceFactories.values()) { for (MediaSource.Factory mediaSourceFactory : mediaSourceFactories.values()) {
@ -736,7 +760,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
mediaSourceFactorySupplier = () -> newInstance(clazz); mediaSourceFactorySupplier = () -> newInstance(clazz);
break; break;
case C.CONTENT_TYPE_OTHER: case C.CONTENT_TYPE_OTHER:
// TODO(181312195): potential setter on Default/ExtractorsFactory for subtitles
mediaSourceFactorySupplier = mediaSourceFactorySupplier =
() -> new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory); () -> new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory);
break; break;

View file

@ -30,6 +30,7 @@ import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.Allocator;
import androidx.media3.exoplayer.upstream.CmcdConfiguration; import androidx.media3.exoplayer.upstream.CmcdConfiguration;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
import androidx.media3.extractor.text.SubtitleParser;
import java.io.IOException; import java.io.IOException;
/** /**
@ -116,6 +117,19 @@ public interface MediaSource {
return this; 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 * Returns the {@link C.ContentType content types} supported by media sources created by this
* factory. * factory.

View file

@ -77,6 +77,7 @@ import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction;
import androidx.media3.exoplayer.upstream.LoaderErrorThrower; import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
import androidx.media3.exoplayer.upstream.ParsingLoadable; import androidx.media3.exoplayer.upstream.ParsingLoadable;
import androidx.media3.exoplayer.util.SntpClient; import androidx.media3.exoplayer.util.SntpClient;
import androidx.media3.extractor.text.SubtitleParser;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.math.LongMath; import com.google.common.math.LongMath;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
@ -196,6 +197,13 @@ public final class DashMediaSource extends BaseMediaSource {
return this; return this;
} }
@Override
@CanIgnoreReturnValue
public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
chunkSourceFactory.setSubtitleParserFactory(checkNotNull(subtitleParserFactory));
return this;
}
@Override @Override
@CanIgnoreReturnValue @CanIgnoreReturnValue
public Factory experimentalParseSubtitlesDuringExtraction( public Factory experimentalParseSubtitlesDuringExtraction(

View file

@ -58,6 +58,7 @@ import androidx.media3.exoplayer.upstream.CmcdConfiguration;
import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
import androidx.media3.extractor.Extractor; import androidx.media3.extractor.Extractor;
import androidx.media3.extractor.text.SubtitleParser;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
@ -197,6 +198,13 @@ public final class HlsMediaSource extends BaseMediaSource
return this; return this;
} }
@CanIgnoreReturnValue
@Override
public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
extractorFactory.setSubtitleParserFactory(checkNotNull(subtitleParserFactory));
return this;
}
@Override @Override
@CanIgnoreReturnValue @CanIgnoreReturnValue
public Factory experimentalParseSubtitlesDuringExtraction( public Factory experimentalParseSubtitlesDuringExtraction(

View file

@ -65,6 +65,7 @@ import androidx.media3.exoplayer.upstream.Loader;
import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction; import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction;
import androidx.media3.exoplayer.upstream.LoaderErrorThrower; import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
import androidx.media3.exoplayer.upstream.ParsingLoadable; import androidx.media3.exoplayer.upstream.ParsingLoadable;
import androidx.media3.extractor.text.SubtitleParser;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.IOException; import java.io.IOException;
@ -152,6 +153,13 @@ public final class SsMediaSource extends BaseMediaSource
return this; return this;
} }
@Override
@CanIgnoreReturnValue
public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
chunkSourceFactory.setSubtitleParserFactory(checkNotNull(subtitleParserFactory));
return this;
}
@Override @Override
@CanIgnoreReturnValue @CanIgnoreReturnValue
public Factory experimentalParseSubtitlesDuringExtraction( public Factory experimentalParseSubtitlesDuringExtraction(

View file

@ -368,23 +368,14 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
} }
@Override @Override
public DefaultExtractorsFactory experimentalSetTextTrackTranscodingEnabled( public synchronized DefaultExtractorsFactory experimentalSetTextTrackTranscodingEnabled(
boolean textTrackTranscodingEnabled) { boolean textTrackTranscodingEnabled) {
this.textTrackTranscodingEnabled = textTrackTranscodingEnabled; this.textTrackTranscodingEnabled = textTrackTranscodingEnabled;
return this; return this;
} }
/**
* Sets a {@link SubtitleParser.Factory} to use when transcoding text tracks.
*
* <p>This is only used if {@link #setTextTrackTranscodingEnabled(boolean)} is enabled.
*
* <p>The default value is {@link DefaultSubtitleParserFactory}.
*
* @param subtitleParserFactory The factory for {@link SubtitleParser} instances.
* @return The factory, for convenience.
*/
@CanIgnoreReturnValue @CanIgnoreReturnValue
@Override
public synchronized DefaultExtractorsFactory setSubtitleParserFactory( public synchronized DefaultExtractorsFactory setSubtitleParserFactory(
SubtitleParser.Factory subtitleParserFactory) { SubtitleParser.Factory subtitleParserFactory) {
this.subtitleParserFactory = subtitleParserFactory; this.subtitleParserFactory = subtitleParserFactory;

View file

@ -18,6 +18,7 @@ package androidx.media3.extractor;
import android.net.Uri; import android.net.Uri;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.extractor.text.SubtitleParser;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -50,6 +51,19 @@ public interface ExtractorsFactory {
return this; return this;
} }
/**
* Sets a {@link SubtitleParser.Factory} to use when transcoding text tracks.
*
* <p>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. */ /** Returns an array of new {@link Extractor} instances. */
Extractor[] createExtractors(); Extractor[] createExtractors();