diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java index e833dece8a..e066ee2783 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java @@ -155,12 +155,9 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac if (!parseSubtitlesDuringExtraction) { flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA; } - if ((codecsToParseWithinGopSampleDependencies & C.VIDEO_CODEC_FLAG_H264) != 0) { - flags |= FragmentedMp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES; - } - if ((codecsToParseWithinGopSampleDependencies & C.VIDEO_CODEC_FLAG_H265) != 0) { - flags |= FragmentedMp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265; - } + flags |= + FragmentedMp4Extractor.codecsToParseWithinGopSampleDependenciesAsFlags( + codecsToParseWithinGopSampleDependencies); extractor = new FragmentedMp4Extractor( subtitleParserFactory, 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 b625523696..3caaa6d9e8 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java @@ -23,6 +23,7 @@ import static androidx.media3.extractor.mp4.Mp4Extractor.FLAG_READ_SEF_DATA; import android.net.Uri; import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; +import androidx.media3.common.C; import androidx.media3.common.FileTypes; import androidx.media3.common.Format; import androidx.media3.common.PlaybackException; @@ -154,6 +155,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { private int tsTimestampSearchBytes; private boolean textTrackTranscodingEnabled; private SubtitleParser.Factory subtitleParserFactory; + private @C.VideoCodecFlags int codecsToParseWithinGopSampleDependencies; private @JpegExtractor.Flags int jpegFlags; public DefaultExtractorsFactory() { @@ -387,6 +389,15 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { return this; } + @CanIgnoreReturnValue + @Override + public synchronized DefaultExtractorsFactory + experimentalSetCodecsToParseWithinGopSampleDependencies( + @C.VideoCodecFlags int codecsToParseWithinGopSampleDependencies) { + this.codecsToParseWithinGopSampleDependencies = codecsToParseWithinGopSampleDependencies; + return this; + } + /** * Sets flags for {@link JpegExtractor} instances created by the factory. * @@ -498,6 +509,8 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { new FragmentedMp4Extractor( subtitleParserFactory, fragmentedMp4Flags + | FragmentedMp4Extractor.codecsToParseWithinGopSampleDependenciesAsFlags( + codecsToParseWithinGopSampleDependencies) | (textTrackTranscodingEnabled ? 0 : FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA))); @@ -505,6 +518,8 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { new Mp4Extractor( subtitleParserFactory, mp4Flags + | Mp4Extractor.codecsToParseWithinGopSampleDependenciesAsFlags( + codecsToParseWithinGopSampleDependencies) | (textTrackTranscodingEnabled ? 0 : Mp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA))); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java index f13f5ae70e..98d5d886f4 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorsFactory.java @@ -16,8 +16,10 @@ package androidx.media3.extractor; import android.net.Uri; +import androidx.media3.common.C; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; +import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.extractor.text.SubtitleParser; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.List; @@ -66,6 +68,25 @@ public interface ExtractorsFactory { return this; } + /** + * Sets the set of video codecs for which within GOP sample dependency information should be + * parsed as part of extraction. Defaults to {@code 0} - empty set of codecs. + * + *
Having access to additional sample dependency information can speed up seeking. See {@link + * Mp4Extractor#FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES}. + * + *
This method is experimental and will be renamed or removed in a future release. + * + * @param codecsToParseWithinGopSampleDependencies The set of codecs for which to parse within GOP + * sample dependency information. + * @return This factory, for convenience. + */ + @CanIgnoreReturnValue + default ExtractorsFactory experimentalSetCodecsToParseWithinGopSampleDependencies( + @C.VideoCodecFlags int codecsToParseWithinGopSampleDependencies) { + return this; + } + /** Returns an array of new {@link Extractor} instances. */ Extractor[] createExtractors(); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java index 3611ddf120..87dde81438 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java @@ -430,6 +430,23 @@ public class FragmentedMp4Extractor implements Extractor { CeaUtil.consume(presentationTimeUs, seiBuffer, ceaTrackOutputs)); } + /** + * Returns {@link Flags} denoting if an extractor should parse within GOP sample dependencies. + * + * @param videoCodecFlags The set of codecs for which to parse within GOP sample dependencies. + */ + public static @Flags int codecsToParseWithinGopSampleDependenciesAsFlags( + @C.VideoCodecFlags int videoCodecFlags) { + @Flags int flags = 0; + if ((videoCodecFlags & C.VIDEO_CODEC_FLAG_H264) != 0) { + flags |= FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES; + } + if ((videoCodecFlags & C.VIDEO_CODEC_FLAG_H265) != 0) { + flags |= FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265; + } + return flags; + } + @Override public boolean sniff(ExtractorInput input) throws IOException { @Nullable SniffFailure sniffFailure = Sniffer.sniffFragmented(input); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java index b69f49ff4e..98b46e1758 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java @@ -319,6 +319,23 @@ public final class Mp4Extractor implements Extractor, SeekMap { tracks = new Mp4Track[0]; } + /** + * Returns {@link Flags} denoting if an extractor should parse within GOP sample dependencies. + * + * @param videoCodecFlags The set of codecs for which to parse within GOP sample dependencies. + */ + public static @Flags int codecsToParseWithinGopSampleDependenciesAsFlags( + @C.VideoCodecFlags int videoCodecFlags) { + @Flags int flags = 0; + if ((videoCodecFlags & C.VIDEO_CODEC_FLAG_H264) != 0) { + flags |= FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES; + } + if ((videoCodecFlags & C.VIDEO_CODEC_FLAG_H265) != 0) { + flags |= FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265; + } + return flags; + } + @Override public boolean sniff(ExtractorInput input) throws IOException { @Nullable