mirror of
https://github.com/samsonjs/media.git
synced 2026-03-25 09:25:53 +00:00
Merge pull request #528 from zgzong:patch-2
PiperOrigin-RevId: 554869426
(cherry picked from commit ef54364478)
This commit is contained in:
parent
57c73d51da
commit
294fa261b7
4 changed files with 152 additions and 1 deletions
|
|
@ -410,7 +410,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||
}
|
||||
|
||||
long periodDurationUs = representationHolder.periodDurationUs;
|
||||
boolean periodEnded = periodDurationUs != C.TIME_UNSET;
|
||||
boolean isLastPeriodInDynamicManifest =
|
||||
manifest.dynamic && periodIndex == manifest.getPeriodCount() - 1;
|
||||
boolean periodEnded = !isLastPeriodInDynamicManifest || periodDurationUs != C.TIME_UNSET;
|
||||
|
||||
if (representationHolder.getSegmentCount() == 0) {
|
||||
// The index doesn't define any segments.
|
||||
|
|
@ -420,6 +422,16 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||
|
||||
long firstAvailableSegmentNum = representationHolder.getFirstAvailableSegmentNum(nowUnixTimeUs);
|
||||
long lastAvailableSegmentNum = representationHolder.getLastAvailableSegmentNum(nowUnixTimeUs);
|
||||
if (isLastPeriodInDynamicManifest) {
|
||||
long lastAvailableSegmentEndTimeUs =
|
||||
representationHolder.getSegmentEndTimeUs(lastAvailableSegmentNum);
|
||||
long lastSegmentDurationUs =
|
||||
lastAvailableSegmentEndTimeUs
|
||||
- representationHolder.getSegmentStartTimeUs(lastAvailableSegmentNum);
|
||||
// Account for some inaccuracy in the overall period duration value by assuming that the
|
||||
// period is finished once no further full sample fits into the overall duration.
|
||||
periodEnded &= (lastAvailableSegmentEndTimeUs + lastSegmentDurationUs >= periodDurationUs);
|
||||
}
|
||||
long segmentNum =
|
||||
getSegmentNum(
|
||||
representationHolder,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import androidx.media3.exoplayer.source.MediaLoadData;
|
|||
import androidx.media3.exoplayer.source.chunk.BundledChunkExtractor;
|
||||
import androidx.media3.exoplayer.source.chunk.Chunk;
|
||||
import androidx.media3.exoplayer.source.chunk.ChunkHolder;
|
||||
import androidx.media3.exoplayer.source.chunk.MediaChunk;
|
||||
import androidx.media3.exoplayer.trackselection.AdaptiveTrackSelection;
|
||||
import androidx.media3.exoplayer.trackselection.FixedTrackSelection;
|
||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||
|
|
@ -414,6 +415,104 @@ public class DefaultDashChunkSourceTest {
|
|||
"key4=5.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getNextChunk_afterLastAvailableButBeforeEndOfLiveManifestWithKnownDuration_doesNotReturnEndOfStream()
|
||||
throws Exception {
|
||||
DashManifest manifest =
|
||||
new DashManifestParser()
|
||||
.parse(
|
||||
Uri.parse("https://example.com/test.mpd"),
|
||||
TestUtil.getInputStream(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"media/mpd/sample_mpd_live_known_duration_not_ended"));
|
||||
DefaultDashChunkSource chunkSource =
|
||||
new DefaultDashChunkSource(
|
||||
BundledChunkExtractor.FACTORY,
|
||||
new LoaderErrorThrower.Placeholder(),
|
||||
manifest,
|
||||
new BaseUrlExclusionList(),
|
||||
/* periodIndex= */ 0,
|
||||
/* adaptationSetIndices= */ new int[] {0},
|
||||
new FixedTrackSelection(new TrackGroup(new Format.Builder().build()), /* track= */ 0),
|
||||
C.TRACK_TYPE_VIDEO,
|
||||
new FakeDataSource(),
|
||||
/* elapsedRealtimeOffsetMs= */ 0,
|
||||
/* maxSegmentsPerLoad= */ 1,
|
||||
/* enableEventMessageTrack= */ false,
|
||||
/* closedCaptionFormats= */ ImmutableList.of(),
|
||||
/* playerTrackEmsgHandler= */ null,
|
||||
PlayerId.UNSET,
|
||||
/* cmcdConfiguration= */ null);
|
||||
ChunkHolder output = new ChunkHolder();
|
||||
// Populate with last available media chunk
|
||||
chunkSource.getNextChunk(
|
||||
/* playbackPositionUs= */ 0,
|
||||
/* loadPositionUs= */ 0,
|
||||
/* queue= */ ImmutableList.of(),
|
||||
output);
|
||||
Chunk previousChunk = output.chunk;
|
||||
output.clear();
|
||||
|
||||
// Request another chunk
|
||||
chunkSource.getNextChunk(
|
||||
/* playbackPositionUs= */ 0,
|
||||
/* loadPositionUs= */ 4_000_000,
|
||||
/* queue= */ ImmutableList.of((MediaChunk) previousChunk),
|
||||
output);
|
||||
|
||||
assertThat(output.endOfStream).isFalse();
|
||||
assertThat(output.chunk).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNextChunk_atEndOfLiveManifestWithKnownDuration_returnsEndOfStream()
|
||||
throws Exception {
|
||||
DashManifest manifest =
|
||||
new DashManifestParser()
|
||||
.parse(
|
||||
Uri.parse("https://example.com/test.mpd"),
|
||||
TestUtil.getInputStream(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"media/mpd/sample_mpd_live_known_duration_ended"));
|
||||
DefaultDashChunkSource chunkSource =
|
||||
new DefaultDashChunkSource(
|
||||
BundledChunkExtractor.FACTORY,
|
||||
new LoaderErrorThrower.Placeholder(),
|
||||
manifest,
|
||||
new BaseUrlExclusionList(),
|
||||
/* periodIndex= */ 0,
|
||||
/* adaptationSetIndices= */ new int[] {0},
|
||||
new FixedTrackSelection(new TrackGroup(new Format.Builder().build()), /* track= */ 0),
|
||||
C.TRACK_TYPE_VIDEO,
|
||||
new FakeDataSource(),
|
||||
/* elapsedRealtimeOffsetMs= */ 0,
|
||||
/* maxSegmentsPerLoad= */ 1,
|
||||
/* enableEventMessageTrack= */ false,
|
||||
/* closedCaptionFormats= */ ImmutableList.of(),
|
||||
/* playerTrackEmsgHandler= */ null,
|
||||
PlayerId.UNSET,
|
||||
/* cmcdConfiguration= */ null);
|
||||
ChunkHolder output = new ChunkHolder();
|
||||
// Populate with last media chunk
|
||||
chunkSource.getNextChunk(
|
||||
/* playbackPositionUs= */ 0,
|
||||
/* loadPositionUs= */ 4_000_000,
|
||||
/* queue= */ ImmutableList.of(),
|
||||
output);
|
||||
Chunk previousChunk = output.chunk;
|
||||
output.clear();
|
||||
|
||||
// Request next chunk
|
||||
chunkSource.getNextChunk(
|
||||
/* playbackPositionUs= */ 0,
|
||||
/* loadPositionUs= */ 8_000_000,
|
||||
/* queue= */ ImmutableList.of((MediaChunk) previousChunk),
|
||||
output);
|
||||
|
||||
assertThat(output.endOfStream).isTrue();
|
||||
}
|
||||
|
||||
private DashChunkSource createDashChunkSource(
|
||||
int numberOfTracks, @Nullable CmcdConfiguration cmcdConfiguration) throws IOException {
|
||||
Assertions.checkArgument(numberOfTracks < 6);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD
|
||||
type="dynamic"
|
||||
timeShiftBufferDepth="PT16S"
|
||||
minimumUpdatePeriod="PT4M"
|
||||
availabilityStartTime="2024-01-01T00:01:00Z">
|
||||
<UTCTiming
|
||||
schemeIdUri="urn:mpeg:dash:utc:direct:2014"
|
||||
value="2024-01-01T00:01:00Z" />
|
||||
<Period id="1" start="PT0S" duration="PT10S">
|
||||
<AdaptationSet id="0" contentType="video">
|
||||
<SegmentTemplate presentationTimeOffset="0" timescale="1000" startNumber="1" media="video_$Time$.m4s">
|
||||
<SegmentTimeline>
|
||||
<S t="0" d="4000" r="1"/>
|
||||
</SegmentTimeline>
|
||||
</SegmentTemplate>
|
||||
<Representation id="0"/>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD
|
||||
type="dynamic"
|
||||
timeShiftBufferDepth="PT16S"
|
||||
minimumUpdatePeriod="PT4M"
|
||||
availabilityStartTime="2024-01-01T00:01:00Z">
|
||||
<UTCTiming
|
||||
schemeIdUri="urn:mpeg:dash:utc:direct:2014"
|
||||
value="2024-01-01T00:01:00Z" />
|
||||
<Period id="1" start="PT0S" duration="PT10S">
|
||||
<AdaptationSet id="0" contentType="video">
|
||||
<SegmentTemplate presentationTimeOffset="0" timescale="1000" startNumber="1" media="video_$Time$.m4s">
|
||||
<SegmentTimeline>
|
||||
<S t="0" d="4000"/>
|
||||
</SegmentTimeline>
|
||||
</SegmentTemplate>
|
||||
<Representation id="0"/>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
||||
Loading…
Reference in a new issue