mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
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
1 changed files with 84 additions and 14 deletions
|
|
@ -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.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE;
|
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_CAPTION_FORMATS;
|
||||||
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT;
|
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.ExtractorOutput;
|
||||||
import androidx.media3.extractor.SeekMap;
|
import androidx.media3.extractor.SeekMap;
|
||||||
import androidx.media3.extractor.TrackOutput;
|
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.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -56,22 +61,87 @@ public final class MediaParserChunkExtractor implements ChunkExtractor {
|
||||||
// Maximum TAG length is 23 characters.
|
// Maximum TAG length is 23 characters.
|
||||||
private static final String TAG = "MediaPrsrChunkExtractor";
|
private static final String TAG = "MediaPrsrChunkExtractor";
|
||||||
|
|
||||||
public static final ChunkExtractor.Factory FACTORY =
|
/** A {@link ChunkExtractor.Factory} for {@link MediaParserChunkExtractor} instances. */
|
||||||
(primaryTrackType,
|
public static class Factory implements ChunkExtractor.Factory {
|
||||||
format,
|
|
||||||
enableEventMessageTrack,
|
private SubtitleParser.Factory subtitleParserFactory;
|
||||||
closedCaptionFormats,
|
private boolean parseSubtitlesDuringExtraction;
|
||||||
playerEmsgTrackOutput,
|
|
||||||
playerId) -> {
|
public Factory() {
|
||||||
if (!MimeTypes.isText(format.containerMimeType)) {
|
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
||||||
// Container is either Matroska or Fragmented MP4.
|
}
|
||||||
return new MediaParserChunkExtractor(
|
|
||||||
primaryTrackType, format, closedCaptionFormats, playerId);
|
@CanIgnoreReturnValue
|
||||||
} else {
|
@Override
|
||||||
// This is a text track that does not require an extractor.
|
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;
|
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 OutputConsumerAdapterV30 outputConsumerAdapter;
|
||||||
private final InputReaderAdapterV30 inputReaderAdapter;
|
private final InputReaderAdapterV30 inputReaderAdapter;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue