Commit 3f5dbf2e by bachinger Committed by Ian Baker

Add flag to SinglePeriodTimeline to suppress projection

Issue: #9037
#minor-release
PiperOrigin-RevId: 385630065
parent 40993f4f
...@@ -138,6 +138,9 @@ ...@@ -138,6 +138,9 @@
([#9004](https://github.com/google/ExoPlayer/issues/9004)). ([#9004](https://github.com/google/ExoPlayer/issues/9004)).
* Forward the `FRAME-RATE` value from the master playlist to renditions. * Forward the `FRAME-RATE` value from the master playlist to renditions.
([#8960](https://github.com/google/ExoPlayer/issues/8960)). ([#8960](https://github.com/google/ExoPlayer/issues/8960)).
* Fix issue where HLS events would start at positions greater than
specified by an `EXT-X-START` tag when placed in a playlist
([#9037](https://github.com/google/ExoPlayer/issues/9037)).
* Ad playback: * Ad playback:
* Support changing ad break positions in the player logic * Support changing ad break positions in the player logic
([#5067](https://github.com/google/ExoPlayer/issues/5067). ([#5067](https://github.com/google/ExoPlayer/issues/5067).
......
...@@ -40,6 +40,7 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -40,6 +40,7 @@ public final class SinglePeriodTimeline extends Timeline {
private final long windowDefaultStartPositionUs; private final long windowDefaultStartPositionUs;
private final boolean isSeekable; private final boolean isSeekable;
private final boolean isDynamic; private final boolean isDynamic;
private final boolean suppressPositionProjection;
@Nullable private final Object manifest; @Nullable private final Object manifest;
@Nullable private final MediaItem mediaItem; @Nullable private final MediaItem mediaItem;
@Nullable private final MediaItem.LiveConfiguration liveConfiguration; @Nullable private final MediaItem.LiveConfiguration liveConfiguration;
...@@ -169,6 +170,7 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -169,6 +170,7 @@ public final class SinglePeriodTimeline extends Timeline {
windowDefaultStartPositionUs, windowDefaultStartPositionUs,
isSeekable, isSeekable,
isDynamic, isDynamic,
/* suppressPositionProjection= */ false,
manifest, manifest,
mediaItem, mediaItem,
useLiveConfiguration ? mediaItem.liveConfiguration : null); useLiveConfiguration ? mediaItem.liveConfiguration : null);
...@@ -176,7 +178,7 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -176,7 +178,7 @@ public final class SinglePeriodTimeline extends Timeline {
/** /**
* @deprecated Use {@link #SinglePeriodTimeline(long, long, long, long, long, long, long, boolean, * @deprecated Use {@link #SinglePeriodTimeline(long, long, long, long, long, long, long, boolean,
* boolean, Object, MediaItem, MediaItem.LiveConfiguration)} instead. * boolean, boolean, Object, MediaItem, MediaItem.LiveConfiguration)} instead.
*/ */
@Deprecated @Deprecated
public SinglePeriodTimeline( public SinglePeriodTimeline(
...@@ -202,12 +204,47 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -202,12 +204,47 @@ public final class SinglePeriodTimeline extends Timeline {
windowDefaultStartPositionUs, windowDefaultStartPositionUs,
isSeekable, isSeekable,
isDynamic, isDynamic,
/* suppressPositionProjection= */ false,
manifest, manifest,
MEDIA_ITEM.buildUpon().setTag(tag).build(), MEDIA_ITEM.buildUpon().setTag(tag).build(),
isLive ? MEDIA_ITEM.liveConfiguration : null); isLive ? MEDIA_ITEM.liveConfiguration : null);
} }
/** /**
* @deprecated Use {@link #SinglePeriodTimeline(long, long, long, long, long, long, long, boolean,
* boolean, boolean, Object, MediaItem, MediaItem.LiveConfiguration)} instead.
*/
@Deprecated
public SinglePeriodTimeline(
long presentationStartTimeMs,
long windowStartTimeMs,
long elapsedRealtimeEpochOffsetMs,
long periodDurationUs,
long windowDurationUs,
long windowPositionInPeriodUs,
long windowDefaultStartPositionUs,
boolean isSeekable,
boolean isDynamic,
@Nullable Object manifest,
MediaItem mediaItem,
@Nullable MediaItem.LiveConfiguration liveConfiguration) {
this(
presentationStartTimeMs,
windowStartTimeMs,
elapsedRealtimeEpochOffsetMs,
periodDurationUs,
windowDurationUs,
windowPositionInPeriodUs,
windowDefaultStartPositionUs,
isSeekable,
isDynamic,
/* suppressPositionProjection= */ false,
manifest,
mediaItem,
liveConfiguration);
}
/**
* Creates a timeline with one period, and a window of known duration starting at a specified * Creates a timeline with one period, and a window of known duration starting at a specified
* position in the period. * position in the period.
* *
...@@ -226,6 +263,9 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -226,6 +263,9 @@ public final class SinglePeriodTimeline extends Timeline {
* which to begin playback, in microseconds. * which to begin playback, in microseconds.
* @param isSeekable Whether seeking is supported within the window. * @param isSeekable Whether seeking is supported within the window.
* @param isDynamic Whether the window may change when the timeline is updated. * @param isDynamic Whether the window may change when the timeline is updated.
* @param suppressPositionProjection Whether {@link #getWindow(int, Window, long) position
* projection} in a playlist should be suppressed. This only applies for dynamic timelines and
* is ignored otherwise.
* @param manifest The manifest. May be {@code null}. * @param manifest The manifest. May be {@code null}.
* @param mediaItem A media item used for {@link Timeline.Window#mediaItem}. * @param mediaItem A media item used for {@link Timeline.Window#mediaItem}.
* @param liveConfiguration The configuration for live playback behaviour, or {@code null} if the * @param liveConfiguration The configuration for live playback behaviour, or {@code null} if the
...@@ -241,6 +281,7 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -241,6 +281,7 @@ public final class SinglePeriodTimeline extends Timeline {
long windowDefaultStartPositionUs, long windowDefaultStartPositionUs,
boolean isSeekable, boolean isSeekable,
boolean isDynamic, boolean isDynamic,
boolean suppressPositionProjection,
@Nullable Object manifest, @Nullable Object manifest,
MediaItem mediaItem, MediaItem mediaItem,
@Nullable MediaItem.LiveConfiguration liveConfiguration) { @Nullable MediaItem.LiveConfiguration liveConfiguration) {
...@@ -253,6 +294,7 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -253,6 +294,7 @@ public final class SinglePeriodTimeline extends Timeline {
this.windowDefaultStartPositionUs = windowDefaultStartPositionUs; this.windowDefaultStartPositionUs = windowDefaultStartPositionUs;
this.isSeekable = isSeekable; this.isSeekable = isSeekable;
this.isDynamic = isDynamic; this.isDynamic = isDynamic;
this.suppressPositionProjection = suppressPositionProjection;
this.manifest = manifest; this.manifest = manifest;
this.mediaItem = checkNotNull(mediaItem); this.mediaItem = checkNotNull(mediaItem);
this.liveConfiguration = liveConfiguration; this.liveConfiguration = liveConfiguration;
...@@ -268,7 +310,7 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -268,7 +310,7 @@ public final class SinglePeriodTimeline extends Timeline {
public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) { public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {
Assertions.checkIndex(windowIndex, 0, 1); Assertions.checkIndex(windowIndex, 0, 1);
long windowDefaultStartPositionUs = this.windowDefaultStartPositionUs; long windowDefaultStartPositionUs = this.windowDefaultStartPositionUs;
if (isDynamic && defaultPositionProjectionUs != 0) { if (isDynamic && !suppressPositionProjection && defaultPositionProjectionUs != 0) {
if (windowDurationUs == C.TIME_UNSET) { if (windowDurationUs == C.TIME_UNSET) {
// Don't allow projection into a window that has an unknown duration. // Don't allow projection into a window that has an unknown duration.
windowDefaultStartPositionUs = C.TIME_UNSET; windowDefaultStartPositionUs = C.TIME_UNSET;
......
...@@ -9428,6 +9428,7 @@ public final class ExoPlayerTest { ...@@ -9428,6 +9428,7 @@ public final class ExoPlayerTest {
/* windowDefaultStartPositionUs= */ 0, /* windowDefaultStartPositionUs= */ 0,
/* isSeekable= */ true, /* isSeekable= */ true,
/* isDynamic= */ true, /* isDynamic= */ true,
/* suppressPositionProjection= */ false,
/* manifest= */ null, /* manifest= */ null,
mediaItem, mediaItem,
mediaItem.liveConfiguration); mediaItem.liveConfiguration);
......
...@@ -548,6 +548,9 @@ public final class HlsMediaSource extends BaseMediaSource ...@@ -548,6 +548,9 @@ public final class HlsMediaSource extends BaseMediaSource
maybeUpdateLiveConfiguration(targetLiveOffsetUs); maybeUpdateLiveConfiguration(targetLiveOffsetUs);
long windowDefaultStartPositionUs = long windowDefaultStartPositionUs =
getLiveWindowDefaultStartPositionUs(playlist, liveEdgeOffsetUs); getLiveWindowDefaultStartPositionUs(playlist, liveEdgeOffsetUs);
boolean suppressPositionProjection =
playlist.playlistType == HlsMediaPlaylist.PLAYLIST_TYPE_EVENT
&& playlist.hasPositiveStartOffset;
return new SinglePeriodTimeline( return new SinglePeriodTimeline(
presentationStartTimeMs, presentationStartTimeMs,
windowStartTimeMs, windowStartTimeMs,
...@@ -558,6 +561,7 @@ public final class HlsMediaSource extends BaseMediaSource ...@@ -558,6 +561,7 @@ public final class HlsMediaSource extends BaseMediaSource
windowDefaultStartPositionUs, windowDefaultStartPositionUs,
/* isSeekable= */ true, /* isSeekable= */ true,
/* isDynamic= */ !playlist.hasEndTag, /* isDynamic= */ !playlist.hasEndTag,
suppressPositionProjection,
manifest, manifest,
mediaItem, mediaItem,
liveConfiguration); liveConfiguration);
...@@ -590,6 +594,7 @@ public final class HlsMediaSource extends BaseMediaSource ...@@ -590,6 +594,7 @@ public final class HlsMediaSource extends BaseMediaSource
windowDefaultStartPositionUs, windowDefaultStartPositionUs,
/* isSeekable= */ true, /* isSeekable= */ true,
/* isDynamic= */ false, /* isDynamic= */ false,
/* suppressPositionProjection= */ true,
manifest, manifest,
mediaItem, mediaItem,
/* liveConfiguration= */ null); /* liveConfiguration= */ null);
......
...@@ -400,6 +400,11 @@ public final class HlsMediaPlaylist extends HlsPlaylist { ...@@ -400,6 +400,11 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* {@link #durationUs}, inclusive. * {@link #durationUs}, inclusive.
*/ */
public final long startOffsetUs; public final long startOffsetUs;
/**
* Whether the {@link #startOffsetUs} was explicitly defined by #EXT-X-START as a positive value
* or zero.
*/
public final boolean hasPositiveStartOffset;
/** Whether the start position should be precise, as defined by #EXT-X-START. */ /** Whether the start position should be precise, as defined by #EXT-X-START. */
public final boolean preciseStart; public final boolean preciseStart;
/** /**
...@@ -526,6 +531,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { ...@@ -526,6 +531,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
: startOffsetUs >= 0 : startOffsetUs >= 0
? min(durationUs, startOffsetUs) ? min(durationUs, startOffsetUs)
: max(0, durationUs + startOffsetUs); : max(0, durationUs + startOffsetUs);
this.hasPositiveStartOffset = startOffsetUs >= 0;
this.serverControl = serverControl; this.serverControl = serverControl;
} }
......
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