Skip to content

Commit 8b33a0a

Browse files
ychaparovcopybara-github
authored andcommitted
Add a ChunkExtractor API to select codecs for sample dependency parsing
Deprecate BundledChunkExtractor.experimentalParseWithinGopSampleDependencies in favour of ChunkExtractor.experimentalSetCodecsToParseWithinGopSampleDependencies which takes a VideoCodecFlags IntDef flags that represent a set of codecs. Add a DASH test using the new API with an H.265 video. PiperOrigin-RevId: 714901602
1 parent 0a27e79 commit 8b33a0a

File tree

7 files changed

+521
-6
lines changed

7 files changed

+521
-6
lines changed

libraries/common/src/main/java/androidx/media3/common/C.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,28 @@ private C() {}
616616
/** See {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}. */
617617
public static final int ALLOW_CAPTURE_BY_SYSTEM = AudioAttributes.ALLOW_CAPTURE_BY_SYSTEM;
618618

619+
/**
620+
* Flags which represent a set of video codecs.
621+
*
622+
*

Possible flag values are:

623+
*
624+
*
    625+
    *
  • {@link #VIDEO_CODEC_FLAG_H264}
  • 626+
    *
  • {@link #VIDEO_CODEC_FLAG_H265}
  • 627+
    *
    628+
    */
    629+
    @UnstableApi
    630+
    @Documented
    631+
    @Retention(RetentionPolicy.SOURCE)
    632+
    @Target(TYPE_USE)
    633+
    @IntDef(
    634+
    flag = true,
    635+
    value = {VIDEO_CODEC_FLAG_H264, VIDEO_CODEC_FLAG_H265})
    636+
    public @interface VideoCodecFlags {}
    637+
    638+
    @UnstableApi public static final int VIDEO_CODEC_FLAG_H264 = 1;
    639+
    @UnstableApi public static final int VIDEO_CODEC_FLAG_H265 = 2;
    640+
    619641
    /**
    620642
    * Flags which can apply to a buffer containing a media sample.
    621643
    *

    libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java

    Lines changed: 18 additions & 4 deletions
    Original file line numberDiff line numberDiff line change
    @@ -61,7 +61,7 @@ public static final class Factory implements ChunkExtractor.Factory {
    6161

    6262
    private SubtitleParser.Factory subtitleParserFactory;
    6363
    private boolean parseSubtitlesDuringExtraction;
    64-
    private boolean parseWithinGopSampleDependencies;
    64+
    private @C.VideoCodecFlags int codecsToParseWithinGopSampleDependencies;
    6565

    6666
    public Factory() {
    6767
    subtitleParserFactory = new DefaultSubtitleParserFactory();
    @@ -82,6 +82,14 @@ public Factory experimentalParseSubtitlesDuringExtraction(
    8282
    return this;
    8383
    }
    8484

    85+
    @Override
    86+
    @CanIgnoreReturnValue
    87+
    public Factory experimentalSetCodecsToParseWithinGopSampleDependencies(
    88+
    @C.VideoCodecFlags int codecsToParseWithinGopSampleDependencies) {
    89+
    this.codecsToParseWithinGopSampleDependencies = codecsToParseWithinGopSampleDependencies;
    90+
    return this;
    91+
    }
    92+
    8593
    /**
    8694
    * {@inheritDoc}
    8795
    *
    @@ -147,9 +155,12 @@ public ChunkExtractor createProgressiveMediaExtractor(
    147155
    if (!parseSubtitlesDuringExtraction) {
    148156
    flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
    149157
    }
    150-
    if (parseWithinGopSampleDependencies) {
    158+
    if ((codecsToParseWithinGopSampleDependencies & C.VIDEO_CODEC_FLAG_H264) != 0) {
    151159
    flags |= FragmentedMp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES;
    152160
    }
    161+
    if ((codecsToParseWithinGopSampleDependencies & C.VIDEO_CODEC_FLAG_H265) != 0) {
    162+
    flags |= FragmentedMp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265;
    163+
    }
    153164
    extractor =
    154165
    new FragmentedMp4Extractor(
    155166
    subtitleParserFactory,
    @@ -171,15 +182,18 @@ public ChunkExtractor createProgressiveMediaExtractor(
    171182
    *
    172183
    *

    This method is experimental and will be renamed or removed in a future release.

    173184
    *
    185+
    * @deprecated Use {@link #experimentalSetCodecsToParseWithinGopSampleDependencies(int)}
    186+
    * instead.
    174187
    * @param parseWithinGopSampleDependencies Whether to parse within GOP sample dependencies
    175188
    * during extraction.
    176189
    * @return This factory, for convenience.
    177190
    */
    178191
    @CanIgnoreReturnValue
    192+
    @Deprecated
    179193
    public Factory experimentalParseWithinGopSampleDependencies(
    180194
    boolean parseWithinGopSampleDependencies) {
    181-
    this.parseWithinGopSampleDependencies = parseWithinGopSampleDependencies;
    182-
    return this;
    195+
    return experimentalSetCodecsToParseWithinGopSampleDependencies(
    196+
    parseWithinGopSampleDependencies ? C.VIDEO_CODEC_FLAG_H264 : 0);
    183197
    }
    184198
    }
    185199

    libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/ChunkExtractor.java

    Lines changed: 20 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -25,6 +25,7 @@
    2525
    import androidx.media3.extractor.Extractor;
    2626
    import androidx.media3.extractor.ExtractorInput;
    2727
    import androidx.media3.extractor.TrackOutput;
    28+
    import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
    2829
    import androidx.media3.extractor.text.SubtitleParser;
    2930
    import com.google.errorprone.annotations.CanIgnoreReturnValue;
    3031
    import java.io.IOException;
    @@ -72,6 +73,25 @@ default Factory experimentalParseSubtitlesDuringExtraction(
    7273
    return this;
    7374
    }
    7475

    76+
    /**
    77+
    * Sets the set of video codecs for which within GOP sample dependency information should be
    78+
    * parsed as part of extraction. Defaults to {@code 0} - empty set of codecs.
    79+
    *
    80+
    *

    Having access to additional sample dependency information can speed up seeking. See {@link

    81+
    * FragmentedMp4Extractor#FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES}.
    82+
    *
    83+
    *

    This method is experimental and will be renamed or removed in a future release.

    84+
    *
    85+
    * @param codecsToParseWithinGopSampleDependencies The set of codecs for which to parse within
    86+
    * GOP sample dependency information.
    87+
    * @return This factory, for convenience.
    88+
    */
    89+
    @CanIgnoreReturnValue
    90+
    default Factory experimentalSetCodecsToParseWithinGopSampleDependencies(
    91+
    @C.VideoCodecFlags int codecsToParseWithinGopSampleDependencies) {
    92+
    return this;
    93+
    }
    94+
    7595
    /**
    7696
    * Returns the output {@link Format} of emitted {@linkplain C#TRACK_TYPE_TEXT text samples}
    7797
    * which were originally in {@code sourceFormat}.

    libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/e2etest/DashPlaybackTest.java

    Lines changed: 42 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -29,6 +29,7 @@
    2929
    import android.net.Uri;
    3030
    import android.view.Surface;
    3131
    import androidx.annotation.Nullable;
    32+
    import androidx.media3.common.C;
    3233
    import androidx.media3.common.MediaItem;
    3334
    import androidx.media3.common.ParserException;
    3435
    import androidx.media3.common.Player;
    @@ -597,7 +598,8 @@ public void playVideo_usingWithinGopSampleDependencies_withSeek() throws Excepti
    597598
    CapturingRenderersFactory capturingRenderersFactory =
    598599
    new CapturingRenderersFactory(applicationContext);
    599600
    BundledChunkExtractor.Factory chunkExtractorFactory =
    600-
    new BundledChunkExtractor.Factory().experimentalParseWithinGopSampleDependencies(true);
    601+
    new BundledChunkExtractor.Factory()
    602+
    .experimentalSetCodecsToParseWithinGopSampleDependencies(C.VIDEO_CODEC_FLAG_H264);
    601603
    DataSource.Factory defaultDataSourceFactory = new DefaultDataSource.Factory(applicationContext);
    602604
    DashMediaSource.Factory dashMediaSourceFactory =
    603605
    new DashMediaSource.Factory(
    @@ -629,7 +631,8 @@ public void playVideo_usingWithinGopSampleDependencies_withSeek() throws Excepti
    629631
    public void playVideo_usingWithinGopSampleDependencies_withSeekAfterEoS() throws Exception {
    630632
    Context applicationContext = ApplicationProvider.getApplicationContext();
    631633
    BundledChunkExtractor.Factory chunkExtractorFactory =
    632-
    new BundledChunkExtractor.Factory().experimentalParseWithinGopSampleDependencies(true);
    634+
    new BundledChunkExtractor.Factory()
    635+
    .experimentalSetCodecsToParseWithinGopSampleDependencies(C.VIDEO_CODEC_FLAG_H264);
    633636
    DataSource.Factory defaultDataSourceFactory = new DefaultDataSource.Factory(applicationContext);
    634637
    DashMediaSource.Factory dashMediaSourceFactory =
    635638
    new DashMediaSource.Factory(
    @@ -656,6 +659,43 @@ public void playVideo_usingWithinGopSampleDependencies_withSeekAfterEoS() throws
    656659
    // assert on the full playback dump.
    657660
    }
    658661

    662+
    @Test
    663+
    public void playVideo_usingWithinGopSampleDependenciesOnH265_withSeek() throws Exception {
    664+
    Context applicationContext = ApplicationProvider.getApplicationContext();
    665+
    CapturingRenderersFactory capturingRenderersFactory =
    666+
    new CapturingRenderersFactory(applicationContext);
    667+
    BundledChunkExtractor.Factory chunkExtractorFactory =
    668+
    new BundledChunkExtractor.Factory()
    669+
    .experimentalSetCodecsToParseWithinGopSampleDependencies(C.VIDEO_CODEC_FLAG_H265);
    670+
    DataSource.Factory defaultDataSourceFactory = new DefaultDataSource.Factory(applicationContext);
    671+
    DashMediaSource.Factory dashMediaSourceFactory =
    672+
    new DashMediaSource.Factory(
    673+
    /* chunkSourceFactory= */ new DefaultDashChunkSource.Factory(
    674+
    chunkExtractorFactory, defaultDataSourceFactory, /* maxSegmentsPerLoad= */ 1),
    675+
    /* manifestDataSourceFactory= */ defaultDataSourceFactory);
    676+
    ExoPlayer player =
    677+
    new ExoPlayer.Builder(applicationContext, capturingRenderersFactory)
    678+
    .setMediaSourceFactory(dashMediaSourceFactory)
    679+
    .setClock(new FakeClock(/* isAutoAdvancing= */ true))
    680+
    .build();
    681+
    player.setTrackSelectionParameters(
    682+
    player.getTrackSelectionParameters().buildUpon().setPreferredTextLanguage("en").build());
    683+
    Surface surface = new Surface(new SurfaceTexture(/* texName= */ 1));
    684+
    player.setVideoSurface(surface);
    685+
    PlaybackOutput playbackOutput = PlaybackOutput.register(player, capturingRenderersFactory);
    686+
    687+
    player.setMediaItem(MediaItem.fromUri("asset:///media/dash/captions_h265/manifest.mpd"));
    688+
    player.seekTo(500L);
    689+
    player.prepare();
    690+
    player.play();
    691+
    TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
    692+
    player.release();
    693+
    surface.release();
    694+
    695+
    DumpFileAsserts.assertOutput(
    696+
    applicationContext, playbackOutput, "playbackdumps/dash/optimized_seek_h265.dump");
    697+
    }
    698+
    659699
    @Test
    660700
    public void multiPeriod_withOffsetInSegment() throws Exception {
    661701
    Context applicationContext = ApplicationProvider.getApplicationContext();
    Lines changed: 15 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,15 @@
    1+
    xml version="1.0" encoding="utf-8"?>
    2+
    <MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" xmlns:cenc="urn:mpeg:cenc:2013" mediaPresentationDuration="PT0H0M2.500S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
    3+
    <Period id="0" duration="PT2.000S">
    4+
    <AdaptationSet mimeType="video/mp4">
    5+
    <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015" value="CC1=eng"/>
    6+
    <Representation codecs="hev1.1.6.L60.90" width="416" height="234" bandwidth="742564" id="sd-dash">
    7+
    <BaseURL>fragmented_captions_h265.mp4BaseURL>
    8+
    <SegmentList presentationTimeOffset="0" duration="20000" timescale="10000">
    9+
    <Initialization range="0-3202"/>
    10+
    <SegmentURL mediaRange="3203-27898"/>
    11+
    SegmentList>
    12+
    Representation>
    13+
    AdaptationSet>
    14+
    Period>
    15+
    MPD>

    0 commit comments

    Comments
     (0)