diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java index 9cc511e097..af036854b3 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java @@ -441,6 +441,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { && !(extractor.getUnderlyingImplementation() instanceof FragmentedMp4Extractor) && !(extractor.getUnderlyingImplementation() instanceof Mp4Extractor) && !(extractor.getUnderlyingImplementation() instanceof TsExtractor) + && !(extractor.getUnderlyingImplementation() instanceof AviExtractor) ? new SubtitleTranscodingExtractor(extractor, subtitleParserFactory) : extractor; } @@ -550,7 +551,10 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { } break; case FileTypes.AVI: - extractors.add(new AviExtractor()); + extractors.add( + new AviExtractor( + (textTrackTranscodingEnabled ? 0 : AviExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA), + subtitleParserFactory)); break; case FileTypes.PNG: extractors.add(new PngExtractor()); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/avi/AviExtractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/avi/AviExtractor.java index d778f58284..1373b17a5e 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/avi/AviExtractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/avi/AviExtractor.java @@ -34,6 +34,8 @@ import androidx.media3.extractor.ExtractorOutput; import androidx.media3.extractor.PositionHolder; import androidx.media3.extractor.SeekMap; import androidx.media3.extractor.TrackOutput; +import androidx.media3.extractor.text.SubtitleParser; +import androidx.media3.extractor.text.SubtitleTranscodingExtractorOutput; import java.io.IOException; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -116,6 +118,24 @@ public final class AviExtractor implements Extractor { private static final int AVIIF_KEYFRAME = 16; + /** + * Flags controlling the behavior of the extractor. Possible flag value is {@link + * #FLAG_EMIT_RAW_SUBTITLE_DATA}. + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @Target(TYPE_USE) + @IntDef( + flag = true, + value = {FLAG_EMIT_RAW_SUBTITLE_DATA}) + public @interface Flags {} + + /** + * Flag to use the source subtitle formats without modification. If unset, subtitles will be + * transcoded to {@link MimeTypes#APPLICATION_MEDIA3_CUES} during extraction. + */ + public static final int FLAG_EMIT_RAW_SUBTITLE_DATA = 1; + /** * Maximum size to skip using {@link ExtractorInput#skip}. Boxes larger than this size are skipped * using {@link #RESULT_SEEK}. @@ -124,6 +144,8 @@ public final class AviExtractor implements Extractor { private final ParsableByteArray scratch; private final ChunkHeaderHolder chunkHeaderHolder; + private final boolean parseSubtitlesDuringExtraction; + private final SubtitleParser.Factory subtitleParserFactory; private @State int state; private ExtractorOutput extractorOutput; @@ -139,7 +161,24 @@ public final class AviExtractor implements Extractor { private int idx1BodySize; private boolean seekMapHasBeenOutput; + /** + * @deprecated Use {@link #AviExtractor(int, SubtitleParser.Factory)} instead. + */ + @Deprecated public AviExtractor() { + this(FLAG_EMIT_RAW_SUBTITLE_DATA, SubtitleParser.Factory.UNSUPPORTED); + } + + /** + * Constructs an instance. + * + * @param extractorFlags Flags that control the extractor's behavior. + * @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during + * extraction. + */ + public AviExtractor(@Flags int extractorFlags, SubtitleParser.Factory subtitleParserFactory) { + this.subtitleParserFactory = subtitleParserFactory; + parseSubtitlesDuringExtraction = (extractorFlags & FLAG_EMIT_RAW_SUBTITLE_DATA) == 0; scratch = new ParsableByteArray(/* limit= */ 12); chunkHeaderHolder = new ChunkHeaderHolder(); extractorOutput = new DummyExtractorOutput(); @@ -155,7 +194,10 @@ public final class AviExtractor implements Extractor { @Override public void init(ExtractorOutput output) { this.state = STATE_SKIPPING_TO_HDRL; - this.extractorOutput = output; + this.extractorOutput = + parseSubtitlesDuringExtraction + ? new SubtitleTranscodingExtractorOutput(output, subtitleParserFactory) + : output; pendingReposition = C.INDEX_UNSET; } diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/DefaultExtractorsFactoryTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/DefaultExtractorsFactoryTest.java index ddc9ff3d27..cd3b017be1 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/DefaultExtractorsFactoryTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/DefaultExtractorsFactoryTest.java @@ -175,7 +175,7 @@ public final class DefaultExtractorsFactoryTest { tsExtractor = extractor; } } - assertThat(aviExtractor).isInstanceOf(SubtitleTranscodingExtractor.class); + assertThat(aviExtractor).isNotInstanceOf(SubtitleTranscodingExtractor.class); assertThat(matroskaExtractor).isInstanceOf(SubtitleTranscodingExtractor.class); assertThat(mp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class); assertThat(fragmentedMp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class); diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/avi/AviExtractorTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/avi/AviExtractorTest.java index ab479240e0..d1bf169d23 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/avi/AviExtractorTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/avi/AviExtractorTest.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.avi; +import androidx.media3.extractor.text.SubtitleParser; import androidx.media3.test.utils.ExtractorAsserts; import com.google.common.collect.ImmutableList; import org.junit.Test; @@ -36,6 +37,9 @@ public final class AviExtractorTest { @Test public void aviSample() throws Exception { - ExtractorAsserts.assertBehavior(AviExtractor::new, "media/avi/sample.avi", simulationConfig); + ExtractorAsserts.assertBehavior( + () -> new AviExtractor(/* extractorFlags= */ 0, SubtitleParser.Factory.UNSUPPORTED), + "media/avi/sample.avi", + simulationConfig); } }