diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/DefaultSubtitleParserFactory.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/DefaultSubtitleParserFactory.java index 1d3db619eb..b2a271956b 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/DefaultSubtitleParserFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/DefaultSubtitleParserFactory.java @@ -17,6 +17,7 @@ package androidx.media3.extractor.text; import androidx.annotation.Nullable; import androidx.media3.common.Format; +import androidx.media3.common.Format.CueReplacementBehavior; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; import androidx.media3.extractor.text.dvb.DvbParser; @@ -61,6 +62,34 @@ public final class DefaultSubtitleParserFactory implements SubtitleParser.Factor || Objects.equals(mimeType, MimeTypes.APPLICATION_TTML); } + @Override + public @CueReplacementBehavior int getCueReplacementBehavior(Format format) { + @Nullable String mimeType = format.sampleMimeType; + if (mimeType != null) { + switch (mimeType) { + case MimeTypes.TEXT_SSA: + return SsaParser.CUE_REPLACEMENT_BEHAVIOR; + case MimeTypes.TEXT_VTT: + return WebvttParser.CUE_REPLACEMENT_BEHAVIOR; + case MimeTypes.APPLICATION_MP4VTT: + return Mp4WebvttParser.CUE_REPLACEMENT_BEHAVIOR; + case MimeTypes.APPLICATION_SUBRIP: + return SubripParser.CUE_REPLACEMENT_BEHAVIOR; + case MimeTypes.APPLICATION_TX3G: + return Tx3gParser.CUE_REPLACEMENT_BEHAVIOR; + case MimeTypes.APPLICATION_PGS: + return PgsParser.CUE_REPLACEMENT_BEHAVIOR; + case MimeTypes.APPLICATION_DVBSUBS: + return DvbParser.CUE_REPLACEMENT_BEHAVIOR; + case MimeTypes.APPLICATION_TTML: + return TtmlParser.CUE_REPLACEMENT_BEHAVIOR; + default: + break; + } + } + throw new IllegalArgumentException("Unsupported MIME type: " + mimeType); + } + @Override public SubtitleParser create(Format format) { @Nullable String mimeType = format.sampleMimeType; @@ -86,7 +115,6 @@ public final class DefaultSubtitleParserFactory implements SubtitleParser.Factor break; } } - throw new IllegalArgumentException( - "Attempted to create parser for unsupported MIME type: " + mimeType); + throw new IllegalArgumentException("Unsupported MIME type: " + mimeType); } } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/SubtitleParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/SubtitleParser.java index f5aa4a706c..125a538022 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/SubtitleParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/SubtitleParser.java @@ -16,8 +16,6 @@ package androidx.media3.extractor.text; -import static androidx.media3.common.Format.CUE_REPLACEMENT_BEHAVIOR_MERGE; - import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.Format; @@ -51,7 +49,24 @@ public interface SubtitleParser { */ boolean supportsFormat(Format format); - /** Creates a {@link SubtitleParser} for the given {@link Format}. */ + /** + * Returns the {@link CueReplacementBehavior} of the {@link SubtitleParser} implementation that + * handles {@code format}. + * + * @return The replacement behavior. + * @throws IllegalArgumentException if {@code format} is {@linkplain #supportsFormat(Format) not + * supported} by this factory. + */ + @CueReplacementBehavior + int getCueReplacementBehavior(Format format); + + /** + * Creates a {@link SubtitleParser} for the given {@link Format}. + * + * @return The {@link SubtitleParser} instance. + * @throws IllegalArgumentException if {@code format} is {@linkplain #supportsFormat(Format) not + * supported} by this factory. + */ SubtitleParser create(Format format); } @@ -247,10 +262,7 @@ public interface SubtitleParser { * this implementation. * *

A given instance must always return the same value from this method. - * - *

The default implementation returns {@link Format#CUE_REPLACEMENT_BEHAVIOR_MERGE}. */ - default @CueReplacementBehavior int getCueReplacementBehavior() { - return CUE_REPLACEMENT_BEHAVIOR_MERGE; - } + @CueReplacementBehavior + int getCueReplacementBehavior(); } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/dvb/DvbParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/dvb/DvbParser.java index 6cfeeca1b3..d75b2d3299 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/dvb/DvbParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/dvb/DvbParser.java @@ -45,6 +45,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @UnstableApi public final class DvbParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + private static final String TAG = "DvbParser"; // Segment types, as defined by ETSI EN 300 743 Table 2 @@ -132,7 +139,7 @@ public final class DvbParser implements SubtitleParser { @Override public @CueReplacementBehavior int getCueReplacementBehavior() { - return Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + return CUE_REPLACEMENT_BEHAVIOR; } @Override diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/pgs/PgsParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/pgs/PgsParser.java index e55334e0fa..c916302a1b 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/pgs/PgsParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/pgs/PgsParser.java @@ -37,6 +37,13 @@ import java.util.zip.Inflater; @UnstableApi public final class PgsParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + private static final int SECTION_TYPE_PALETTE = 0x14; private static final int SECTION_TYPE_BITMAP_PICTURE = 0x15; private static final int SECTION_TYPE_IDENTIFIER = 0x16; @@ -57,7 +64,7 @@ public final class PgsParser implements SubtitleParser { @Override public @CueReplacementBehavior int getCueReplacementBehavior() { - return Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + return CUE_REPLACEMENT_BEHAVIOR; } @Override diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/ssa/SsaParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/ssa/SsaParser.java index 601e0fec7d..5098b64f35 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/ssa/SsaParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/ssa/SsaParser.java @@ -28,6 +28,8 @@ import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; import androidx.annotation.Nullable; import androidx.media3.common.C; +import androidx.media3.common.Format; +import androidx.media3.common.Format.CueReplacementBehavior; import androidx.media3.common.text.Cue; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Log; @@ -52,6 +54,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @UnstableApi public final class SsaParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_MERGE; + private static final String TAG = "SsaParser"; private static final Pattern SSA_TIMECODE_PATTERN = @@ -117,6 +126,11 @@ public final class SsaParser implements SubtitleParser { } } + @Override + public @CueReplacementBehavior int getCueReplacementBehavior() { + return CUE_REPLACEMENT_BEHAVIOR; + } + @Nullable @Override public ImmutableList parse(byte[] data, int offset, int length) { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/subrip/SubripParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/subrip/SubripParser.java index a159276d9d..1ed05b83ba 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/subrip/SubripParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/subrip/SubripParser.java @@ -22,6 +22,8 @@ import android.text.Spanned; import android.text.TextUtils; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.media3.common.Format; +import androidx.media3.common.Format.CueReplacementBehavior; import androidx.media3.common.text.Cue; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Log; @@ -40,6 +42,13 @@ import java.util.regex.Pattern; @UnstableApi public final class SubripParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_MERGE; + // Fractional positions for use when alignment tags are present. private static final float START_FRACTION = 0.08f; private static final float END_FRACTION = 1 - START_FRACTION; @@ -77,6 +86,11 @@ public final class SubripParser implements SubtitleParser { parsableByteArray = new ParsableByteArray(); } + @Override + public @CueReplacementBehavior int getCueReplacementBehavior() { + return CUE_REPLACEMENT_BEHAVIOR; + } + @Nullable @Override public ImmutableList parse(byte[] data, int offset, int length) { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlParser.java index f699336f71..5899680cc6 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/ttml/TtmlParser.java @@ -23,6 +23,8 @@ import static java.lang.Math.min; import android.text.Layout; import androidx.annotation.Nullable; import androidx.media3.common.C; +import androidx.media3.common.Format; +import androidx.media3.common.Format.CueReplacementBehavior; import androidx.media3.common.text.Cue; import androidx.media3.common.text.TextAnnotation; import androidx.media3.common.util.Assertions; @@ -77,6 +79,13 @@ import org.xmlpull.v1.XmlPullParserFactory; @UnstableApi public final class TtmlParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_MERGE; + private static final String TAG = "TtmlParser"; private static final String TTP = "http://www.w3.org/ns/ttml#parameter"; @@ -119,6 +128,11 @@ public final class TtmlParser implements SubtitleParser { } } + @Override + public @CueReplacementBehavior int getCueReplacementBehavior() { + return CUE_REPLACEMENT_BEHAVIOR; + } + @Override public ImmutableList parse(byte[] data, int offset, int length) { ImmutableList.Builder cues = ImmutableList.builder(); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/tx3g/Tx3gParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/tx3g/Tx3gParser.java index f7258d858e..3478693286 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/tx3g/Tx3gParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/tx3g/Tx3gParser.java @@ -51,6 +51,13 @@ import java.util.List; @UnstableApi public final class Tx3gParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + private static final String TAG = "Tx3gParser"; private static final int TYPE_STYL = 0x7374796c; @@ -126,7 +133,7 @@ public final class Tx3gParser implements SubtitleParser { @Override public @CueReplacementBehavior int getCueReplacementBehavior() { - return Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + return CUE_REPLACEMENT_BEHAVIOR; } @Override diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/Mp4WebvttParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/Mp4WebvttParser.java index 968d77d6ca..6e46ad786d 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/Mp4WebvttParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/Mp4WebvttParser.java @@ -37,6 +37,13 @@ import java.util.List; @UnstableApi public final class Mp4WebvttParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + private static final int BOX_HEADER_SIZE = 8; @SuppressWarnings("ConstantCaseForConstants") @@ -56,7 +63,7 @@ public final class Mp4WebvttParser implements SubtitleParser { @Override public @CueReplacementBehavior int getCueReplacementBehavior() { - return Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE; + return CUE_REPLACEMENT_BEHAVIOR; } @Override diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttParser.java index 62604398a7..c374f79b48 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/webvtt/WebvttParser.java @@ -17,6 +17,8 @@ package androidx.media3.extractor.text.webvtt; import android.text.TextUtils; import androidx.annotation.Nullable; +import androidx.media3.common.Format; +import androidx.media3.common.Format.CueReplacementBehavior; import androidx.media3.common.ParserException; import androidx.media3.common.util.Consumer; import androidx.media3.common.util.ParsableByteArray; @@ -36,6 +38,13 @@ import java.util.List; @UnstableApi public final class WebvttParser implements SubtitleParser { + /** + * The {@link CueReplacementBehavior} for consecutive {@link CuesWithTiming} emitted by this + * implementation. + */ + public static final @CueReplacementBehavior int CUE_REPLACEMENT_BEHAVIOR = + Format.CUE_REPLACEMENT_BEHAVIOR_MERGE; + private static final int EVENT_NONE = -1; private static final int EVENT_END_OF_FILE = 0; private static final int EVENT_COMMENT = 1; @@ -53,6 +62,11 @@ public final class WebvttParser implements SubtitleParser { cssParser = new WebvttCssParser(); } + @Override + public @CueReplacementBehavior int getCueReplacementBehavior() { + return CUE_REPLACEMENT_BEHAVIOR; + } + @Override public ImmutableList parse(byte[] data, int offset, int length) { ImmutableList.Builder result = ImmutableList.builder();