Commit a3884d84 by Tianyi Feng

Merge pull request #528 from zgzong:patch-2

PiperOrigin-RevId: 554869426
(cherry picked from commit 7e3547299445cf3b5c2506abb4449bbb9a997130)
parent 7f5c6765
...@@ -416,7 +416,9 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -416,7 +416,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
} }
long periodDurationUs = representationHolder.periodDurationUs; 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) { if (representationHolder.getSegmentCount() == 0) {
// The index doesn't define any segments. // The index doesn't define any segments.
...@@ -426,6 +428,16 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -426,6 +428,16 @@ public class DefaultDashChunkSource implements DashChunkSource {
long firstAvailableSegmentNum = representationHolder.getFirstAvailableSegmentNum(nowUnixTimeUs); long firstAvailableSegmentNum = representationHolder.getFirstAvailableSegmentNum(nowUnixTimeUs);
long lastAvailableSegmentNum = representationHolder.getLastAvailableSegmentNum(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 = long segmentNum =
getSegmentNum( getSegmentNum(
representationHolder, representationHolder,
......
...@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.source.TrackGroup; ...@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor; import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor;
import com.google.android.exoplayer2.source.chunk.Chunk; import com.google.android.exoplayer2.source.chunk.Chunk;
import com.google.android.exoplayer2.source.chunk.ChunkHolder; import com.google.android.exoplayer2.source.chunk.ChunkHolder;
import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest; import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser; import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
import com.google.android.exoplayer2.testutil.FakeDataSource; import com.google.android.exoplayer2.testutil.FakeDataSource;
...@@ -414,6 +415,104 @@ public class DefaultDashChunkSourceTest { ...@@ -414,6 +415,104 @@ public class DefaultDashChunkSourceTest {
"key4=5.0"); "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( private DashChunkSource createDashChunkSource(
int numberOfTracks, @Nullable CmcdConfiguration cmcdConfiguration) throws IOException { int numberOfTracks, @Nullable CmcdConfiguration cmcdConfiguration) throws IOException {
Assertions.checkArgument(numberOfTracks < 6); Assertions.checkArgument(numberOfTracks < 6);
......
<?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>
<?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>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment