Use SubtitleExtractor
from MediaParserChunkExtractor
This uses a 'bundled' extractor (`SubtitleExtractor`) because `MediaParser` doesn't support transcoding subtitles to `application/x-media3-cues`. This transcoding is required to support non-legacy subtitle handling where they are parsed during extraction, instead of during rendering. PiperOrigin-RevId: 665282298
This commit is contained in:
parent
266f16823f
commit
b04b270c2b
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer.source.chunk;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE;
|
||||
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EXPOSE_CAPTION_FORMATS;
|
||||
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT;
|
||||
@ -44,6 +45,10 @@ import androidx.media3.extractor.ExtractorInput;
|
||||
import androidx.media3.extractor.ExtractorOutput;
|
||||
import androidx.media3.extractor.SeekMap;
|
||||
import androidx.media3.extractor.TrackOutput;
|
||||
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||
import androidx.media3.extractor.text.SubtitleExtractor;
|
||||
import androidx.media3.extractor.text.SubtitleParser;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -56,22 +61,87 @@ public final class MediaParserChunkExtractor implements ChunkExtractor {
|
||||
// Maximum TAG length is 23 characters.
|
||||
private static final String TAG = "MediaPrsrChunkExtractor";
|
||||
|
||||
public static final ChunkExtractor.Factory FACTORY =
|
||||
(primaryTrackType,
|
||||
format,
|
||||
enableEventMessageTrack,
|
||||
closedCaptionFormats,
|
||||
playerEmsgTrackOutput,
|
||||
playerId) -> {
|
||||
if (!MimeTypes.isText(format.containerMimeType)) {
|
||||
// Container is either Matroska or Fragmented MP4.
|
||||
return new MediaParserChunkExtractor(
|
||||
primaryTrackType, format, closedCaptionFormats, playerId);
|
||||
} else {
|
||||
// This is a text track that does not require an extractor.
|
||||
/** A {@link ChunkExtractor.Factory} for {@link MediaParserChunkExtractor} instances. */
|
||||
public static class Factory implements ChunkExtractor.Factory {
|
||||
|
||||
private SubtitleParser.Factory subtitleParserFactory;
|
||||
private boolean parseSubtitlesDuringExtraction;
|
||||
|
||||
public Factory() {
|
||||
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
||||
}
|
||||
|
||||
@CanIgnoreReturnValue
|
||||
@Override
|
||||
public Factory setSubtitleParserFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||
this.subtitleParserFactory = checkNotNull(subtitleParserFactory);
|
||||
return this;
|
||||
}
|
||||
|
||||
@CanIgnoreReturnValue
|
||||
@Override
|
||||
public Factory experimentalParseSubtitlesDuringExtraction(
|
||||
boolean parseSubtitlesDuringExtraction) {
|
||||
this.parseSubtitlesDuringExtraction = parseSubtitlesDuringExtraction;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>This implementation performs transcoding of the original format to {@link
|
||||
* MimeTypes#APPLICATION_MEDIA3_CUES} if it is supported by {@link SubtitleParser.Factory}.
|
||||
*
|
||||
* <p>To modify the support behavior, you can {@linkplain
|
||||
* #setSubtitleParserFactory(SubtitleParser.Factory) set your own subtitle parser factory}.
|
||||
*/
|
||||
@Override
|
||||
public Format getOutputTextFormat(Format sourceFormat) {
|
||||
if (parseSubtitlesDuringExtraction && subtitleParserFactory.supportsFormat(sourceFormat)) {
|
||||
return sourceFormat
|
||||
.buildUpon()
|
||||
.setSampleMimeType(MimeTypes.APPLICATION_MEDIA3_CUES)
|
||||
.setCueReplacementBehavior(
|
||||
subtitleParserFactory.getCueReplacementBehavior(sourceFormat))
|
||||
.setCodecs(
|
||||
sourceFormat.sampleMimeType
|
||||
+ (sourceFormat.codecs != null ? " " + sourceFormat.codecs : ""))
|
||||
.setSubsampleOffsetUs(Format.OFFSET_SAMPLE_RELATIVE)
|
||||
.build();
|
||||
} else {
|
||||
return sourceFormat;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ChunkExtractor createProgressiveMediaExtractor(
|
||||
@C.TrackType int primaryTrackType,
|
||||
Format representationFormat,
|
||||
boolean enableEventMessageTrack,
|
||||
List<Format> closedCaptionFormats,
|
||||
@Nullable TrackOutput playerEmsgTrackOutput,
|
||||
PlayerId playerId) {
|
||||
if (!MimeTypes.isText(representationFormat.containerMimeType)) {
|
||||
// Container is either Matroska or Fragmented MP4.
|
||||
return new MediaParserChunkExtractor(
|
||||
primaryTrackType, representationFormat, closedCaptionFormats, playerId);
|
||||
} else {
|
||||
if (!parseSubtitlesDuringExtraction) {
|
||||
// Subtitles will be parsed after decoding
|
||||
return null;
|
||||
} else {
|
||||
return new BundledChunkExtractor(
|
||||
new SubtitleExtractor(
|
||||
subtitleParserFactory.create(representationFormat), representationFormat),
|
||||
primaryTrackType,
|
||||
representationFormat);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final ChunkExtractor.Factory FACTORY = new Factory();
|
||||
|
||||
private final OutputConsumerAdapterV30 outputConsumerAdapter;
|
||||
private final InputReaderAdapterV30 inputReaderAdapter;
|
||||
|
Loading…
x
Reference in New Issue
Block a user