Add setters of SubtitleParser.Factory and experimental toggle
The `SubtitleParser.Factory` is no longer @Nullable and the experimenting toggle is used to enable/disable the use of this factory for subtitle parsing during extraction. The three places that will hold the "truth" for the `SubtitleParser.Factory` are: BundledChunkExtractor.Factory, SsChunkSource.Factory, DefaultHlsExtractorFactory DASH: `DashMediaSource.Factory` would only propagate it to `DashChunkSource.Factory` -> `BundledChunkExtractor.Factory` SS: `SSMediaSource.Factory` -> `SsChunkSource.Factory` HLS: `HlsMediaSource.Factory` -> `HlsExtractorFactory` #minor-release PiperOrigin-RevId: 601151615
This commit is contained in:
parent
0acf6902e5
commit
4d7b23f0d1
@ -15,6 +15,11 @@
|
|||||||
implementing a custom `CompositeSequenceableLoaderFactory`.
|
implementing a custom `CompositeSequenceableLoaderFactory`.
|
||||||
* Fix issue where repeating the same time causes metadata from this item
|
* Fix issue where repeating the same time causes metadata from this item
|
||||||
to be cleared ([#1007](https://github.com/androidx/media/issues/1007)).
|
to be cleared ([#1007](https://github.com/androidx/media/issues/1007)).
|
||||||
|
* Rename `experimentalSetSubtitleParserFactory` methods on
|
||||||
|
`BundledChunkExtractor.Factory` and `DefaultHlsExtractorFactory` to
|
||||||
|
`setSubtitleParserFactory` and disallow passing `null`. Use the new
|
||||||
|
`experimentalParseSubtitlesDuringExtraction(boolean)` methods to control
|
||||||
|
parsing behaviour.
|
||||||
* Transformer:
|
* Transformer:
|
||||||
* Track Selection:
|
* Track Selection:
|
||||||
* Extractors:
|
* Extractors:
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.exoplayer.source.chunk;
|
package androidx.media3.exoplayer.source.chunk;
|
||||||
|
|
||||||
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Util.castNonNull;
|
import static androidx.media3.common.util.Util.castNonNull;
|
||||||
|
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@ -39,9 +40,11 @@ import androidx.media3.extractor.jpeg.JpegExtractor;
|
|||||||
import androidx.media3.extractor.mkv.MatroskaExtractor;
|
import androidx.media3.extractor.mkv.MatroskaExtractor;
|
||||||
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
||||||
import androidx.media3.extractor.png.PngExtractor;
|
import androidx.media3.extractor.png.PngExtractor;
|
||||||
|
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 androidx.media3.extractor.text.SubtitleParser;
|
||||||
import androidx.media3.extractor.text.SubtitleTranscodingExtractor;
|
import androidx.media3.extractor.text.SubtitleTranscodingExtractor;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -57,24 +60,25 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
|||||||
/** {@link ChunkExtractor.Factory} for {@link BundledChunkExtractor}. */
|
/** {@link ChunkExtractor.Factory} for {@link BundledChunkExtractor}. */
|
||||||
public static final class Factory implements ChunkExtractor.Factory {
|
public static final class Factory implements ChunkExtractor.Factory {
|
||||||
|
|
||||||
/** Non-null if subtitles should be parsed during extraction, null otherwise. */
|
private SubtitleParser.Factory subtitleParserFactory;
|
||||||
@Nullable private SubtitleParser.Factory subtitleParserFactory;
|
private boolean parseSubtitlesDuringExtraction;
|
||||||
|
|
||||||
/**
|
public Factory() {
|
||||||
* Sets the {@link SubtitleParser.Factory} to use for parsing subtitles during extraction, or
|
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
||||||
* null to parse subtitles during decoding. The default is null (subtitles parsed after
|
}
|
||||||
* decoding).
|
|
||||||
*
|
@CanIgnoreReturnValue
|
||||||
* <p>This method is experimental. Its default value may change, or it may be renamed or removed
|
@Override
|
||||||
* in a future release.
|
public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
*
|
this.subtitleParserFactory = checkNotNull(subtitleParserFactory);
|
||||||
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
return this;
|
||||||
* extraction.
|
}
|
||||||
* @return This factory, for convenience.
|
|
||||||
*/
|
@CanIgnoreReturnValue
|
||||||
public Factory experimentalSetSubtitleParserFactory(
|
@Override
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
public Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
this.subtitleParserFactory = subtitleParserFactory;
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
this.parseSubtitlesDuringExtraction = parseSubtitlesDuringExtraction;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,18 +89,16 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
|||||||
* MimeTypes#APPLICATION_MEDIA3_CUES} if it is supported by {@link SubtitleParser.Factory}.
|
* MimeTypes#APPLICATION_MEDIA3_CUES} if it is supported by {@link SubtitleParser.Factory}.
|
||||||
*
|
*
|
||||||
* <p>To modify the support behavior, you can {@linkplain
|
* <p>To modify the support behavior, you can {@linkplain
|
||||||
* #experimentalSetSubtitleParserFactory(SubtitleParser.Factory) set your own subtitle parser
|
* #setSubtitleParserFactory(SubtitleParser.Factory) set your own subtitle parser factory}.
|
||||||
* factory}.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Format getOutputTextFormat(Format sourceFormat) {
|
public Format getOutputTextFormat(Format sourceFormat) {
|
||||||
if (subtitleParserFactory != null && subtitleParserFactory.supportsFormat(sourceFormat)) {
|
if (parseSubtitlesDuringExtraction && subtitleParserFactory.supportsFormat(sourceFormat)) {
|
||||||
@Format.CueReplacementBehavior
|
|
||||||
int cueReplacementBehavior = subtitleParserFactory.getCueReplacementBehavior(sourceFormat);
|
|
||||||
return sourceFormat
|
return sourceFormat
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.setSampleMimeType(MimeTypes.APPLICATION_MEDIA3_CUES)
|
.setSampleMimeType(MimeTypes.APPLICATION_MEDIA3_CUES)
|
||||||
.setCueReplacementBehavior(cueReplacementBehavior)
|
.setCueReplacementBehavior(
|
||||||
|
subtitleParserFactory.getCueReplacementBehavior(sourceFormat))
|
||||||
.setCodecs(
|
.setCodecs(
|
||||||
sourceFormat.sampleMimeType
|
sourceFormat.sampleMimeType
|
||||||
+ (sourceFormat.codecs != null ? " " + sourceFormat.codecs : ""))
|
+ (sourceFormat.codecs != null ? " " + sourceFormat.codecs : ""))
|
||||||
@ -119,7 +121,7 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
|||||||
@Nullable String containerMimeType = representationFormat.containerMimeType;
|
@Nullable String containerMimeType = representationFormat.containerMimeType;
|
||||||
Extractor extractor;
|
Extractor extractor;
|
||||||
if (MimeTypes.isText(containerMimeType)) {
|
if (MimeTypes.isText(containerMimeType)) {
|
||||||
if (subtitleParserFactory == null) {
|
if (!parseSubtitlesDuringExtraction) {
|
||||||
// Subtitles will be parsed after decoding
|
// Subtitles will be parsed after decoding
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
@ -129,15 +131,10 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
|||||||
}
|
}
|
||||||
} else if (MimeTypes.isMatroska(containerMimeType)) {
|
} else if (MimeTypes.isMatroska(containerMimeType)) {
|
||||||
@MatroskaExtractor.Flags int flags = MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES;
|
@MatroskaExtractor.Flags int flags = MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES;
|
||||||
if (subtitleParserFactory == null) {
|
if (!parseSubtitlesDuringExtraction) {
|
||||||
flags |= MatroskaExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
flags |= MatroskaExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
}
|
}
|
||||||
extractor =
|
extractor = new MatroskaExtractor(subtitleParserFactory, flags);
|
||||||
new MatroskaExtractor(
|
|
||||||
subtitleParserFactory != null
|
|
||||||
? subtitleParserFactory
|
|
||||||
: SubtitleParser.Factory.UNSUPPORTED,
|
|
||||||
flags);
|
|
||||||
} else if (Objects.equals(containerMimeType, MimeTypes.IMAGE_JPEG)) {
|
} else if (Objects.equals(containerMimeType, MimeTypes.IMAGE_JPEG)) {
|
||||||
extractor = new JpegExtractor(JpegExtractor.FLAG_READ_IMAGE);
|
extractor = new JpegExtractor(JpegExtractor.FLAG_READ_IMAGE);
|
||||||
} else if (Objects.equals(containerMimeType, MimeTypes.IMAGE_PNG)) {
|
} else if (Objects.equals(containerMimeType, MimeTypes.IMAGE_PNG)) {
|
||||||
@ -147,21 +144,19 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
|||||||
if (enableEventMessageTrack) {
|
if (enableEventMessageTrack) {
|
||||||
flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK;
|
flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK;
|
||||||
}
|
}
|
||||||
if (subtitleParserFactory == null) {
|
if (!parseSubtitlesDuringExtraction) {
|
||||||
flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
}
|
}
|
||||||
extractor =
|
extractor =
|
||||||
new FragmentedMp4Extractor(
|
new FragmentedMp4Extractor(
|
||||||
subtitleParserFactory != null
|
subtitleParserFactory,
|
||||||
? subtitleParserFactory
|
|
||||||
: SubtitleParser.Factory.UNSUPPORTED,
|
|
||||||
flags,
|
flags,
|
||||||
/* timestampAdjuster= */ null,
|
/* timestampAdjuster= */ null,
|
||||||
/* sideloadedTrack= */ null,
|
/* sideloadedTrack= */ null,
|
||||||
closedCaptionFormats,
|
closedCaptionFormats,
|
||||||
playerEmsgTrackOutput);
|
playerEmsgTrackOutput);
|
||||||
}
|
}
|
||||||
if (subtitleParserFactory != null
|
if (parseSubtitlesDuringExtraction
|
||||||
&& !MimeTypes.isText(containerMimeType)
|
&& !MimeTypes.isText(containerMimeType)
|
||||||
&& !(extractor.getUnderlyingImplementation() instanceof FragmentedMp4Extractor)
|
&& !(extractor.getUnderlyingImplementation() instanceof FragmentedMp4Extractor)
|
||||||
&& !(extractor.getUnderlyingImplementation() instanceof MatroskaExtractor)) {
|
&& !(extractor.getUnderlyingImplementation() instanceof MatroskaExtractor)) {
|
||||||
|
@ -25,6 +25,8 @@ import androidx.media3.extractor.ChunkIndex;
|
|||||||
import androidx.media3.extractor.Extractor;
|
import androidx.media3.extractor.Extractor;
|
||||||
import androidx.media3.extractor.ExtractorInput;
|
import androidx.media3.extractor.ExtractorInput;
|
||||||
import androidx.media3.extractor.TrackOutput;
|
import androidx.media3.extractor.TrackOutput;
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -41,24 +43,34 @@ public interface ChunkExtractor {
|
|||||||
interface Factory {
|
interface Factory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new {@link ChunkExtractor} instance.
|
* Sets the {@link SubtitleParser.Factory} to use for parsing subtitles during extraction. The
|
||||||
|
* default factory value is implementation dependent.
|
||||||
*
|
*
|
||||||
* @param primaryTrackType The {@link C.TrackType type} of the primary track.
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
* @param representationFormat The format of the representation to extract from.
|
* extraction.
|
||||||
* @param enableEventMessageTrack Whether to enable the event message track.
|
* @return This factory, for convenience.
|
||||||
* @param closedCaptionFormats The {@link Format Formats} of the Closed-Caption tracks.
|
|
||||||
* @param playerEmsgTrackOutput The {@link TrackOutput} for extracted EMSG messages, or null.
|
|
||||||
* @param playerId The {@link PlayerId} of the player using this chunk extractor.
|
|
||||||
* @return A new {@link ChunkExtractor} instance, or null if not applicable.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@CanIgnoreReturnValue
|
||||||
ChunkExtractor createProgressiveMediaExtractor(
|
default Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
@C.TrackType int primaryTrackType,
|
return this;
|
||||||
Format representationFormat,
|
}
|
||||||
boolean enableEventMessageTrack,
|
|
||||||
List<Format> closedCaptionFormats,
|
/**
|
||||||
@Nullable TrackOutput playerEmsgTrackOutput,
|
* Sets whether subtitles should be parsed as part of extraction (before being added to the
|
||||||
PlayerId playerId);
|
* sample queue) or as part of rendering (when being taken from the sample queue). Defaults to
|
||||||
|
* {@code false} (i.e. subtitles will be parsed as part of rendering).
|
||||||
|
*
|
||||||
|
* <p>This method is experimental and will be renamed or removed in a future release.
|
||||||
|
*
|
||||||
|
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
||||||
|
* rendering.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
default Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the output {@link Format} of emitted {@linkplain C#TRACK_TYPE_TEXT text samples}
|
* Returns the output {@link Format} of emitted {@linkplain C#TRACK_TYPE_TEXT text samples}
|
||||||
@ -79,6 +91,26 @@ public interface ChunkExtractor {
|
|||||||
default Format getOutputTextFormat(Format sourceFormat) {
|
default Format getOutputTextFormat(Format sourceFormat) {
|
||||||
return sourceFormat;
|
return sourceFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link ChunkExtractor} instance.
|
||||||
|
*
|
||||||
|
* @param primaryTrackType The {@link C.TrackType type} of the primary track.
|
||||||
|
* @param representationFormat The format of the representation to extract from.
|
||||||
|
* @param enableEventMessageTrack Whether to enable the event message track.
|
||||||
|
* @param closedCaptionFormats The {@link Format Formats} of the Closed-Caption tracks.
|
||||||
|
* @param playerEmsgTrackOutput The {@link TrackOutput} for extracted EMSG messages, or null.
|
||||||
|
* @param playerId The {@link PlayerId} of the player using this chunk extractor.
|
||||||
|
* @return A new {@link ChunkExtractor} instance, or null if not applicable.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
ChunkExtractor createProgressiveMediaExtractor(
|
||||||
|
@C.TrackType int primaryTrackType,
|
||||||
|
Format representationFormat,
|
||||||
|
boolean enableEventMessageTrack,
|
||||||
|
List<Format> closedCaptionFormats,
|
||||||
|
@Nullable TrackOutput playerEmsgTrackOutput,
|
||||||
|
PlayerId playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Provides {@link TrackOutput} instances to be written to during extraction. */
|
/** Provides {@link TrackOutput} instances to be written to during extraction. */
|
||||||
|
@ -30,6 +30,8 @@ import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
|
|||||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||||
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
||||||
import androidx.media3.extractor.Extractor;
|
import androidx.media3.extractor.Extractor;
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** A {@link ChunkSource} for DASH streams. */
|
/** A {@link ChunkSource} for DASH streams. */
|
||||||
@ -39,6 +41,36 @@ public interface DashChunkSource extends ChunkSource {
|
|||||||
/** Factory for {@link DashChunkSource}s. */
|
/** Factory for {@link DashChunkSource}s. */
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link SubtitleParser.Factory} to use for parsing subtitles during extraction. The
|
||||||
|
* default factory value is implementation dependent.
|
||||||
|
*
|
||||||
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
|
* extraction.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
default Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether subtitles should be parsed as part of extraction (before being added to the
|
||||||
|
* sample queue) or as part of rendering (when being taken from the sample queue). Defaults to
|
||||||
|
* {@code false} (i.e. subtitles will be parsed as part of rendering).
|
||||||
|
*
|
||||||
|
* <p>This method is experimental and will be renamed or removed in a future release.
|
||||||
|
*
|
||||||
|
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
||||||
|
* rendering.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
default Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param manifestLoaderErrorThrower Throws errors affecting loading of manifests.
|
* @param manifestLoaderErrorThrower Throws errors affecting loading of manifests.
|
||||||
* @param manifest The initial manifest.
|
* @param manifest The initial manifest.
|
||||||
|
@ -77,8 +77,6 @@ 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.DefaultSubtitleParserFactory;
|
|
||||||
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;
|
||||||
@ -114,7 +112,6 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
private DrmSessionManagerProvider drmSessionManagerProvider;
|
private DrmSessionManagerProvider drmSessionManagerProvider;
|
||||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
@Nullable private SubtitleParser.Factory subtitleParserFactory;
|
|
||||||
private long fallbackTargetLiveOffsetMs;
|
private long fallbackTargetLiveOffsetMs;
|
||||||
private long minLiveStartPositionUs;
|
private long minLiveStartPositionUs;
|
||||||
@Nullable private ParsingLoadable.Parser<? extends DashManifest> manifestParser;
|
@Nullable private ParsingLoadable.Parser<? extends DashManifest> manifestParser;
|
||||||
@ -199,33 +196,11 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>This method may only be used with {@link DefaultDashChunkSource.Factory}.
|
|
||||||
*
|
|
||||||
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
|
||||||
* rendering.
|
|
||||||
* @return This factory, for convenience.
|
|
||||||
*/
|
|
||||||
// TODO: b/289916598 - Flip the default of this to true.
|
|
||||||
@Override
|
@Override
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public Factory experimentalParseSubtitlesDuringExtraction(
|
public Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
boolean parseSubtitlesDuringExtraction) {
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
if (parseSubtitlesDuringExtraction) {
|
chunkSourceFactory.experimentalParseSubtitlesDuringExtraction(parseSubtitlesDuringExtraction);
|
||||||
if (subtitleParserFactory == null) {
|
|
||||||
this.subtitleParserFactory = new DefaultSubtitleParserFactory();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.subtitleParserFactory = null;
|
|
||||||
}
|
|
||||||
if (chunkSourceFactory instanceof DefaultDashChunkSource.Factory) {
|
|
||||||
((DefaultDashChunkSource.Factory) chunkSourceFactory)
|
|
||||||
.setSubtitleParserFactory(subtitleParserFactory);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
|||||||
import androidx.media3.extractor.ChunkIndex;
|
import androidx.media3.extractor.ChunkIndex;
|
||||||
import androidx.media3.extractor.text.SubtitleParser;
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -113,18 +114,19 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
this.maxSegmentsPerLoad = maxSegmentsPerLoad;
|
this.maxSegmentsPerLoad = maxSegmentsPerLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@CanIgnoreReturnValue
|
||||||
* Sets the {@link SubtitleParser.Factory} to be used for parsing subtitles during extraction,
|
@Override
|
||||||
* or null to parse subtitles during decoding.
|
public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
*
|
chunkExtractorFactory.setSubtitleParserFactory(subtitleParserFactory);
|
||||||
* <p>This may only be used with {@link BundledChunkExtractor.Factory}.
|
return this;
|
||||||
*/
|
|
||||||
/* package */ Factory setSubtitleParserFactory(
|
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
|
||||||
if (chunkExtractorFactory instanceof BundledChunkExtractor.Factory) {
|
|
||||||
((BundledChunkExtractor.Factory) chunkExtractorFactory)
|
|
||||||
.experimentalSetSubtitleParserFactory(subtitleParserFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
@Override
|
||||||
|
public Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
chunkExtractorFactory.experimentalParseSubtitlesDuringExtraction(
|
||||||
|
parseSubtitlesDuringExtraction);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ package androidx.media3.exoplayer.hls;
|
|||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.util.TimestampAdjuster;
|
import androidx.media3.common.util.TimestampAdjuster;
|
||||||
@ -47,7 +46,8 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract
|
|||||||
@VisibleForTesting /* package */ final Extractor extractor;
|
@VisibleForTesting /* package */ final Extractor extractor;
|
||||||
private final Format multivariantPlaylistFormat;
|
private final Format multivariantPlaylistFormat;
|
||||||
private final TimestampAdjuster timestampAdjuster;
|
private final TimestampAdjuster timestampAdjuster;
|
||||||
@Nullable private final SubtitleParser.Factory subtitleParserFactory;
|
private final SubtitleParser.Factory subtitleParserFactory;
|
||||||
|
private final boolean parseSubtitlesDuringExtraction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -62,7 +62,8 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract
|
|||||||
extractor,
|
extractor,
|
||||||
multivariantPlaylistFormat,
|
multivariantPlaylistFormat,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
/* subtitleParserFactory= */ null);
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
|
/* parseSubtitlesDuringExtraction= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,16 +78,18 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract
|
|||||||
* multivariantPlaylistFormat.
|
* multivariantPlaylistFormat.
|
||||||
*/
|
*/
|
||||||
// TODO(b/289983417): Once the subtitle-parsing-during-extraction is the only available flow, make
|
// TODO(b/289983417): Once the subtitle-parsing-during-extraction is the only available flow, make
|
||||||
// this constructor public and remove @Nullable from subtitleParserFactory
|
// this constructor public and remove parseSubtitlesDuringExtraction parameter
|
||||||
/* package */ BundledHlsMediaChunkExtractor(
|
/* package */ BundledHlsMediaChunkExtractor(
|
||||||
Extractor extractor,
|
Extractor extractor,
|
||||||
Format multivariantPlaylistFormat,
|
Format multivariantPlaylistFormat,
|
||||||
TimestampAdjuster timestampAdjuster,
|
TimestampAdjuster timestampAdjuster,
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
SubtitleParser.Factory subtitleParserFactory,
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
this.extractor = extractor;
|
this.extractor = extractor;
|
||||||
this.multivariantPlaylistFormat = multivariantPlaylistFormat;
|
this.multivariantPlaylistFormat = multivariantPlaylistFormat;
|
||||||
this.timestampAdjuster = timestampAdjuster;
|
this.timestampAdjuster = timestampAdjuster;
|
||||||
this.subtitleParserFactory = subtitleParserFactory;
|
this.subtitleParserFactory = subtitleParserFactory;
|
||||||
|
this.parseSubtitlesDuringExtraction = parseSubtitlesDuringExtraction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -124,18 +127,11 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract
|
|||||||
Extractor newExtractorInstance;
|
Extractor newExtractorInstance;
|
||||||
// LINT.IfChange(extractor_instantiation)
|
// LINT.IfChange(extractor_instantiation)
|
||||||
if (extractor instanceof WebvttExtractor) {
|
if (extractor instanceof WebvttExtractor) {
|
||||||
SubtitleParser.Factory webvttSubtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
|
||||||
boolean parseSubtitlesDuringExtraction = false;
|
|
||||||
if (subtitleParserFactory != null
|
|
||||||
&& subtitleParserFactory.supportsFormat(multivariantPlaylistFormat)) {
|
|
||||||
webvttSubtitleParserFactory = subtitleParserFactory;
|
|
||||||
parseSubtitlesDuringExtraction = true;
|
|
||||||
}
|
|
||||||
newExtractorInstance =
|
newExtractorInstance =
|
||||||
new WebvttExtractor(
|
new WebvttExtractor(
|
||||||
multivariantPlaylistFormat.language,
|
multivariantPlaylistFormat.language,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
webvttSubtitleParserFactory,
|
subtitleParserFactory,
|
||||||
parseSubtitlesDuringExtraction);
|
parseSubtitlesDuringExtraction);
|
||||||
} else if (extractor instanceof AdtsExtractor) {
|
} else if (extractor instanceof AdtsExtractor) {
|
||||||
newExtractorInstance = new AdtsExtractor();
|
newExtractorInstance = new AdtsExtractor();
|
||||||
@ -150,7 +146,11 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract
|
|||||||
"Unexpected extractor type for recreation: " + extractor.getClass().getSimpleName());
|
"Unexpected extractor type for recreation: " + extractor.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
return new BundledHlsMediaChunkExtractor(
|
return new BundledHlsMediaChunkExtractor(
|
||||||
newExtractorInstance, multivariantPlaylistFormat, timestampAdjuster, subtitleParserFactory);
|
newExtractorInstance,
|
||||||
|
multivariantPlaylistFormat,
|
||||||
|
timestampAdjuster,
|
||||||
|
subtitleParserFactory,
|
||||||
|
parseSubtitlesDuringExtraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,6 +33,7 @@ import androidx.media3.extractor.Extractor;
|
|||||||
import androidx.media3.extractor.ExtractorInput;
|
import androidx.media3.extractor.ExtractorInput;
|
||||||
import androidx.media3.extractor.mp3.Mp3Extractor;
|
import androidx.media3.extractor.mp3.Mp3Extractor;
|
||||||
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
||||||
|
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||||
import androidx.media3.extractor.text.SubtitleParser;
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
import androidx.media3.extractor.ts.Ac3Extractor;
|
import androidx.media3.extractor.ts.Ac3Extractor;
|
||||||
import androidx.media3.extractor.ts.Ac4Extractor;
|
import androidx.media3.extractor.ts.Ac4Extractor;
|
||||||
@ -41,6 +42,7 @@ import androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory;
|
|||||||
import androidx.media3.extractor.ts.TsExtractor;
|
import androidx.media3.extractor.ts.TsExtractor;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -67,8 +69,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
|
|
||||||
private final @DefaultTsPayloadReaderFactory.Flags int payloadReaderFactoryFlags;
|
private final @DefaultTsPayloadReaderFactory.Flags int payloadReaderFactoryFlags;
|
||||||
|
|
||||||
/** Non-null if subtitles should be parsed during extraction, null otherwise. */
|
private SubtitleParser.Factory subtitleParserFactory;
|
||||||
@Nullable private SubtitleParser.Factory subtitleParserFactory;
|
private boolean parseSubtitlesDuringExtraction;
|
||||||
|
|
||||||
private final boolean exposeCea608WhenMissingDeclarations;
|
private final boolean exposeCea608WhenMissingDeclarations;
|
||||||
|
|
||||||
@ -96,6 +98,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
int payloadReaderFactoryFlags, boolean exposeCea608WhenMissingDeclarations) {
|
int payloadReaderFactoryFlags, boolean exposeCea608WhenMissingDeclarations) {
|
||||||
this.payloadReaderFactoryFlags = payloadReaderFactoryFlags;
|
this.payloadReaderFactoryFlags = payloadReaderFactoryFlags;
|
||||||
this.exposeCea608WhenMissingDeclarations = exposeCea608WhenMissingDeclarations;
|
this.exposeCea608WhenMissingDeclarations = exposeCea608WhenMissingDeclarations;
|
||||||
|
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -135,7 +138,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
createExtractorByFileType(fileType, format, muxedCaptionFormats, timestampAdjuster));
|
createExtractorByFileType(fileType, format, muxedCaptionFormats, timestampAdjuster));
|
||||||
if (sniffQuietly(extractor, sniffingExtractorInput)) {
|
if (sniffQuietly(extractor, sniffingExtractorInput)) {
|
||||||
return new BundledHlsMediaChunkExtractor(
|
return new BundledHlsMediaChunkExtractor(
|
||||||
extractor, format, timestampAdjuster, subtitleParserFactory);
|
extractor,
|
||||||
|
format,
|
||||||
|
timestampAdjuster,
|
||||||
|
subtitleParserFactory,
|
||||||
|
parseSubtitlesDuringExtraction);
|
||||||
}
|
}
|
||||||
if (fallBackExtractor == null
|
if (fallBackExtractor == null
|
||||||
&& (fileType == formatInferredFileType
|
&& (fileType == formatInferredFileType
|
||||||
@ -149,26 +156,29 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new BundledHlsMediaChunkExtractor(
|
return new BundledHlsMediaChunkExtractor(
|
||||||
checkNotNull(fallBackExtractor), format, timestampAdjuster, subtitleParserFactory);
|
checkNotNull(fallBackExtractor),
|
||||||
|
format,
|
||||||
|
timestampAdjuster,
|
||||||
|
subtitleParserFactory,
|
||||||
|
parseSubtitlesDuringExtraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@CanIgnoreReturnValue
|
||||||
* Sets the {@link SubtitleParser.Factory} to use for parsing subtitles during extraction, or null
|
@Override
|
||||||
* to parse subtitles during decoding. The default is null (subtitles parsed after decoding).
|
public DefaultHlsExtractorFactory setSubtitleParserFactory(
|
||||||
*
|
SubtitleParser.Factory subtitleParserFactory) {
|
||||||
* <p>This method is experimental. Its default value may change, or it may be renamed or removed
|
|
||||||
* in a future release.
|
|
||||||
*
|
|
||||||
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
|
||||||
* extraction.
|
|
||||||
* @return This factory, for convenience.
|
|
||||||
*/
|
|
||||||
public DefaultHlsExtractorFactory experimentalSetSubtitleParserFactory(
|
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
|
||||||
this.subtitleParserFactory = subtitleParserFactory;
|
this.subtitleParserFactory = subtitleParserFactory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
@Override
|
||||||
|
public DefaultHlsExtractorFactory experimentalParseSubtitlesDuringExtraction(
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
this.parseSubtitlesDuringExtraction = parseSubtitlesDuringExtraction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@ -176,18 +186,15 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
* MimeTypes#APPLICATION_MEDIA3_CUES} if it is supported by {@link SubtitleParser.Factory}.
|
* MimeTypes#APPLICATION_MEDIA3_CUES} if it is supported by {@link SubtitleParser.Factory}.
|
||||||
*
|
*
|
||||||
* <p>To modify the support behavior, you can {@linkplain
|
* <p>To modify the support behavior, you can {@linkplain
|
||||||
* #experimentalSetSubtitleParserFactory(SubtitleParser.Factory) set your own subtitle parser
|
* #setSubtitleParserFactory(SubtitleParser.Factory) set your own subtitle parser factory}.
|
||||||
* factory}.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Format getOutputTextFormat(Format sourceFormat) {
|
public Format getOutputTextFormat(Format sourceFormat) {
|
||||||
if (subtitleParserFactory != null && subtitleParserFactory.supportsFormat(sourceFormat)) {
|
if (parseSubtitlesDuringExtraction && subtitleParserFactory.supportsFormat(sourceFormat)) {
|
||||||
@Format.CueReplacementBehavior
|
|
||||||
int cueReplacementBehavior = subtitleParserFactory.getCueReplacementBehavior(sourceFormat);
|
|
||||||
return sourceFormat
|
return sourceFormat
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.setSampleMimeType(MimeTypes.APPLICATION_MEDIA3_CUES)
|
.setSampleMimeType(MimeTypes.APPLICATION_MEDIA3_CUES)
|
||||||
.setCueReplacementBehavior(cueReplacementBehavior)
|
.setCueReplacementBehavior(subtitleParserFactory.getCueReplacementBehavior(sourceFormat))
|
||||||
.setCodecs(
|
.setCodecs(
|
||||||
sourceFormat.sampleMimeType
|
sourceFormat.sampleMimeType
|
||||||
+ (sourceFormat.codecs != null ? " " + sourceFormat.codecs : ""))
|
+ (sourceFormat.codecs != null ? " " + sourceFormat.codecs : ""))
|
||||||
@ -216,16 +223,10 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
// LINT.IfChange(extractor_instantiation)
|
// LINT.IfChange(extractor_instantiation)
|
||||||
switch (fileType) {
|
switch (fileType) {
|
||||||
case FileTypes.WEBVTT:
|
case FileTypes.WEBVTT:
|
||||||
SubtitleParser.Factory webvttSubtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
|
||||||
boolean parseSubtitlesDuringExtraction = false;
|
|
||||||
if (subtitleParserFactory != null && subtitleParserFactory.supportsFormat(format)) {
|
|
||||||
webvttSubtitleParserFactory = subtitleParserFactory;
|
|
||||||
parseSubtitlesDuringExtraction = true;
|
|
||||||
}
|
|
||||||
return new WebvttExtractor(
|
return new WebvttExtractor(
|
||||||
format.language,
|
format.language,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
webvttSubtitleParserFactory,
|
subtitleParserFactory,
|
||||||
parseSubtitlesDuringExtraction);
|
parseSubtitlesDuringExtraction);
|
||||||
case FileTypes.ADTS:
|
case FileTypes.ADTS:
|
||||||
return new AdtsExtractor();
|
return new AdtsExtractor();
|
||||||
@ -237,7 +238,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
return new Mp3Extractor(/* flags= */ 0, /* forcedFirstSampleTimestampUs= */ 0);
|
return new Mp3Extractor(/* flags= */ 0, /* forcedFirstSampleTimestampUs= */ 0);
|
||||||
case FileTypes.MP4:
|
case FileTypes.MP4:
|
||||||
return createFragmentedMp4Extractor(
|
return createFragmentedMp4Extractor(
|
||||||
subtitleParserFactory, timestampAdjuster, format, muxedCaptionFormats);
|
subtitleParserFactory,
|
||||||
|
parseSubtitlesDuringExtraction,
|
||||||
|
timestampAdjuster,
|
||||||
|
format,
|
||||||
|
muxedCaptionFormats);
|
||||||
case FileTypes.TS:
|
case FileTypes.TS:
|
||||||
return createTsExtractor(
|
return createTsExtractor(
|
||||||
payloadReaderFactoryFlags,
|
payloadReaderFactoryFlags,
|
||||||
@ -245,7 +250,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
format,
|
format,
|
||||||
muxedCaptionFormats,
|
muxedCaptionFormats,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
subtitleParserFactory);
|
subtitleParserFactory,
|
||||||
|
parseSubtitlesDuringExtraction);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -257,7 +263,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
Format format,
|
Format format,
|
||||||
@Nullable List<Format> muxedCaptionFormats,
|
@Nullable List<Format> muxedCaptionFormats,
|
||||||
TimestampAdjuster timestampAdjuster,
|
TimestampAdjuster timestampAdjuster,
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
SubtitleParser.Factory subtitleParserFactory,
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
@DefaultTsPayloadReaderFactory.Flags
|
@DefaultTsPayloadReaderFactory.Flags
|
||||||
int payloadReaderFactoryFlags =
|
int payloadReaderFactoryFlags =
|
||||||
DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM
|
DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM
|
||||||
@ -287,7 +294,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@TsExtractor.Flags int extractorFlags = 0;
|
@TsExtractor.Flags int extractorFlags = 0;
|
||||||
if (subtitleParserFactory == null) {
|
if (!parseSubtitlesDuringExtraction) {
|
||||||
subtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
subtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
||||||
extractorFlags |= TsExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
extractorFlags |= TsExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
}
|
}
|
||||||
@ -301,7 +308,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static FragmentedMp4Extractor createFragmentedMp4Extractor(
|
private static FragmentedMp4Extractor createFragmentedMp4Extractor(
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory,
|
SubtitleParser.Factory subtitleParserFactory,
|
||||||
|
boolean parseSubtitlesDuringExtraction,
|
||||||
TimestampAdjuster timestampAdjuster,
|
TimestampAdjuster timestampAdjuster,
|
||||||
Format format,
|
Format format,
|
||||||
@Nullable List<Format> muxedCaptionFormats) {
|
@Nullable List<Format> muxedCaptionFormats) {
|
||||||
@ -309,7 +317,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
// creating a separate EMSG track for every audio track in a video stream.
|
// creating a separate EMSG track for every audio track in a video stream.
|
||||||
@FragmentedMp4Extractor.Flags
|
@FragmentedMp4Extractor.Flags
|
||||||
int flags = isFmp4Variant(format) ? FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK : 0;
|
int flags = isFmp4Variant(format) ? FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK : 0;
|
||||||
if (subtitleParserFactory == null) {
|
if (!parseSubtitlesDuringExtraction) {
|
||||||
subtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
subtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
||||||
flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ import androidx.media3.exoplayer.analytics.PlayerId;
|
|||||||
import androidx.media3.extractor.Extractor;
|
import androidx.media3.extractor.Extractor;
|
||||||
import androidx.media3.extractor.ExtractorInput;
|
import androidx.media3.extractor.ExtractorInput;
|
||||||
import androidx.media3.extractor.PositionHolder;
|
import androidx.media3.extractor.PositionHolder;
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -63,6 +65,37 @@ public interface HlsExtractorFactory {
|
|||||||
PlayerId playerId)
|
PlayerId playerId)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link SubtitleParser.Factory} to use for parsing subtitles during extraction. The
|
||||||
|
* default factory value is implementation dependent.
|
||||||
|
*
|
||||||
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
|
* extraction.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
default HlsExtractorFactory setSubtitleParserFactory(
|
||||||
|
SubtitleParser.Factory subtitleParserFactory) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether subtitles should be parsed as part of extraction (before being added to the sample
|
||||||
|
* queue) or as part of rendering (when being taken from the sample queue). Defaults to {@code
|
||||||
|
* false} (i.e. subtitles will be parsed as part of rendering).
|
||||||
|
*
|
||||||
|
* <p>This method is experimental and will be renamed or removed in a future release.
|
||||||
|
*
|
||||||
|
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
||||||
|
* rendering.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
default HlsExtractorFactory experimentalParseSubtitlesDuringExtraction(
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the output {@link Format} of emitted {@linkplain C#TRACK_TYPE_TEXT text samples} which
|
* Returns the output {@link Format} of emitted {@linkplain C#TRACK_TYPE_TEXT text samples} which
|
||||||
* were originally in {@code sourceFormat}.
|
* were originally in {@code sourceFormat}.
|
||||||
|
@ -58,8 +58,6 @@ 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.DefaultSubtitleParserFactory;
|
|
||||||
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;
|
||||||
@ -113,7 +111,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
@Nullable private CmcdConfiguration.Factory cmcdConfigurationFactory;
|
@Nullable private CmcdConfiguration.Factory cmcdConfigurationFactory;
|
||||||
private DrmSessionManagerProvider drmSessionManagerProvider;
|
private DrmSessionManagerProvider drmSessionManagerProvider;
|
||||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
@Nullable private SubtitleParser.Factory subtitleParserFactory;
|
|
||||||
private boolean allowChunklessPreparation;
|
private boolean allowChunklessPreparation;
|
||||||
private @MetadataType int metadataType;
|
private @MetadataType int metadataType;
|
||||||
private boolean useSessionKeys;
|
private boolean useSessionKeys;
|
||||||
@ -199,32 +197,11 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>This method may only be used with {@link DefaultHlsExtractorFactory}.
|
|
||||||
*
|
|
||||||
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
|
||||||
* rendering.
|
|
||||||
* @return This factory, for convenience.
|
|
||||||
*/
|
|
||||||
// TODO: b/289916598 - Flip the default of this to true.
|
|
||||||
@Override
|
@Override
|
||||||
|
@CanIgnoreReturnValue
|
||||||
public Factory experimentalParseSubtitlesDuringExtraction(
|
public Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
boolean parseSubtitlesDuringExtraction) {
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
if (parseSubtitlesDuringExtraction) {
|
extractorFactory.experimentalParseSubtitlesDuringExtraction(parseSubtitlesDuringExtraction);
|
||||||
if (subtitleParserFactory == null) {
|
|
||||||
this.subtitleParserFactory = new DefaultSubtitleParserFactory();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.subtitleParserFactory = null;
|
|
||||||
}
|
|
||||||
if (extractorFactory instanceof DefaultHlsExtractorFactory) {
|
|
||||||
((DefaultHlsExtractorFactory) extractorFactory)
|
|
||||||
.experimentalSetSubtitleParserFactory(subtitleParserFactory);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +53,10 @@ import androidx.media3.extractor.Extractor;
|
|||||||
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
||||||
import androidx.media3.extractor.mp4.Track;
|
import androidx.media3.extractor.mp4.Track;
|
||||||
import androidx.media3.extractor.mp4.TrackEncryptionBox;
|
import androidx.media3.extractor.mp4.TrackEncryptionBox;
|
||||||
|
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||||
import androidx.media3.extractor.text.SubtitleParser;
|
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 java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -65,24 +67,29 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
public static final class Factory implements SsChunkSource.Factory {
|
public static final class Factory implements SsChunkSource.Factory {
|
||||||
|
|
||||||
private final DataSource.Factory dataSourceFactory;
|
private final DataSource.Factory dataSourceFactory;
|
||||||
@Nullable private SubtitleParser.Factory subtitleParserFactory;
|
private SubtitleParser.Factory subtitleParserFactory;
|
||||||
|
private boolean parseSubtitlesDuringExtraction;
|
||||||
|
|
||||||
public Factory(DataSource.Factory dataSourceFactory) {
|
public Factory(DataSource.Factory dataSourceFactory) {
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
|
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@CanIgnoreReturnValue
|
||||||
* Sets the {@link SubtitleParser.Factory} to be used for parsing subtitles during extraction,
|
@Override
|
||||||
* or {@code null} to parse subtitles during decoding.
|
public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
*
|
|
||||||
* <p>This may only be used with {@link BundledChunkExtractor.Factory}.
|
|
||||||
*/
|
|
||||||
/* package */ Factory setSubtitleParserFactory(
|
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
|
||||||
this.subtitleParserFactory = subtitleParserFactory;
|
this.subtitleParserFactory = subtitleParserFactory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
@Override
|
||||||
|
public Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
this.parseSubtitlesDuringExtraction = parseSubtitlesDuringExtraction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@ -91,13 +98,12 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Format getOutputTextFormat(Format sourceFormat) {
|
public Format getOutputTextFormat(Format sourceFormat) {
|
||||||
if (subtitleParserFactory != null && subtitleParserFactory.supportsFormat(sourceFormat)) {
|
if (parseSubtitlesDuringExtraction && subtitleParserFactory.supportsFormat(sourceFormat)) {
|
||||||
@Format.CueReplacementBehavior
|
|
||||||
int cueReplacementBehavior = subtitleParserFactory.getCueReplacementBehavior(sourceFormat);
|
|
||||||
return sourceFormat
|
return sourceFormat
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.setSampleMimeType(MimeTypes.APPLICATION_MEDIA3_CUES)
|
.setSampleMimeType(MimeTypes.APPLICATION_MEDIA3_CUES)
|
||||||
.setCueReplacementBehavior(cueReplacementBehavior)
|
.setCueReplacementBehavior(
|
||||||
|
subtitleParserFactory.getCueReplacementBehavior(sourceFormat))
|
||||||
.setCodecs(
|
.setCodecs(
|
||||||
sourceFormat.sampleMimeType
|
sourceFormat.sampleMimeType
|
||||||
+ (sourceFormat.codecs != null ? " " + sourceFormat.codecs : ""))
|
+ (sourceFormat.codecs != null ? " " + sourceFormat.codecs : ""))
|
||||||
@ -127,7 +133,8 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
trackSelection,
|
trackSelection,
|
||||||
dataSource,
|
dataSource,
|
||||||
cmcdConfiguration,
|
cmcdConfiguration,
|
||||||
subtitleParserFactory);
|
subtitleParserFactory,
|
||||||
|
parseSubtitlesDuringExtraction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +165,8 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
* @param cmcdConfiguration The {@link CmcdConfiguration} for this chunk source.
|
* @param cmcdConfiguration The {@link CmcdConfiguration} for this chunk source.
|
||||||
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
* extraction.
|
* extraction.
|
||||||
|
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
||||||
|
* rendering.
|
||||||
*/
|
*/
|
||||||
public DefaultSsChunkSource(
|
public DefaultSsChunkSource(
|
||||||
LoaderErrorThrower manifestLoaderErrorThrower,
|
LoaderErrorThrower manifestLoaderErrorThrower,
|
||||||
@ -166,7 +175,8 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
ExoTrackSelection trackSelection,
|
ExoTrackSelection trackSelection,
|
||||||
DataSource dataSource,
|
DataSource dataSource,
|
||||||
@Nullable CmcdConfiguration cmcdConfiguration,
|
@Nullable CmcdConfiguration cmcdConfiguration,
|
||||||
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
SubtitleParser.Factory subtitleParserFactory,
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.streamElementIndex = streamElementIndex;
|
this.streamElementIndex = streamElementIndex;
|
||||||
@ -203,14 +213,13 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
int flags =
|
int flags =
|
||||||
FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
|
FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
|
||||||
| FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX;
|
| FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX;
|
||||||
|
if (!parseSubtitlesDuringExtraction) {
|
||||||
|
flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
|
}
|
||||||
Extractor extractor =
|
Extractor extractor =
|
||||||
new FragmentedMp4Extractor(
|
new FragmentedMp4Extractor(
|
||||||
subtitleParserFactory == null
|
subtitleParserFactory,
|
||||||
? SubtitleParser.Factory.UNSUPPORTED
|
flags,
|
||||||
: subtitleParserFactory,
|
|
||||||
subtitleParserFactory == null
|
|
||||||
? flags | FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA
|
|
||||||
: flags,
|
|
||||||
/* timestampAdjuster= */ null,
|
/* timestampAdjuster= */ null,
|
||||||
track,
|
track,
|
||||||
/* closedCaptionFormats= */ ImmutableList.of(),
|
/* closedCaptionFormats= */ ImmutableList.of(),
|
||||||
|
@ -27,6 +27,8 @@ import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
|
|||||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||||
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
||||||
import androidx.media3.extractor.Extractor;
|
import androidx.media3.extractor.Extractor;
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
|
|
||||||
/** A {@link ChunkSource} for SmoothStreaming. */
|
/** A {@link ChunkSource} for SmoothStreaming. */
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
@ -55,6 +57,36 @@ public interface SsChunkSource extends ChunkSource {
|
|||||||
@Nullable TransferListener transferListener,
|
@Nullable TransferListener transferListener,
|
||||||
@Nullable CmcdConfiguration cmcdConfiguration);
|
@Nullable CmcdConfiguration cmcdConfiguration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link SubtitleParser.Factory} to use for parsing subtitles during extraction. The
|
||||||
|
* default factory value is implementation dependent.
|
||||||
|
*
|
||||||
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
|
* extraction.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
default Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether subtitles should be parsed as part of extraction (before being added to the
|
||||||
|
* sample queue) or as part of rendering (when being taken from the sample queue). Defaults to
|
||||||
|
* {@code false} (i.e. subtitles will be parsed as part of rendering).
|
||||||
|
*
|
||||||
|
* <p>This method is experimental and will be renamed or removed in a future release.
|
||||||
|
*
|
||||||
|
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
||||||
|
* rendering.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
default Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the output {@link Format} of emitted {@linkplain C#TRACK_TYPE_TEXT text samples}
|
* Returns the output {@link Format} of emitted {@linkplain C#TRACK_TYPE_TEXT text samples}
|
||||||
* which were originally in {@code sourceFormat}.
|
* which were originally in {@code sourceFormat}.
|
||||||
|
@ -65,8 +65,6 @@ 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.DefaultSubtitleParserFactory;
|
|
||||||
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;
|
||||||
@ -93,7 +91,6 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
@Nullable private CmcdConfiguration.Factory cmcdConfigurationFactory;
|
@Nullable private CmcdConfiguration.Factory cmcdConfigurationFactory;
|
||||||
private DrmSessionManagerProvider drmSessionManagerProvider;
|
private DrmSessionManagerProvider drmSessionManagerProvider;
|
||||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
@Nullable private SubtitleParser.Factory subtitleParserFactory;
|
|
||||||
private long livePresentationDelayMs;
|
private long livePresentationDelayMs;
|
||||||
@Nullable private ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
@Nullable private ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
||||||
|
|
||||||
@ -155,32 +152,11 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>This method may only be used with {@link DefaultSsChunkSource.Factory}.
|
|
||||||
*
|
|
||||||
* @param parseSubtitlesDuringExtraction Whether to parse subtitles during extraction or
|
|
||||||
* rendering.
|
|
||||||
* @return This factory, for convenience.
|
|
||||||
*/
|
|
||||||
// TODO: b/289916598 - Flip the default of this to true.
|
|
||||||
@Override
|
@Override
|
||||||
|
@CanIgnoreReturnValue
|
||||||
public Factory experimentalParseSubtitlesDuringExtraction(
|
public Factory experimentalParseSubtitlesDuringExtraction(
|
||||||
boolean parseSubtitlesDuringExtraction) {
|
boolean parseSubtitlesDuringExtraction) {
|
||||||
if (parseSubtitlesDuringExtraction) {
|
chunkSourceFactory.experimentalParseSubtitlesDuringExtraction(parseSubtitlesDuringExtraction);
|
||||||
if (subtitleParserFactory == null) {
|
|
||||||
this.subtitleParserFactory = new DefaultSubtitleParserFactory();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.subtitleParserFactory = null;
|
|
||||||
}
|
|
||||||
if (chunkSourceFactory instanceof DefaultSsChunkSource.Factory) {
|
|
||||||
((DefaultSsChunkSource.Factory) chunkSourceFactory)
|
|
||||||
.setSubtitleParserFactory(subtitleParserFactory);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import androidx.media3.exoplayer.trackselection.AdaptiveTrackSelection;
|
|||||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||||
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
||||||
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
import androidx.media3.test.utils.FakeDataSource;
|
import androidx.media3.test.utils.FakeDataSource;
|
||||||
import androidx.media3.test.utils.TestUtil;
|
import androidx.media3.test.utils.TestUtil;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@ -315,6 +316,7 @@ public class DefaultSsChunkSourceTest {
|
|||||||
adaptiveTrackSelection,
|
adaptiveTrackSelection,
|
||||||
new FakeDataSource(),
|
new FakeDataSource(),
|
||||||
cmcdConfiguration,
|
cmcdConfiguration,
|
||||||
/* subtitleParserFactory= */ null);
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
|
/* parseSubtitlesDuringExtraction= */ false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
package androidx.media3.exoplayer.smoothstreaming;
|
package androidx.media3.exoplayer.smoothstreaming;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.assertThrows;
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -33,6 +32,7 @@ import androidx.media3.exoplayer.source.MediaSource;
|
|||||||
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
|
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
|
||||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||||
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
import androidx.media3.exoplayer.upstream.LoaderErrorThrower;
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
import androidx.media3.test.utils.FakeDataSource;
|
import androidx.media3.test.utils.FakeDataSource;
|
||||||
import androidx.media3.test.utils.TestUtil;
|
import androidx.media3.test.utils.TestUtil;
|
||||||
import androidx.media3.test.utils.robolectric.RobolectricUtil;
|
import androidx.media3.test.utils.robolectric.RobolectricUtil;
|
||||||
@ -104,14 +104,12 @@ public class SsMediaSourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
setExperimentalParseSubtitlesDuringExtraction_withNonDefaultChunkSourceFactory_setThrows() {
|
setExperimentalParseSubtitlesDuringExtraction_withNonDefaultChunkSourceFactory_setSucceeds() {
|
||||||
SsMediaSource.Factory ssMediaSourceFactory =
|
SsMediaSource.Factory ssMediaSourceFactory =
|
||||||
new SsMediaSource.Factory(
|
new SsMediaSource.Factory(
|
||||||
/* chunkSourceFactory= */ this::createSampleSsChunkSource,
|
/* chunkSourceFactory= */ this::createSampleSsChunkSource,
|
||||||
/* manifestDataSourceFactory= */ () -> createSampleDataSource(SAMPLE_MANIFEST));
|
/* manifestDataSourceFactory= */ () -> createSampleDataSource(SAMPLE_MANIFEST));
|
||||||
assertThrows(
|
ssMediaSourceFactory.experimentalParseSubtitlesDuringExtraction(false);
|
||||||
IllegalStateException.class,
|
|
||||||
() -> ssMediaSourceFactory.experimentalParseSubtitlesDuringExtraction(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -219,6 +217,7 @@ public class SsMediaSourceTest {
|
|||||||
trackSelection,
|
trackSelection,
|
||||||
new FakeDataSource(),
|
new FakeDataSource(),
|
||||||
cmcdConfiguration,
|
cmcdConfiguration,
|
||||||
/* subtitleParserFactory= */ null);
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
|
/* parseSubtitlesDuringExtraction= */ false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user