Plumb SubtitleParser.Factory into AviExtractor
AviExtractor supports text tracks (`AviExtractor.FOURCC_txts` -> `C.TRACK_TYPE_TEXT`) with subtitles. AviExtractor will no longer be wrapped in SubtitleTranscodingExtractor, but instead use SubtitleTranscodingExtractorOutput under the hood. FLAG_EMIT_RAW_SUBTITLE_DATA flag will be used to toggle between subtitle parsing during extraction (before the sample queue) or during decoding (after the sample queue). PiperOrigin-RevId: 598594981
This commit is contained in:
parent
4a07d13838
commit
a88d8a415a
@ -441,6 +441,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
&& !(extractor.getUnderlyingImplementation() instanceof FragmentedMp4Extractor)
|
&& !(extractor.getUnderlyingImplementation() instanceof FragmentedMp4Extractor)
|
||||||
&& !(extractor.getUnderlyingImplementation() instanceof Mp4Extractor)
|
&& !(extractor.getUnderlyingImplementation() instanceof Mp4Extractor)
|
||||||
&& !(extractor.getUnderlyingImplementation() instanceof TsExtractor)
|
&& !(extractor.getUnderlyingImplementation() instanceof TsExtractor)
|
||||||
|
&& !(extractor.getUnderlyingImplementation() instanceof AviExtractor)
|
||||||
? new SubtitleTranscodingExtractor(extractor, subtitleParserFactory)
|
? new SubtitleTranscodingExtractor(extractor, subtitleParserFactory)
|
||||||
: extractor;
|
: extractor;
|
||||||
}
|
}
|
||||||
@ -550,7 +551,10 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FileTypes.AVI:
|
case FileTypes.AVI:
|
||||||
extractors.add(new AviExtractor());
|
extractors.add(
|
||||||
|
new AviExtractor(
|
||||||
|
(textTrackTranscodingEnabled ? 0 : AviExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA),
|
||||||
|
subtitleParserFactory));
|
||||||
break;
|
break;
|
||||||
case FileTypes.PNG:
|
case FileTypes.PNG:
|
||||||
extractors.add(new PngExtractor());
|
extractors.add(new PngExtractor());
|
||||||
|
@ -34,6 +34,8 @@ import androidx.media3.extractor.ExtractorOutput;
|
|||||||
import androidx.media3.extractor.PositionHolder;
|
import androidx.media3.extractor.PositionHolder;
|
||||||
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.SubtitleParser;
|
||||||
|
import androidx.media3.extractor.text.SubtitleTranscodingExtractorOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@ -116,6 +118,24 @@ public final class AviExtractor implements Extractor {
|
|||||||
|
|
||||||
private static final int AVIIF_KEYFRAME = 16;
|
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
|
* Maximum size to skip using {@link ExtractorInput#skip}. Boxes larger than this size are skipped
|
||||||
* using {@link #RESULT_SEEK}.
|
* using {@link #RESULT_SEEK}.
|
||||||
@ -124,6 +144,8 @@ public final class AviExtractor implements Extractor {
|
|||||||
|
|
||||||
private final ParsableByteArray scratch;
|
private final ParsableByteArray scratch;
|
||||||
private final ChunkHeaderHolder chunkHeaderHolder;
|
private final ChunkHeaderHolder chunkHeaderHolder;
|
||||||
|
private final boolean parseSubtitlesDuringExtraction;
|
||||||
|
private final SubtitleParser.Factory subtitleParserFactory;
|
||||||
|
|
||||||
private @State int state;
|
private @State int state;
|
||||||
private ExtractorOutput extractorOutput;
|
private ExtractorOutput extractorOutput;
|
||||||
@ -139,7 +161,24 @@ public final class AviExtractor implements Extractor {
|
|||||||
private int idx1BodySize;
|
private int idx1BodySize;
|
||||||
private boolean seekMapHasBeenOutput;
|
private boolean seekMapHasBeenOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AviExtractor(int, SubtitleParser.Factory)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public AviExtractor() {
|
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);
|
scratch = new ParsableByteArray(/* limit= */ 12);
|
||||||
chunkHeaderHolder = new ChunkHeaderHolder();
|
chunkHeaderHolder = new ChunkHeaderHolder();
|
||||||
extractorOutput = new DummyExtractorOutput();
|
extractorOutput = new DummyExtractorOutput();
|
||||||
@ -155,7 +194,10 @@ public final class AviExtractor implements Extractor {
|
|||||||
@Override
|
@Override
|
||||||
public void init(ExtractorOutput output) {
|
public void init(ExtractorOutput output) {
|
||||||
this.state = STATE_SKIPPING_TO_HDRL;
|
this.state = STATE_SKIPPING_TO_HDRL;
|
||||||
this.extractorOutput = output;
|
this.extractorOutput =
|
||||||
|
parseSubtitlesDuringExtraction
|
||||||
|
? new SubtitleTranscodingExtractorOutput(output, subtitleParserFactory)
|
||||||
|
: output;
|
||||||
pendingReposition = C.INDEX_UNSET;
|
pendingReposition = C.INDEX_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ public final class DefaultExtractorsFactoryTest {
|
|||||||
tsExtractor = extractor;
|
tsExtractor = extractor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertThat(aviExtractor).isInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(aviExtractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
assertThat(matroskaExtractor).isInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(matroskaExtractor).isInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
assertThat(mp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(mp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
assertThat(fragmentedMp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(fragmentedMp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.extractor.avi;
|
package androidx.media3.extractor.avi;
|
||||||
|
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
import androidx.media3.test.utils.ExtractorAsserts;
|
import androidx.media3.test.utils.ExtractorAsserts;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -36,6 +37,9 @@ public final class AviExtractorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void aviSample() throws Exception {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user