mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Expose fMP4 FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES to DASH
In order for DASH playback to benefit from FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES, the fMP4 extractor flag must be set. The smallest API change that allows this is to add an experimental method to BundledChunkExtractor. Add a dash end-to-end test to verify that video frames are skipped at decoder input. PiperOrigin-RevId: 651046676
This commit is contained in:
parent
c64dacf3df
commit
0ff9e0723d
3 changed files with 231 additions and 0 deletions
|
|
@ -62,6 +62,7 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
||||||
|
|
||||||
private SubtitleParser.Factory subtitleParserFactory;
|
private SubtitleParser.Factory subtitleParserFactory;
|
||||||
private boolean parseSubtitlesDuringExtraction;
|
private boolean parseSubtitlesDuringExtraction;
|
||||||
|
private boolean parseWithinGopSampleDependencies;
|
||||||
|
|
||||||
public Factory() {
|
public Factory() {
|
||||||
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
||||||
|
|
@ -147,6 +148,9 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
||||||
if (!parseSubtitlesDuringExtraction) {
|
if (!parseSubtitlesDuringExtraction) {
|
||||||
flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
flags |= FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
}
|
}
|
||||||
|
if (parseWithinGopSampleDependencies) {
|
||||||
|
flags |= FragmentedMp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES;
|
||||||
|
}
|
||||||
extractor =
|
extractor =
|
||||||
new FragmentedMp4Extractor(
|
new FragmentedMp4Extractor(
|
||||||
subtitleParserFactory,
|
subtitleParserFactory,
|
||||||
|
|
@ -164,6 +168,26 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
|
||||||
}
|
}
|
||||||
return new BundledChunkExtractor(extractor, primaryTrackType, representationFormat);
|
return new BundledChunkExtractor(extractor, primaryTrackType, representationFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether within GOP sample dependency information should be parsed as part of extraction.
|
||||||
|
* Defaults to {@code false}.
|
||||||
|
*
|
||||||
|
* <p>Having access to additional sample dependency information can speed up seeking. See {@link
|
||||||
|
* FragmentedMp4Extractor#FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES}.
|
||||||
|
*
|
||||||
|
* <p>This method is experimental and will be renamed or removed in a future release.
|
||||||
|
*
|
||||||
|
* @param parseWithinGopSampleDependencies Whether to parse within GOP sample dependencies
|
||||||
|
* during extraction.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Factory experimentalParseWithinGopSampleDependencies(
|
||||||
|
boolean parseWithinGopSampleDependencies) {
|
||||||
|
this.parseWithinGopSampleDependencies = parseWithinGopSampleDependencies;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@link Factory} for {@link BundledChunkExtractor}. */
|
/** {@link Factory} for {@link BundledChunkExtractor}. */
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,16 @@ import android.graphics.SurfaceTexture;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
|
import androidx.media3.datasource.DataSource;
|
||||||
import androidx.media3.datasource.DefaultDataSource;
|
import androidx.media3.datasource.DefaultDataSource;
|
||||||
import androidx.media3.exoplayer.ExoPlayer;
|
import androidx.media3.exoplayer.ExoPlayer;
|
||||||
import androidx.media3.exoplayer.Renderer;
|
import androidx.media3.exoplayer.Renderer;
|
||||||
import androidx.media3.exoplayer.RenderersFactory;
|
import androidx.media3.exoplayer.RenderersFactory;
|
||||||
import androidx.media3.exoplayer.dash.DashMediaSource;
|
import androidx.media3.exoplayer.dash.DashMediaSource;
|
||||||
|
import androidx.media3.exoplayer.dash.DefaultDashChunkSource;
|
||||||
import androidx.media3.exoplayer.metadata.MetadataDecoderFactory;
|
import androidx.media3.exoplayer.metadata.MetadataDecoderFactory;
|
||||||
import androidx.media3.exoplayer.metadata.MetadataRenderer;
|
import androidx.media3.exoplayer.metadata.MetadataRenderer;
|
||||||
|
import androidx.media3.exoplayer.source.chunk.BundledChunkExtractor;
|
||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
|
||||||
import androidx.media3.test.utils.CapturingRenderersFactory;
|
import androidx.media3.test.utils.CapturingRenderersFactory;
|
||||||
import androidx.media3.test.utils.DumpFileAsserts;
|
import androidx.media3.test.utils.DumpFileAsserts;
|
||||||
|
|
@ -365,4 +368,38 @@ public final class DashPlaybackTest {
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
applicationContext, playbackOutput, "playbackdumps/dash/image_with_seek_after_eos.dump");
|
applicationContext, playbackOutput, "playbackdumps/dash/image_with_seek_after_eos.dump");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void playVideo_usingWithinGopSampleDependencies_withSeek() throws Exception {
|
||||||
|
Context applicationContext = ApplicationProvider.getApplicationContext();
|
||||||
|
CapturingRenderersFactory capturingRenderersFactory =
|
||||||
|
new CapturingRenderersFactory(applicationContext);
|
||||||
|
BundledChunkExtractor.Factory chunkExtractorFactory =
|
||||||
|
new BundledChunkExtractor.Factory().experimentalParseWithinGopSampleDependencies(true);
|
||||||
|
DataSource.Factory defaultDataSourceFactory = new DefaultDataSource.Factory(applicationContext);
|
||||||
|
DashMediaSource.Factory dashMediaSourceFactory =
|
||||||
|
new DashMediaSource.Factory(
|
||||||
|
/* chunkSourceFactory= */ new DefaultDashChunkSource.Factory(
|
||||||
|
chunkExtractorFactory, defaultDataSourceFactory, /* maxSegmentsPerLoad= */ 1),
|
||||||
|
/* manifestDataSourceFactory= */ defaultDataSourceFactory);
|
||||||
|
ExoPlayer player =
|
||||||
|
new ExoPlayer.Builder(applicationContext, capturingRenderersFactory)
|
||||||
|
.setMediaSourceFactory(dashMediaSourceFactory)
|
||||||
|
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
||||||
|
.build();
|
||||||
|
Surface surface = new Surface(new SurfaceTexture(/* texName= */ 1));
|
||||||
|
player.setVideoSurface(surface);
|
||||||
|
PlaybackOutput playbackOutput = PlaybackOutput.register(player, capturingRenderersFactory);
|
||||||
|
|
||||||
|
player.setMediaItem(MediaItem.fromUri("asset:///media/dash/standalone-webvtt/sample.mpd"));
|
||||||
|
player.seekTo(500L);
|
||||||
|
player.prepare();
|
||||||
|
player.play();
|
||||||
|
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||||
|
player.release();
|
||||||
|
surface.release();
|
||||||
|
|
||||||
|
DumpFileAsserts.assertOutput(
|
||||||
|
applicationContext, playbackOutput, "playbackdumps/dash/optimized_seek.dump");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
MediaCodecAdapter (exotest.video.avc):
|
||||||
|
inputBuffers:
|
||||||
|
count = 24
|
||||||
|
input buffer #0:
|
||||||
|
timeUs = 1000000000000
|
||||||
|
contents = length 36692, hash D216076E
|
||||||
|
input buffer #1:
|
||||||
|
timeUs = 1000000066733
|
||||||
|
contents = length 5312, hash D45D3CA0
|
||||||
|
input buffer #2:
|
||||||
|
timeUs = 1000000200200
|
||||||
|
contents = length 7735, hash 4490F110
|
||||||
|
input buffer #3:
|
||||||
|
timeUs = 1000000133466
|
||||||
|
contents = length 987, hash 560B5036
|
||||||
|
input buffer #4:
|
||||||
|
timeUs = 1000000333666
|
||||||
|
contents = length 6061, hash 736C72B2
|
||||||
|
input buffer #5:
|
||||||
|
timeUs = 1000000266933
|
||||||
|
contents = length 992, hash FE132F23
|
||||||
|
input buffer #6:
|
||||||
|
timeUs = 1000000433766
|
||||||
|
contents = length 4899, hash F72F86A1
|
||||||
|
input buffer #7:
|
||||||
|
timeUs = 1000000400400
|
||||||
|
contents = length 568, hash 519A8E50
|
||||||
|
input buffer #8:
|
||||||
|
timeUs = 1000000567233
|
||||||
|
contents = length 5450, hash F06EC4AA
|
||||||
|
input buffer #9:
|
||||||
|
timeUs = 1000000500500
|
||||||
|
contents = length 1051, hash 92DFA63A
|
||||||
|
input buffer #10:
|
||||||
|
timeUs = 1000000533866
|
||||||
|
contents = length 781, hash 36BE495B
|
||||||
|
input buffer #11:
|
||||||
|
timeUs = 1000000700700
|
||||||
|
contents = length 4725, hash AC0C8CD3
|
||||||
|
input buffer #12:
|
||||||
|
timeUs = 1000000633966
|
||||||
|
contents = length 1022, hash 5D8BFF34
|
||||||
|
input buffer #13:
|
||||||
|
timeUs = 1000000600600
|
||||||
|
contents = length 790, hash 99413A99
|
||||||
|
input buffer #14:
|
||||||
|
timeUs = 1000000667333
|
||||||
|
contents = length 610, hash 5E129290
|
||||||
|
input buffer #15:
|
||||||
|
timeUs = 1000000834166
|
||||||
|
contents = length 2751, hash 769974CB
|
||||||
|
input buffer #16:
|
||||||
|
timeUs = 1000000767433
|
||||||
|
contents = length 745, hash B78A477A
|
||||||
|
input buffer #17:
|
||||||
|
timeUs = 1000000734066
|
||||||
|
contents = length 621, hash CF741E7A
|
||||||
|
input buffer #18:
|
||||||
|
timeUs = 1000000800800
|
||||||
|
contents = length 505, hash 1DB4894E
|
||||||
|
input buffer #19:
|
||||||
|
timeUs = 1000000967633
|
||||||
|
contents = length 1268, hash C15348DC
|
||||||
|
input buffer #20:
|
||||||
|
timeUs = 1000000900900
|
||||||
|
contents = length 880, hash C2DE85D0
|
||||||
|
input buffer #21:
|
||||||
|
timeUs = 1000000867533
|
||||||
|
contents = length 530, hash C98BC6A8
|
||||||
|
input buffer #22:
|
||||||
|
timeUs = 1000000934266
|
||||||
|
contents = length 568, hash 4FE5C8EA
|
||||||
|
input buffer #23:
|
||||||
|
timeUs = 0
|
||||||
|
flags = 4
|
||||||
|
contents = length 0, hash 1
|
||||||
|
outputBuffers:
|
||||||
|
count = 23
|
||||||
|
output buffer #0:
|
||||||
|
timeUs = 1000000000000
|
||||||
|
size = 36692
|
||||||
|
rendered = false
|
||||||
|
output buffer #1:
|
||||||
|
timeUs = 1000000066733
|
||||||
|
size = 5312
|
||||||
|
rendered = false
|
||||||
|
output buffer #2:
|
||||||
|
timeUs = 1000000200200
|
||||||
|
size = 7735
|
||||||
|
rendered = false
|
||||||
|
output buffer #3:
|
||||||
|
timeUs = 1000000133466
|
||||||
|
size = 987
|
||||||
|
rendered = false
|
||||||
|
output buffer #4:
|
||||||
|
timeUs = 1000000333666
|
||||||
|
size = 6061
|
||||||
|
rendered = false
|
||||||
|
output buffer #5:
|
||||||
|
timeUs = 1000000266933
|
||||||
|
size = 992
|
||||||
|
rendered = false
|
||||||
|
output buffer #6:
|
||||||
|
timeUs = 1000000433766
|
||||||
|
size = 4899
|
||||||
|
rendered = false
|
||||||
|
output buffer #7:
|
||||||
|
timeUs = 1000000400400
|
||||||
|
size = 568
|
||||||
|
rendered = false
|
||||||
|
output buffer #8:
|
||||||
|
timeUs = 1000000567233
|
||||||
|
size = 5450
|
||||||
|
rendered = true
|
||||||
|
output buffer #9:
|
||||||
|
timeUs = 1000000500500
|
||||||
|
size = 1051
|
||||||
|
rendered = true
|
||||||
|
output buffer #10:
|
||||||
|
timeUs = 1000000533866
|
||||||
|
size = 781
|
||||||
|
rendered = true
|
||||||
|
output buffer #11:
|
||||||
|
timeUs = 1000000700700
|
||||||
|
size = 4725
|
||||||
|
rendered = true
|
||||||
|
output buffer #12:
|
||||||
|
timeUs = 1000000633966
|
||||||
|
size = 1022
|
||||||
|
rendered = true
|
||||||
|
output buffer #13:
|
||||||
|
timeUs = 1000000600600
|
||||||
|
size = 790
|
||||||
|
rendered = true
|
||||||
|
output buffer #14:
|
||||||
|
timeUs = 1000000667333
|
||||||
|
size = 610
|
||||||
|
rendered = true
|
||||||
|
output buffer #15:
|
||||||
|
timeUs = 1000000834166
|
||||||
|
size = 2751
|
||||||
|
rendered = true
|
||||||
|
output buffer #16:
|
||||||
|
timeUs = 1000000767433
|
||||||
|
size = 745
|
||||||
|
rendered = true
|
||||||
|
output buffer #17:
|
||||||
|
timeUs = 1000000734066
|
||||||
|
size = 621
|
||||||
|
rendered = true
|
||||||
|
output buffer #18:
|
||||||
|
timeUs = 1000000800800
|
||||||
|
size = 505
|
||||||
|
rendered = true
|
||||||
|
output buffer #19:
|
||||||
|
timeUs = 1000000967633
|
||||||
|
size = 1268
|
||||||
|
rendered = true
|
||||||
|
output buffer #20:
|
||||||
|
timeUs = 1000000900900
|
||||||
|
size = 880
|
||||||
|
rendered = true
|
||||||
|
output buffer #21:
|
||||||
|
timeUs = 1000000867533
|
||||||
|
size = 530
|
||||||
|
rendered = true
|
||||||
|
output buffer #22:
|
||||||
|
timeUs = 1000000934266
|
||||||
|
size = 568
|
||||||
|
rendered = true
|
||||||
Loading…
Reference in a new issue