Skip to content

Commit a9f57d4

Browse files
committed
Fixes early transiton to Player.STATE_ENDED with MPD transition dynamic to static
This checkin fixes Issue #1441 where the player transitons to `Player.STATE_ENDED` once the buffer runs out on a DASH start-over playlist that has transitioned from dynamic to static. The fix detects the DASH Period has changed offset to the window, which occurs when the origin vendor follows the DASH-IF recommendations in *Section 4.6.4. Transition Phase between Live and On-Demand* , summerized as: - adds the attribute `MPD@mediaPresentationDuration` - removes the attribute `MPD@minimumUpdatePeriod` - `Period@start` is removed (if it was present) - `Period@duration` is added (in case more than 1 period is present) - `Adaptationset .SegmentTemplate@presentationTimeOffset` is set to earliest presentation time of a segment in the Adaptationset The MPD change does not affect the render position or the segment timeline at all, however the cleanest way to implement this was to report a `PositionUpdateForPlaylistChange` which triggers a seek and flushes the current buffered content.
1 parent ca51ed6 commit a9f57d4

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java

+21
Original file line numberDiff line numberDiff line change
@@ -3030,6 +3030,11 @@ private static PositionUpdateForPlaylistChange resolvePositionForPlaylistChange(
30303030
}
30313031
}
30323032

3033+
long periodPositionDeltaUs = checkPlayingPeriodPositionChanged(timeline, playbackInfo, period.windowIndex);
3034+
if (periodPositionDeltaUs > 0) {
3035+
periodPositionUs = periodPositionUs - periodPositionDeltaUs;
3036+
}
3037+
30333038
return new PositionUpdateForPlaylistChange(
30343039
newPeriodId,
30353040
periodPositionUs,
@@ -3039,6 +3044,22 @@ private static PositionUpdateForPlaylistChange resolvePositionForPlaylistChange(
30393044
setTargetLiveOffset);
30403045
}
30413046

3047+
private static long checkPlayingPeriodPositionChanged(Timeline timeline, PlaybackInfo playbackInfo, int currentWindowIndex) {
3048+
long periodPositionDeltaUs = C.TIME_UNSET;
3049+
if (!playbackInfo.timeline.isEmpty() && !timeline.isEmpty() && !playbackInfo.periodId.isAd()) {
3050+
Timeline.Window newWindow = timeline.getWindow(currentWindowIndex, new Timeline.Window());
3051+
Timeline.Window oldWindow = playbackInfo.timeline.getWindow(currentWindowIndex, new Timeline.Window());
3052+
if (oldWindow.isDynamic && ! newWindow.isDynamic) {
3053+
Timeline.Period newPeriod = timeline.getPeriodByUid(playbackInfo.periodId.periodUid, new Timeline.Period());
3054+
int windowIndex = newPeriod.windowIndex;
3055+
Pair<Object, Long> oldPositionZero = playbackInfo.timeline.getPeriodPosition(oldWindow, new Timeline.Period(), windowIndex, 0);
3056+
Pair<Object, Long> newPositionZero = timeline.getPeriodPosition(newWindow, new Timeline.Period(), windowIndex, 0);
3057+
periodPositionDeltaUs = oldPositionZero.second - newPositionZero.second;
3058+
}
3059+
}
3060+
return periodPositionDeltaUs;
3061+
}
3062+
30423063
private static boolean isIgnorableServerSideAdInsertionPeriodChange(
30433064
boolean isUsingPlaceholderPeriod,
30443065
MediaPeriodId oldPeriodId,

0 commit comments

Comments
 (0)