mirror of
https://github.com/androidx/media.git
synced 2025-04-29 22:36:54 +08:00
Report initial discontinuity for DASH periods that require preroll
DASH periods don't have to start at the beginning of a segment. In these cases, they should report an initial discontinuity to let the player know it needs to expect preroll data (e.g. to flush renderers) This information is only available in the ChunkSampleStream after loading the initialization data, so we need to check the sample streams and tell them to only report discontinuities at the very beginning of playback. All other position resets are triggered by the player itself and don't need this method. Issue: androidx/media#1440 PiperOrigin-RevId: 668831563
This commit is contained in:
parent
8367e420ad
commit
e8664dbc8e
@ -101,6 +101,9 @@
|
||||
* Cronet Extension:
|
||||
* RTMP Extension:
|
||||
* HLS Extension:
|
||||
* DASH Extension:
|
||||
* Add support for periods starting in the middle of a segment
|
||||
([#1440](https://github.com/androidx/media/issues/1440)).
|
||||
* Smooth Streaming Extension:
|
||||
* RTSP Extension:
|
||||
* Decoder Extensions (FFmpeg, VP9, AV1, etc.):
|
||||
|
@ -22,6 +22,7 @@ import static java.lang.Math.min;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
@ -95,6 +96,8 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
private long lastSeekPositionUs;
|
||||
private int nextNotifyPrimaryFormatMediaChunkIndex;
|
||||
@Nullable private BaseMediaChunk canceledMediaChunk;
|
||||
private boolean canReportInitialDiscontinuity;
|
||||
private boolean hasInitialDiscontinuity;
|
||||
|
||||
/* package */ boolean loadingFinished;
|
||||
|
||||
@ -114,6 +117,8 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
* @param loadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy}.
|
||||
* @param mediaSourceEventDispatcher A dispatcher to notify of {@link MediaSourceEventListener}
|
||||
* events.
|
||||
* @param canReportInitialDiscontinuity Whether the stream can report an initial discontinuity if
|
||||
* the first chunk can't start at the beginning and needs to preroll data.
|
||||
*/
|
||||
public ChunkSampleStream(
|
||||
@C.TrackType int primaryTrackType,
|
||||
@ -126,7 +131,8 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher) {
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
boolean canReportInitialDiscontinuity) {
|
||||
this.primaryTrackType = primaryTrackType;
|
||||
this.embeddedTrackTypes = embeddedTrackTypes == null ? new int[0] : embeddedTrackTypes;
|
||||
this.embeddedTrackFormats = embeddedTrackFormats == null ? new Format[0] : embeddedTrackFormats;
|
||||
@ -134,6 +140,7 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
this.callback = callback;
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.canReportInitialDiscontinuity = canReportInitialDiscontinuity;
|
||||
loader = new Loader("ChunkSampleStream");
|
||||
nextChunkHolder = new ChunkHolder();
|
||||
mediaChunks = new ArrayList<>();
|
||||
@ -258,6 +265,7 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
*/
|
||||
public void seekToUs(long positionUs) {
|
||||
lastSeekPositionUs = positionUs;
|
||||
canReportInitialDiscontinuity = false;
|
||||
if (isPendingReset()) {
|
||||
// A reset is already pending. We only need to update its position.
|
||||
pendingResetPositionUs = positionUs;
|
||||
@ -600,12 +608,22 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
// seeking to a chunk boundary then we want the queue to pass through all of the samples in
|
||||
// the chunk. Doing this ensures we'll always output the keyframe at the start of the chunk,
|
||||
// even if its timestamp is slightly earlier than the advertised chunk start time.
|
||||
if (mediaChunk.startTimeUs != pendingResetPositionUs) {
|
||||
if (mediaChunk.startTimeUs < pendingResetPositionUs) {
|
||||
primarySampleQueue.setStartTimeUs(pendingResetPositionUs);
|
||||
for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) {
|
||||
embeddedSampleQueue.setStartTimeUs(pendingResetPositionUs);
|
||||
}
|
||||
if (canReportInitialDiscontinuity) {
|
||||
// Only report it as discontinuity if the SampleQueue can't skip the samples directly.
|
||||
boolean sampleQueueCanSkipSamples =
|
||||
MimeTypes.allSamplesAreSyncSamples(
|
||||
mediaChunk.trackFormat.sampleMimeType, mediaChunk.trackFormat.codecs);
|
||||
hasInitialDiscontinuity = !sampleQueueCanSkipSamples;
|
||||
}
|
||||
}
|
||||
// Once we started loading the first media chunk, no more initial discontinuities can be
|
||||
// reported.
|
||||
canReportInitialDiscontinuity = false;
|
||||
pendingResetPositionUs = C.TIME_UNSET;
|
||||
}
|
||||
mediaChunk.init(chunkOutput);
|
||||
@ -670,6 +688,19 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes a pending initial discontinuity.
|
||||
*
|
||||
* @return Whether the stream had an initial discontinuity.
|
||||
*/
|
||||
public boolean consumeInitialDiscontinuity() {
|
||||
try {
|
||||
return hasInitialDiscontinuity;
|
||||
} finally {
|
||||
hasInitialDiscontinuity = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void discardUpstream(int preferredQueueSize) {
|
||||
Assertions.checkState(!loader.isLoading());
|
||||
|
||||
|
@ -114,6 +114,8 @@ import java.util.regex.Pattern;
|
||||
private DashManifest manifest;
|
||||
private int periodIndex;
|
||||
private List<EventStream> eventStreams;
|
||||
private boolean canReportInitialDiscontinuity;
|
||||
private long initialStartTimeUs;
|
||||
|
||||
public DashMediaPeriod(
|
||||
int id,
|
||||
@ -149,6 +151,7 @@ import java.util.regex.Pattern;
|
||||
this.allocator = allocator;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
this.playerId = playerId;
|
||||
this.canReportInitialDiscontinuity = true;
|
||||
playerEmsgHandler = new PlayerEmsgHandler(manifest, playerEmsgCallback, allocator);
|
||||
sampleStreams = newSampleStreamArray(0);
|
||||
eventSampleStreams = new EventSampleStream[0];
|
||||
@ -305,6 +308,10 @@ import java.util.regex.Pattern;
|
||||
compositeSequenceableLoaderFactory.create(
|
||||
sampleStreamList,
|
||||
Lists.transform(sampleStreamList, s -> ImmutableList.of(s.primaryTrackType)));
|
||||
if (canReportInitialDiscontinuity) {
|
||||
canReportInitialDiscontinuity = false;
|
||||
initialStartTimeUs = positionUs;
|
||||
}
|
||||
return positionUs;
|
||||
}
|
||||
|
||||
@ -337,6 +344,11 @@ import java.util.regex.Pattern;
|
||||
|
||||
@Override
|
||||
public long readDiscontinuity() {
|
||||
for (ChunkSampleStream<DashChunkSource> sampleStream : sampleStreams) {
|
||||
if (sampleStream.consumeInitialDiscontinuity()) {
|
||||
return initialStartTimeUs;
|
||||
}
|
||||
}
|
||||
return C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@ -824,7 +836,8 @@ import java.util.regex.Pattern;
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
mediaSourceEventDispatcher);
|
||||
mediaSourceEventDispatcher,
|
||||
canReportInitialDiscontinuity);
|
||||
synchronized (this) {
|
||||
// The map is also accessed on the loading thread so synchronize access.
|
||||
trackEmsgHandlerBySampleStream.put(stream, trackPlayerEmsgHandler);
|
||||
|
@ -440,4 +440,27 @@ public final class DashPlaybackTest {
|
||||
// TODO: b/352276461 - The last frame might not be rendered. When the bug is fixed,
|
||||
// assert on the full playback dump.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiPeriod_withOffsetInSegment() throws Exception {
|
||||
Context applicationContext = ApplicationProvider.getApplicationContext();
|
||||
CapturingRenderersFactory capturingRenderersFactory =
|
||||
new CapturingRenderersFactory(applicationContext);
|
||||
ExoPlayer player =
|
||||
new ExoPlayer.Builder(applicationContext, capturingRenderersFactory)
|
||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
||||
.build();
|
||||
player.setVideoSurface(new Surface(new SurfaceTexture(/* texName= */ 1)));
|
||||
PlaybackOutput playbackOutput = PlaybackOutput.register(player, capturingRenderersFactory);
|
||||
|
||||
player.setMediaItem(
|
||||
MediaItem.fromUri("asset:///media/dash/multi-period-with-offset/sample.mpd"));
|
||||
player.prepare();
|
||||
player.play();
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
player.release();
|
||||
|
||||
DumpFileAsserts.assertOutput(
|
||||
applicationContext, playbackOutput, "playbackdumps/dash/multi-period-with-offset.dump");
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +264,8 @@ import java.util.List;
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
mediaSourceEventDispatcher);
|
||||
mediaSourceEventDispatcher,
|
||||
/* canReportInitialDiscontinuity= */ false);
|
||||
}
|
||||
|
||||
private static TrackGroupArray buildTrackGroups(
|
||||
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT1.0010000467300415S">
|
||||
<Period id='0' duration='PT0.5S'>
|
||||
<AdaptationSet id="1" contentType="video" width="1080" height="720" frameRate="30000/1001" subsegmentAlignment="true" par="3:2">
|
||||
<Representation id="1" bandwidth="721967" codecs="avc1.64001f" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>sample.video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="862-905" timescale="30000">
|
||||
<Initialization range="0-861"/>
|
||||
</SegmentBase>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
<Period id='1'>
|
||||
<AdaptationSet id="1" contentType="video" width="1080" height="720" frameRate="30000/1001" subsegmentAlignment="true" par="3:2">
|
||||
<Representation id="1" bandwidth="721967" codecs="avc1.64001f" mimeType="video/mp4" sar="1:1">
|
||||
<BaseURL>sample.video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="862-905" timescale="30000" presentationTimeOffset="15000">
|
||||
<Initialization range="0-861"/>
|
||||
</SegmentBase>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
Binary file not shown.
@ -0,0 +1,321 @@
|
||||
MediaCodecAdapter (exotest.video.avc):
|
||||
inputBuffers:
|
||||
count = 46
|
||||
input buffer #0:
|
||||
timeUs = 1000000000000
|
||||
contents = length 36692, hash D216076E
|
||||
input buffer #1:
|
||||
timeUs = 1000000066733
|
||||
contents = length 5312, hash D45D3CA0
|
||||
input buffer #2:
|
||||
timeUs = 1000000033366
|
||||
contents = length 599, hash 1BE7812D
|
||||
input buffer #3:
|
||||
timeUs = 1000000200200
|
||||
contents = length 7735, hash 4490F110
|
||||
input buffer #4:
|
||||
timeUs = 1000000133466
|
||||
contents = length 987, hash 560B5036
|
||||
input buffer #5:
|
||||
timeUs = 1000000100100
|
||||
contents = length 673, hash ED7CD8C7
|
||||
input buffer #6:
|
||||
timeUs = 1000000166833
|
||||
contents = length 523, hash 3020DF50
|
||||
input buffer #7:
|
||||
timeUs = 1000000333666
|
||||
contents = length 6061, hash 736C72B2
|
||||
input buffer #8:
|
||||
timeUs = 1000000266933
|
||||
contents = length 992, hash FE132F23
|
||||
input buffer #9:
|
||||
timeUs = 1000000233566
|
||||
contents = length 623, hash 5B2C1816
|
||||
input buffer #10:
|
||||
timeUs = 1000000300300
|
||||
contents = length 421, hash 742E69C1
|
||||
input buffer #11:
|
||||
timeUs = 1000000433766
|
||||
contents = length 4899, hash F72F86A1
|
||||
input buffer #12:
|
||||
timeUs = 1000000400400
|
||||
contents = length 568, hash 519A8E50
|
||||
input buffer #13:
|
||||
timeUs = 1000000367033
|
||||
contents = length 620, hash 3990AA39
|
||||
input buffer #14:
|
||||
timeUs = 0
|
||||
flags = 4
|
||||
contents = length 0, hash 1
|
||||
input buffer #15:
|
||||
timeUs = 1000000000000
|
||||
contents = length 36692, hash D216076E
|
||||
input buffer #16:
|
||||
timeUs = 1000000066733
|
||||
contents = length 5312, hash D45D3CA0
|
||||
input buffer #17:
|
||||
timeUs = 1000000033366
|
||||
contents = length 599, hash 1BE7812D
|
||||
input buffer #18:
|
||||
timeUs = 1000000200200
|
||||
contents = length 7735, hash 4490F110
|
||||
input buffer #19:
|
||||
timeUs = 1000000133466
|
||||
contents = length 987, hash 560B5036
|
||||
input buffer #20:
|
||||
timeUs = 1000000100100
|
||||
contents = length 673, hash ED7CD8C7
|
||||
input buffer #21:
|
||||
timeUs = 1000000166833
|
||||
contents = length 523, hash 3020DF50
|
||||
input buffer #22:
|
||||
timeUs = 1000000333666
|
||||
contents = length 6061, hash 736C72B2
|
||||
input buffer #23:
|
||||
timeUs = 1000000266933
|
||||
contents = length 992, hash FE132F23
|
||||
input buffer #24:
|
||||
timeUs = 1000000233566
|
||||
contents = length 623, hash 5B2C1816
|
||||
input buffer #25:
|
||||
timeUs = 1000000300300
|
||||
contents = length 421, hash 742E69C1
|
||||
input buffer #26:
|
||||
timeUs = 1000000433766
|
||||
contents = length 4899, hash F72F86A1
|
||||
input buffer #27:
|
||||
timeUs = 1000000400400
|
||||
contents = length 568, hash 519A8E50
|
||||
input buffer #28:
|
||||
timeUs = 1000000367033
|
||||
contents = length 620, hash 3990AA39
|
||||
input buffer #29:
|
||||
timeUs = 1000000567233
|
||||
contents = length 5450, hash F06EC4AA
|
||||
input buffer #30:
|
||||
timeUs = 1000000500500
|
||||
contents = length 1051, hash 92DFA63A
|
||||
input buffer #31:
|
||||
timeUs = 1000000467133
|
||||
contents = length 874, hash 69587FB4
|
||||
input buffer #32:
|
||||
timeUs = 1000000533866
|
||||
contents = length 781, hash 36BE495B
|
||||
input buffer #33:
|
||||
timeUs = 1000000700700
|
||||
contents = length 4725, hash AC0C8CD3
|
||||
input buffer #34:
|
||||
timeUs = 1000000633966
|
||||
contents = length 1022, hash 5D8BFF34
|
||||
input buffer #35:
|
||||
timeUs = 1000000600600
|
||||
contents = length 790, hash 99413A99
|
||||
input buffer #36:
|
||||
timeUs = 1000000667333
|
||||
contents = length 610, hash 5E129290
|
||||
input buffer #37:
|
||||
timeUs = 1000000834166
|
||||
contents = length 2751, hash 769974CB
|
||||
input buffer #38:
|
||||
timeUs = 1000000767433
|
||||
contents = length 745, hash B78A477A
|
||||
input buffer #39:
|
||||
timeUs = 1000000734066
|
||||
contents = length 621, hash CF741E7A
|
||||
input buffer #40:
|
||||
timeUs = 1000000800800
|
||||
contents = length 505, hash 1DB4894E
|
||||
input buffer #41:
|
||||
timeUs = 1000000967633
|
||||
contents = length 1268, hash C15348DC
|
||||
input buffer #42:
|
||||
timeUs = 1000000900900
|
||||
contents = length 880, hash C2DE85D0
|
||||
input buffer #43:
|
||||
timeUs = 1000000867533
|
||||
contents = length 530, hash C98BC6A8
|
||||
input buffer #44:
|
||||
timeUs = 1000000934266
|
||||
contents = length 568, hash 4FE5C8EA
|
||||
input buffer #45:
|
||||
timeUs = 0
|
||||
flags = 4
|
||||
contents = length 0, hash 1
|
||||
outputBuffers:
|
||||
count = 44
|
||||
output buffer #0:
|
||||
timeUs = 1000000000000
|
||||
size = 36692
|
||||
rendered = true
|
||||
output buffer #1:
|
||||
timeUs = 1000000066733
|
||||
size = 5312
|
||||
rendered = true
|
||||
output buffer #2:
|
||||
timeUs = 1000000033366
|
||||
size = 599
|
||||
rendered = true
|
||||
output buffer #3:
|
||||
timeUs = 1000000200200
|
||||
size = 7735
|
||||
rendered = true
|
||||
output buffer #4:
|
||||
timeUs = 1000000133466
|
||||
size = 987
|
||||
rendered = true
|
||||
output buffer #5:
|
||||
timeUs = 1000000100100
|
||||
size = 673
|
||||
rendered = true
|
||||
output buffer #6:
|
||||
timeUs = 1000000166833
|
||||
size = 523
|
||||
rendered = true
|
||||
output buffer #7:
|
||||
timeUs = 1000000333666
|
||||
size = 6061
|
||||
rendered = true
|
||||
output buffer #8:
|
||||
timeUs = 1000000266933
|
||||
size = 992
|
||||
rendered = true
|
||||
output buffer #9:
|
||||
timeUs = 1000000233566
|
||||
size = 623
|
||||
rendered = true
|
||||
output buffer #10:
|
||||
timeUs = 1000000300300
|
||||
size = 421
|
||||
rendered = true
|
||||
output buffer #11:
|
||||
timeUs = 1000000433766
|
||||
size = 4899
|
||||
rendered = true
|
||||
output buffer #12:
|
||||
timeUs = 1000000400400
|
||||
size = 568
|
||||
rendered = true
|
||||
output buffer #13:
|
||||
timeUs = 1000000367033
|
||||
size = 620
|
||||
rendered = true
|
||||
output buffer #14:
|
||||
timeUs = 1000000000000
|
||||
size = 36692
|
||||
rendered = false
|
||||
output buffer #15:
|
||||
timeUs = 1000000066733
|
||||
size = 5312
|
||||
rendered = false
|
||||
output buffer #16:
|
||||
timeUs = 1000000033366
|
||||
size = 599
|
||||
rendered = false
|
||||
output buffer #17:
|
||||
timeUs = 1000000200200
|
||||
size = 7735
|
||||
rendered = false
|
||||
output buffer #18:
|
||||
timeUs = 1000000133466
|
||||
size = 987
|
||||
rendered = false
|
||||
output buffer #19:
|
||||
timeUs = 1000000100100
|
||||
size = 673
|
||||
rendered = false
|
||||
output buffer #20:
|
||||
timeUs = 1000000166833
|
||||
size = 523
|
||||
rendered = false
|
||||
output buffer #21:
|
||||
timeUs = 1000000333666
|
||||
size = 6061
|
||||
rendered = false
|
||||
output buffer #22:
|
||||
timeUs = 1000000266933
|
||||
size = 992
|
||||
rendered = false
|
||||
output buffer #23:
|
||||
timeUs = 1000000233566
|
||||
size = 623
|
||||
rendered = false
|
||||
output buffer #24:
|
||||
timeUs = 1000000300300
|
||||
size = 421
|
||||
rendered = false
|
||||
output buffer #25:
|
||||
timeUs = 1000000433766
|
||||
size = 4899
|
||||
rendered = false
|
||||
output buffer #26:
|
||||
timeUs = 1000000400400
|
||||
size = 568
|
||||
rendered = false
|
||||
output buffer #27:
|
||||
timeUs = 1000000367033
|
||||
size = 620
|
||||
rendered = false
|
||||
output buffer #28:
|
||||
timeUs = 1000000567233
|
||||
size = 5450
|
||||
rendered = true
|
||||
output buffer #29:
|
||||
timeUs = 1000000500500
|
||||
size = 1051
|
||||
rendered = true
|
||||
output buffer #30:
|
||||
timeUs = 1000000467133
|
||||
size = 874
|
||||
rendered = false
|
||||
output buffer #31:
|
||||
timeUs = 1000000533866
|
||||
size = 781
|
||||
rendered = true
|
||||
output buffer #32:
|
||||
timeUs = 1000000700700
|
||||
size = 4725
|
||||
rendered = true
|
||||
output buffer #33:
|
||||
timeUs = 1000000633966
|
||||
size = 1022
|
||||
rendered = true
|
||||
output buffer #34:
|
||||
timeUs = 1000000600600
|
||||
size = 790
|
||||
rendered = true
|
||||
output buffer #35:
|
||||
timeUs = 1000000667333
|
||||
size = 610
|
||||
rendered = true
|
||||
output buffer #36:
|
||||
timeUs = 1000000834166
|
||||
size = 2751
|
||||
rendered = true
|
||||
output buffer #37:
|
||||
timeUs = 1000000767433
|
||||
size = 745
|
||||
rendered = true
|
||||
output buffer #38:
|
||||
timeUs = 1000000734066
|
||||
size = 621
|
||||
rendered = true
|
||||
output buffer #39:
|
||||
timeUs = 1000000800800
|
||||
size = 505
|
||||
rendered = true
|
||||
output buffer #40:
|
||||
timeUs = 1000000967633
|
||||
size = 1268
|
||||
rendered = true
|
||||
output buffer #41:
|
||||
timeUs = 1000000900900
|
||||
size = 880
|
||||
rendered = true
|
||||
output buffer #42:
|
||||
timeUs = 1000000867533
|
||||
size = 530
|
||||
rendered = true
|
||||
output buffer #43:
|
||||
timeUs = 1000000934266
|
||||
size = 568
|
||||
rendered = true
|
@ -187,7 +187,8 @@ public class FakeAdaptiveMediaPeriod
|
||||
DrmSessionManager.DRM_UNSUPPORTED,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
new DefaultLoadErrorHandlingPolicy(/* minimumLoadableRetryCount= */ 3),
|
||||
mediaSourceEventDispatcher);
|
||||
mediaSourceEventDispatcher,
|
||||
/* canReportInitialDiscontinuity= */ false);
|
||||
streams[i] = sampleStream;
|
||||
sampleStreams.add(sampleStream);
|
||||
streamResetFlags[i] = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user