mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Add Timeline.Window.isLive
This flag is currently merged into Window.isDynamic, which isn't always true because 1. A window can be dynamic for other reasons (e.g. when the duration is still missing). 2. A live stream can be become non-dynamic when it ends. Issue:#2668 Issue:#5973 PiperOrigin-RevId: 271999378
This commit is contained in:
parent
26dd4aad68
commit
dd4f9bcaae
17 changed files with 138 additions and 41 deletions
|
|
@ -80,6 +80,9 @@
|
||||||
and move it to the core library.
|
and move it to the core library.
|
||||||
* Move `LibvpxVideoRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER` to
|
* Move `LibvpxVideoRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER` to
|
||||||
`C.MSG_SET_OUTPUT_BUFFER_RENDERER`.
|
`C.MSG_SET_OUTPUT_BUFFER_RENDERER`.
|
||||||
|
* Add `Timeline.Window.isLive` to indicate that a window is a live stream
|
||||||
|
([#2668](https://github.com/google/ExoPlayer/issues/2668) and
|
||||||
|
[#5973](https://github.com/google/ExoPlayer/issues/5973)).
|
||||||
|
|
||||||
### 2.10.5 (2019-09-20) ###
|
### 2.10.5 (2019-09-20) ###
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ import java.util.Arrays;
|
||||||
/* windowStartTimeMs= */ C.TIME_UNSET,
|
/* windowStartTimeMs= */ C.TIME_UNSET,
|
||||||
/* isSeekable= */ !isDynamic,
|
/* isSeekable= */ !isDynamic,
|
||||||
isDynamic,
|
isDynamic,
|
||||||
|
/* isLive= */ isDynamic,
|
||||||
defaultPositionsUs[windowIndex],
|
defaultPositionsUs[windowIndex],
|
||||||
durationUs,
|
durationUs,
|
||||||
/* firstPeriodIndex= */ windowIndex,
|
/* firstPeriodIndex= */ windowIndex,
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ public class ImaAdsLoaderTest {
|
||||||
|
|
||||||
private static final long CONTENT_DURATION_US = 10 * C.MICROS_PER_SECOND;
|
private static final long CONTENT_DURATION_US = 10 * C.MICROS_PER_SECOND;
|
||||||
private static final Timeline CONTENT_TIMELINE =
|
private static final Timeline CONTENT_TIMELINE =
|
||||||
new SinglePeriodTimeline(CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false);
|
new SinglePeriodTimeline(
|
||||||
|
CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false, /* isLive= */ false);
|
||||||
private static final Uri TEST_URI = Uri.EMPTY;
|
private static final Uri TEST_URI = Uri.EMPTY;
|
||||||
private static final long TEST_AD_DURATION_US = 5 * C.MICROS_PER_SECOND;
|
private static final long TEST_AD_DURATION_US = 5 * C.MICROS_PER_SECOND;
|
||||||
private static final long[][] PREROLL_ADS_DURATIONS_US = new long[][] {{TEST_AD_DURATION_US}};
|
private static final long[][] PREROLL_ADS_DURATIONS_US = new long[][] {{TEST_AD_DURATION_US}};
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,9 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||||
* duration is unknown, since it's continually extending as more content is broadcast. If content
|
* duration is unknown, since it's continually extending as more content is broadcast. If content
|
||||||
* only remains available for a limited period of time then the window may start at a non-zero
|
* only remains available for a limited period of time then the window may start at a non-zero
|
||||||
* position, defining the region of content that can still be played. The window will have {@link
|
* position, defining the region of content that can still be played. The window will have {@link
|
||||||
* Window#isDynamic} set to true if the stream is still live. Its default position is typically near
|
* Window#isLive} set to true to indicate it's a live stream and {@link Window#isDynamic} set to
|
||||||
* to the live edge (indicated by the black dot in the figure above).
|
* true as long as we expect changes to the live window. Its default position is typically near to
|
||||||
|
* the live edge (indicated by the black dot in the figure above).
|
||||||
*
|
*
|
||||||
* <h3>Live stream with indefinite availability</h3>
|
* <h3>Live stream with indefinite availability</h3>
|
||||||
*
|
*
|
||||||
|
|
@ -158,8 +159,13 @@ public abstract class Timeline {
|
||||||
public boolean isDynamic;
|
public boolean isDynamic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The index of the first period that belongs to this window.
|
* Whether the media in this window is live. For informational purposes only.
|
||||||
|
*
|
||||||
|
* <p>Check {@link #isDynamic} to know whether this window may still change.
|
||||||
*/
|
*/
|
||||||
|
public boolean isLive;
|
||||||
|
|
||||||
|
/** The index of the first period that belongs to this window. */
|
||||||
public int firstPeriodIndex;
|
public int firstPeriodIndex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -200,6 +206,7 @@ public abstract class Timeline {
|
||||||
long windowStartTimeMs,
|
long windowStartTimeMs,
|
||||||
boolean isSeekable,
|
boolean isSeekable,
|
||||||
boolean isDynamic,
|
boolean isDynamic,
|
||||||
|
boolean isLive,
|
||||||
long defaultPositionUs,
|
long defaultPositionUs,
|
||||||
long durationUs,
|
long durationUs,
|
||||||
int firstPeriodIndex,
|
int firstPeriodIndex,
|
||||||
|
|
@ -212,6 +219,7 @@ public abstract class Timeline {
|
||||||
this.windowStartTimeMs = windowStartTimeMs;
|
this.windowStartTimeMs = windowStartTimeMs;
|
||||||
this.isSeekable = isSeekable;
|
this.isSeekable = isSeekable;
|
||||||
this.isDynamic = isDynamic;
|
this.isDynamic = isDynamic;
|
||||||
|
this.isLive = isLive;
|
||||||
this.defaultPositionUs = defaultPositionUs;
|
this.defaultPositionUs = defaultPositionUs;
|
||||||
this.durationUs = durationUs;
|
this.durationUs = durationUs;
|
||||||
this.firstPeriodIndex = firstPeriodIndex;
|
this.firstPeriodIndex = firstPeriodIndex;
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
||||||
/* isSeekable= */ false,
|
/* isSeekable= */ false,
|
||||||
// Dynamic window to indicate pending timeline updates.
|
// Dynamic window to indicate pending timeline updates.
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ false,
|
||||||
/* defaultPositionUs= */ 0,
|
/* defaultPositionUs= */ 0,
|
||||||
/* durationUs= */ C.TIME_UNSET,
|
/* durationUs= */ C.TIME_UNSET,
|
||||||
/* firstPeriodIndex= */ 0,
|
/* firstPeriodIndex= */ 0,
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,14 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
interface Listener {
|
interface Listener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the duration or ability to seek within the period changes.
|
* Called when the duration, the ability to seek within the period, or the categorization as
|
||||||
|
* live stream changes.
|
||||||
*
|
*
|
||||||
* @param durationUs The duration of the period, or {@link C#TIME_UNSET}.
|
* @param durationUs The duration of the period, or {@link C#TIME_UNSET}.
|
||||||
* @param isSeekable Whether the period is seekable.
|
* @param isSeekable Whether the period is seekable.
|
||||||
|
* @param isLive Whether the period is live.
|
||||||
*/
|
*/
|
||||||
void onSourceInfoRefreshed(long durationUs, boolean isSeekable);
|
void onSourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -129,6 +130,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
private int enabledTrackCount;
|
private int enabledTrackCount;
|
||||||
private long durationUs;
|
private long durationUs;
|
||||||
private long length;
|
private long length;
|
||||||
|
private boolean isLive;
|
||||||
|
|
||||||
private long lastSeekPositionUs;
|
private long lastSeekPositionUs;
|
||||||
private long pendingResetPositionUs;
|
private long pendingResetPositionUs;
|
||||||
|
|
@ -551,7 +553,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
|
long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
|
||||||
durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0
|
durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0
|
||||||
: largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US;
|
: largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US;
|
||||||
listener.onSourceInfoRefreshed(durationUs, isSeekable);
|
listener.onSourceInfoRefreshed(durationUs, isSeekable, isLive);
|
||||||
}
|
}
|
||||||
eventDispatcher.loadCompleted(
|
eventDispatcher.loadCompleted(
|
||||||
loadable.dataSpec,
|
loadable.dataSpec,
|
||||||
|
|
@ -740,14 +742,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
}
|
}
|
||||||
trackArray[i] = new TrackGroup(trackFormat);
|
trackArray[i] = new TrackGroup(trackFormat);
|
||||||
}
|
}
|
||||||
dataType =
|
isLive = length == C.LENGTH_UNSET && seekMap.getDurationUs() == C.TIME_UNSET;
|
||||||
length == C.LENGTH_UNSET && seekMap.getDurationUs() == C.TIME_UNSET
|
dataType = isLive ? C.DATA_TYPE_MEDIA_PROGRESSIVE_LIVE : C.DATA_TYPE_MEDIA;
|
||||||
? C.DATA_TYPE_MEDIA_PROGRESSIVE_LIVE
|
|
||||||
: C.DATA_TYPE_MEDIA;
|
|
||||||
preparedState =
|
preparedState =
|
||||||
new PreparedState(seekMap, new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
|
new PreparedState(seekMap, new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
|
||||||
prepared = true;
|
prepared = true;
|
||||||
listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable());
|
listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable(), isLive);
|
||||||
Assertions.checkNotNull(callback).onPrepared(this);
|
Assertions.checkNotNull(callback).onPrepared(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
||||||
|
|
||||||
private long timelineDurationUs;
|
private long timelineDurationUs;
|
||||||
private boolean timelineIsSeekable;
|
private boolean timelineIsSeekable;
|
||||||
|
private boolean timelineIsLive;
|
||||||
@Nullable private TransferListener transferListener;
|
@Nullable private TransferListener transferListener;
|
||||||
|
|
||||||
// TODO: Make private when ExtractorMediaSource is deleted.
|
// TODO: Make private when ExtractorMediaSource is deleted.
|
||||||
|
|
@ -253,7 +254,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
||||||
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
||||||
transferListener = mediaTransferListener;
|
transferListener = mediaTransferListener;
|
||||||
drmSessionManager.prepare();
|
drmSessionManager.prepare();
|
||||||
notifySourceInfoRefreshed(timelineDurationUs, timelineIsSeekable);
|
notifySourceInfoRefreshed(timelineDurationUs, timelineIsSeekable, timelineIsLive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -293,27 +294,32 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
||||||
// ProgressiveMediaPeriod.Listener implementation.
|
// ProgressiveMediaPeriod.Listener implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSourceInfoRefreshed(long durationUs, boolean isSeekable) {
|
public void onSourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive) {
|
||||||
// If we already have the duration from a previous source info refresh, use it.
|
// If we already have the duration from a previous source info refresh, use it.
|
||||||
durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs;
|
durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs;
|
||||||
if (timelineDurationUs == durationUs && timelineIsSeekable == isSeekable) {
|
if (timelineDurationUs == durationUs
|
||||||
|
&& timelineIsSeekable == isSeekable
|
||||||
|
&& timelineIsLive == isLive) {
|
||||||
// Suppress no-op source info changes.
|
// Suppress no-op source info changes.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
notifySourceInfoRefreshed(durationUs, isSeekable);
|
notifySourceInfoRefreshed(durationUs, isSeekable, isLive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private void notifySourceInfoRefreshed(long durationUs, boolean isSeekable) {
|
private void notifySourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive) {
|
||||||
timelineDurationUs = durationUs;
|
timelineDurationUs = durationUs;
|
||||||
timelineIsSeekable = isSeekable;
|
timelineIsSeekable = isSeekable;
|
||||||
// TODO: Make timeline dynamic until its duration is known. This is non-trivial. See b/69703223.
|
timelineIsLive = isLive;
|
||||||
|
// TODO: Split up isDynamic into multiple fields to indicate which values may change. Then
|
||||||
|
// indicate that the duration may change until it's known. See [internal: b/69703223].
|
||||||
refreshSourceInfo(
|
refreshSourceInfo(
|
||||||
new SinglePeriodTimeline(
|
new SinglePeriodTimeline(
|
||||||
timelineDurationUs,
|
timelineDurationUs,
|
||||||
timelineIsSeekable,
|
timelineIsSeekable,
|
||||||
/* isDynamic= */ false,
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ timelineIsLive,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
tag));
|
tag));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@ public final class SilenceMediaSource extends BaseMediaSource {
|
||||||
@Override
|
@Override
|
||||||
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
||||||
refreshSourceInfo(
|
refreshSourceInfo(
|
||||||
new SinglePeriodTimeline(durationUs, /* isSeekable= */ true, /* isDynamic= */ false));
|
new SinglePeriodTimeline(
|
||||||
|
durationUs, /* isSeekable= */ true, /* isDynamic= */ false, /* isLive= */ false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,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 isLive;
|
||||||
@Nullable private final Object tag;
|
@Nullable private final Object tag;
|
||||||
@Nullable private final Object manifest;
|
@Nullable private final Object manifest;
|
||||||
|
|
||||||
|
|
@ -44,9 +45,11 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
* @param durationUs The duration of the period, in microseconds.
|
* @param durationUs The duration of the period, in microseconds.
|
||||||
* @param isSeekable Whether seeking is supported within the period.
|
* @param isSeekable Whether seeking is supported within the period.
|
||||||
* @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 isLive Whether the window is live.
|
||||||
*/
|
*/
|
||||||
public SinglePeriodTimeline(long durationUs, boolean isSeekable, boolean isDynamic) {
|
public SinglePeriodTimeline(
|
||||||
this(durationUs, isSeekable, isDynamic, /* manifest= */ null, /* tag= */ null);
|
long durationUs, boolean isSeekable, boolean isDynamic, boolean isLive) {
|
||||||
|
this(durationUs, isSeekable, isDynamic, isLive, /* manifest= */ null, /* tag= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,6 +58,7 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
* @param durationUs The duration of the period, in microseconds.
|
* @param durationUs The duration of the period, in microseconds.
|
||||||
* @param isSeekable Whether seeking is supported within the period.
|
* @param isSeekable Whether seeking is supported within the period.
|
||||||
* @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 isLive Whether the window is live.
|
||||||
* @param manifest The manifest. May be {@code null}.
|
* @param manifest The manifest. May be {@code null}.
|
||||||
* @param tag A tag used for {@link Window#tag}.
|
* @param tag A tag used for {@link Window#tag}.
|
||||||
*/
|
*/
|
||||||
|
|
@ -62,6 +66,7 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
long durationUs,
|
long durationUs,
|
||||||
boolean isSeekable,
|
boolean isSeekable,
|
||||||
boolean isDynamic,
|
boolean isDynamic,
|
||||||
|
boolean isLive,
|
||||||
@Nullable Object manifest,
|
@Nullable Object manifest,
|
||||||
@Nullable Object tag) {
|
@Nullable Object tag) {
|
||||||
this(
|
this(
|
||||||
|
|
@ -71,6 +76,7 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
/* windowDefaultStartPositionUs= */ 0,
|
/* windowDefaultStartPositionUs= */ 0,
|
||||||
isSeekable,
|
isSeekable,
|
||||||
isDynamic,
|
isDynamic,
|
||||||
|
isLive,
|
||||||
manifest,
|
manifest,
|
||||||
tag);
|
tag);
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +93,7 @@ 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 isLive Whether the window is live.
|
||||||
* @param manifest The manifest. May be (@code null}.
|
* @param manifest The manifest. May be (@code null}.
|
||||||
* @param tag A tag used for {@link Timeline.Window#tag}.
|
* @param tag A tag used for {@link Timeline.Window#tag}.
|
||||||
*/
|
*/
|
||||||
|
|
@ -97,6 +104,7 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
long windowDefaultStartPositionUs,
|
long windowDefaultStartPositionUs,
|
||||||
boolean isSeekable,
|
boolean isSeekable,
|
||||||
boolean isDynamic,
|
boolean isDynamic,
|
||||||
|
boolean isLive,
|
||||||
@Nullable Object manifest,
|
@Nullable Object manifest,
|
||||||
@Nullable Object tag) {
|
@Nullable Object tag) {
|
||||||
this(
|
this(
|
||||||
|
|
@ -108,6 +116,7 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
windowDefaultStartPositionUs,
|
windowDefaultStartPositionUs,
|
||||||
isSeekable,
|
isSeekable,
|
||||||
isDynamic,
|
isDynamic,
|
||||||
|
isLive,
|
||||||
manifest,
|
manifest,
|
||||||
tag);
|
tag);
|
||||||
}
|
}
|
||||||
|
|
@ -127,6 +136,7 @@ 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 isLive Whether the window is live.
|
||||||
* @param manifest The manifest. May be {@code null}.
|
* @param manifest The manifest. May be {@code null}.
|
||||||
* @param tag A tag used for {@link Timeline.Window#tag}.
|
* @param tag A tag used for {@link Timeline.Window#tag}.
|
||||||
*/
|
*/
|
||||||
|
|
@ -139,6 +149,7 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
long windowDefaultStartPositionUs,
|
long windowDefaultStartPositionUs,
|
||||||
boolean isSeekable,
|
boolean isSeekable,
|
||||||
boolean isDynamic,
|
boolean isDynamic,
|
||||||
|
boolean isLive,
|
||||||
@Nullable Object manifest,
|
@Nullable Object manifest,
|
||||||
@Nullable Object tag) {
|
@Nullable Object tag) {
|
||||||
this.presentationStartTimeMs = presentationStartTimeMs;
|
this.presentationStartTimeMs = presentationStartTimeMs;
|
||||||
|
|
@ -149,6 +160,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.isLive = isLive;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +194,7 @@ public final class SinglePeriodTimeline extends Timeline {
|
||||||
windowStartTimeMs,
|
windowStartTimeMs,
|
||||||
isSeekable,
|
isSeekable,
|
||||||
isDynamic,
|
isDynamic,
|
||||||
|
isLive,
|
||||||
windowDefaultStartPositionUs,
|
windowDefaultStartPositionUs,
|
||||||
windowDurationUs,
|
windowDurationUs,
|
||||||
0,
|
0,
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,12 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
|
||||||
dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP);
|
dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP);
|
||||||
timeline =
|
timeline =
|
||||||
new SinglePeriodTimeline(
|
new SinglePeriodTimeline(
|
||||||
durationUs, /* isSeekable= */ true, /* isDynamic= */ false, /* manifest= */ null, tag);
|
durationUs,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
|
/* manifest= */ null,
|
||||||
|
tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaSource implementation.
|
// MediaSource implementation.
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ public final class MediaPeriodQueueTest {
|
||||||
private static final long SECOND_AD_START_TIME_US = 20 * C.MICROS_PER_SECOND;
|
private static final long SECOND_AD_START_TIME_US = 20 * C.MICROS_PER_SECOND;
|
||||||
|
|
||||||
private static final Timeline CONTENT_TIMELINE =
|
private static final Timeline CONTENT_TIMELINE =
|
||||||
new SinglePeriodTimeline(CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false);
|
new SinglePeriodTimeline(
|
||||||
|
CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false, /* isLive= */ false);
|
||||||
private static final Uri AD_URI = Uri.EMPTY;
|
private static final Uri AD_URI = Uri.EMPTY;
|
||||||
|
|
||||||
private MediaPeriodQueue mediaPeriodQueue;
|
private MediaPeriodQueue mediaPeriodQueue;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,12 @@ public final class ClippingMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoClipping() throws IOException {
|
public void testNoClipping() throws IOException {
|
||||||
Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
|
Timeline timeline =
|
||||||
|
new SinglePeriodTimeline(
|
||||||
|
TEST_PERIOD_DURATION_US,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
|
|
||||||
Timeline clippedTimeline = getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US);
|
Timeline clippedTimeline = getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US);
|
||||||
|
|
||||||
|
|
@ -78,7 +83,12 @@ public final class ClippingMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClippingUnseekableWindowThrows() throws IOException {
|
public void testClippingUnseekableWindowThrows() throws IOException {
|
||||||
Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, false, false);
|
Timeline timeline =
|
||||||
|
new SinglePeriodTimeline(
|
||||||
|
TEST_PERIOD_DURATION_US,
|
||||||
|
/* isSeekable= */ false,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
|
|
||||||
// If the unseekable window isn't clipped, clipping succeeds.
|
// If the unseekable window isn't clipped, clipping succeeds.
|
||||||
getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US);
|
getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US);
|
||||||
|
|
@ -93,7 +103,12 @@ public final class ClippingMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClippingStart() throws IOException {
|
public void testClippingStart() throws IOException {
|
||||||
Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
|
Timeline timeline =
|
||||||
|
new SinglePeriodTimeline(
|
||||||
|
TEST_PERIOD_DURATION_US,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
|
|
||||||
Timeline clippedTimeline =
|
Timeline clippedTimeline =
|
||||||
getClippedTimeline(timeline, TEST_CLIP_AMOUNT_US, TEST_PERIOD_DURATION_US);
|
getClippedTimeline(timeline, TEST_CLIP_AMOUNT_US, TEST_PERIOD_DURATION_US);
|
||||||
|
|
@ -105,7 +120,12 @@ public final class ClippingMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClippingEnd() throws IOException {
|
public void testClippingEnd() throws IOException {
|
||||||
Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
|
Timeline timeline =
|
||||||
|
new SinglePeriodTimeline(
|
||||||
|
TEST_PERIOD_DURATION_US,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
|
|
||||||
Timeline clippedTimeline =
|
Timeline clippedTimeline =
|
||||||
getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US);
|
getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US);
|
||||||
|
|
@ -121,7 +141,8 @@ public final class ClippingMediaSourceTest {
|
||||||
// to it having loaded sufficient data to establish its duration and seekability. Such timelines
|
// to it having loaded sufficient data to establish its duration and seekability. Such timelines
|
||||||
// should not result in clipping failure.
|
// should not result in clipping failure.
|
||||||
Timeline timeline =
|
Timeline timeline =
|
||||||
new SinglePeriodTimeline(C.TIME_UNSET, /* isSeekable= */ false, /* isDynamic= */ true);
|
new SinglePeriodTimeline(
|
||||||
|
C.TIME_UNSET, /* isSeekable= */ false, /* isDynamic= */ true, /* isLive= */ true);
|
||||||
|
|
||||||
Timeline clippedTimeline =
|
Timeline clippedTimeline =
|
||||||
getClippedTimeline(
|
getClippedTimeline(
|
||||||
|
|
@ -139,7 +160,8 @@ public final class ClippingMediaSourceTest {
|
||||||
new SinglePeriodTimeline(
|
new SinglePeriodTimeline(
|
||||||
/* durationUs= */ TEST_PERIOD_DURATION_US,
|
/* durationUs= */ TEST_PERIOD_DURATION_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ false);
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
|
|
||||||
// When clipping to the end, the clipped timeline should also have a duration.
|
// When clipping to the end, the clipped timeline should also have a duration.
|
||||||
Timeline clippedTimeline =
|
Timeline clippedTimeline =
|
||||||
|
|
@ -153,7 +175,10 @@ public final class ClippingMediaSourceTest {
|
||||||
// Create a child timeline that has an unknown duration.
|
// Create a child timeline that has an unknown duration.
|
||||||
Timeline timeline =
|
Timeline timeline =
|
||||||
new SinglePeriodTimeline(
|
new SinglePeriodTimeline(
|
||||||
/* durationUs= */ C.TIME_UNSET, /* isSeekable= */ true, /* isDynamic= */ false);
|
/* durationUs= */ C.TIME_UNSET,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
|
|
||||||
// When clipping to the end, the clipped timeline should also have an unset duration.
|
// When clipping to the end, the clipped timeline should also have an unset duration.
|
||||||
Timeline clippedTimeline =
|
Timeline clippedTimeline =
|
||||||
|
|
@ -164,7 +189,12 @@ public final class ClippingMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClippingStartAndEnd() throws IOException {
|
public void testClippingStartAndEnd() throws IOException {
|
||||||
Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
|
Timeline timeline =
|
||||||
|
new SinglePeriodTimeline(
|
||||||
|
TEST_PERIOD_DURATION_US,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
|
|
||||||
Timeline clippedTimeline =
|
Timeline clippedTimeline =
|
||||||
getClippedTimeline(
|
getClippedTimeline(
|
||||||
|
|
@ -185,6 +215,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
|
|
||||||
|
|
@ -207,6 +238,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
Timeline timeline2 =
|
Timeline timeline2 =
|
||||||
|
|
@ -217,6 +249,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
|
|
||||||
|
|
@ -256,6 +289,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
Timeline timeline2 =
|
Timeline timeline2 =
|
||||||
|
|
@ -266,6 +300,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
|
|
||||||
|
|
@ -305,6 +340,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
Timeline timeline2 =
|
Timeline timeline2 =
|
||||||
|
|
@ -315,6 +351,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
|
|
||||||
|
|
@ -355,6 +392,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
Timeline timeline2 =
|
Timeline timeline2 =
|
||||||
|
|
@ -365,6 +403,7 @@ public final class ClippingMediaSourceTest {
|
||||||
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
|
|
||||||
|
|
@ -480,7 +519,10 @@ public final class ClippingMediaSourceTest {
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Timeline timeline =
|
Timeline timeline =
|
||||||
new SinglePeriodTimeline(
|
new SinglePeriodTimeline(
|
||||||
TEST_PERIOD_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false);
|
TEST_PERIOD_DURATION_US,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false);
|
||||||
FakeMediaSource fakeMediaSource =
|
FakeMediaSource fakeMediaSource =
|
||||||
new FakeMediaSource(timeline) {
|
new FakeMediaSource(timeline) {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ public final class SinglePeriodTimelineTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetPeriodPositionDynamicWindowUnknownDuration() {
|
public void testGetPeriodPositionDynamicWindowUnknownDuration() {
|
||||||
SinglePeriodTimeline timeline = new SinglePeriodTimeline(C.TIME_UNSET, false, true);
|
SinglePeriodTimeline timeline =
|
||||||
|
new SinglePeriodTimeline(
|
||||||
|
C.TIME_UNSET, /* isSeekable= */ false, /* isDynamic= */ true, /* isLive= */ true);
|
||||||
// Should return null with any positive position projection.
|
// Should return null with any positive position projection.
|
||||||
Pair<Object, Long> position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, 1);
|
Pair<Object, Long> position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, 1);
|
||||||
assertThat(position).isNull();
|
assertThat(position).isNull();
|
||||||
|
|
@ -62,6 +64,7 @@ public final class SinglePeriodTimelineTest {
|
||||||
/* windowDefaultStartPositionUs= */ 0,
|
/* windowDefaultStartPositionUs= */ 0,
|
||||||
/* isSeekable= */ false,
|
/* isSeekable= */ false,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
// Should return null with a positive position projection beyond window duration.
|
// Should return null with a positive position projection beyond window duration.
|
||||||
|
|
@ -85,6 +88,7 @@ public final class SinglePeriodTimelineTest {
|
||||||
/* durationUs= */ C.TIME_UNSET,
|
/* durationUs= */ C.TIME_UNSET,
|
||||||
/* isSeekable= */ false,
|
/* isSeekable= */ false,
|
||||||
/* isDynamic= */ false,
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
|
|
||||||
|
|
@ -104,6 +108,7 @@ public final class SinglePeriodTimelineTest {
|
||||||
/* durationUs= */ C.TIME_UNSET,
|
/* durationUs= */ C.TIME_UNSET,
|
||||||
/* isSeekable= */ false,
|
/* isSeekable= */ false,
|
||||||
/* isDynamic= */ false,
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
tag);
|
tag);
|
||||||
|
|
||||||
|
|
@ -117,6 +122,7 @@ public final class SinglePeriodTimelineTest {
|
||||||
/* durationUs= */ C.TIME_UNSET,
|
/* durationUs= */ C.TIME_UNSET,
|
||||||
/* isSeekable= */ false,
|
/* isSeekable= */ false,
|
||||||
/* isDynamic= */ false,
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
/* manifest= */ null,
|
/* manifest= */ null,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
Object uid = timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ true).uid;
|
Object uid = timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ true).uid;
|
||||||
|
|
|
||||||
|
|
@ -1216,10 +1216,6 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
Assertions.checkIndex(windowIndex, 0, 1);
|
Assertions.checkIndex(windowIndex, 0, 1);
|
||||||
long windowDefaultStartPositionUs = getAdjustedWindowDefaultStartPositionUs(
|
long windowDefaultStartPositionUs = getAdjustedWindowDefaultStartPositionUs(
|
||||||
defaultPositionProjectionUs);
|
defaultPositionProjectionUs);
|
||||||
boolean isDynamic =
|
|
||||||
manifest.dynamic
|
|
||||||
&& manifest.minUpdatePeriodMs != C.TIME_UNSET
|
|
||||||
&& manifest.durationMs == C.TIME_UNSET;
|
|
||||||
return window.set(
|
return window.set(
|
||||||
Window.SINGLE_WINDOW_UID,
|
Window.SINGLE_WINDOW_UID,
|
||||||
windowTag,
|
windowTag,
|
||||||
|
|
@ -1227,7 +1223,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
presentationStartTimeMs,
|
presentationStartTimeMs,
|
||||||
windowStartTimeMs,
|
windowStartTimeMs,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
isDynamic,
|
/* isDynamic= */ isMovingLiveWindow(manifest),
|
||||||
|
/* isLive= */ manifest.dynamic,
|
||||||
windowDefaultStartPositionUs,
|
windowDefaultStartPositionUs,
|
||||||
windowDurationUs,
|
windowDurationUs,
|
||||||
/* firstPeriodIndex= */ 0,
|
/* firstPeriodIndex= */ 0,
|
||||||
|
|
@ -1247,7 +1244,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
|
|
||||||
private long getAdjustedWindowDefaultStartPositionUs(long defaultPositionProjectionUs) {
|
private long getAdjustedWindowDefaultStartPositionUs(long defaultPositionProjectionUs) {
|
||||||
long windowDefaultStartPositionUs = this.windowDefaultStartPositionUs;
|
long windowDefaultStartPositionUs = this.windowDefaultStartPositionUs;
|
||||||
if (!manifest.dynamic) {
|
if (!isMovingLiveWindow(manifest)) {
|
||||||
return windowDefaultStartPositionUs;
|
return windowDefaultStartPositionUs;
|
||||||
}
|
}
|
||||||
if (defaultPositionProjectionUs > 0) {
|
if (defaultPositionProjectionUs > 0) {
|
||||||
|
|
@ -1292,6 +1289,12 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||||
Assertions.checkIndex(periodIndex, 0, getPeriodCount());
|
Assertions.checkIndex(periodIndex, 0, getPeriodCount());
|
||||||
return firstPeriodId + periodIndex;
|
return firstPeriodId + periodIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isMovingLiveWindow(DashManifest manifest) {
|
||||||
|
return manifest.dynamic
|
||||||
|
&& manifest.minUpdatePeriodMs != C.TIME_UNSET
|
||||||
|
&& manifest.durationMs == C.TIME_UNSET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class DefaultPlayerEmsgCallback implements PlayerEmsgCallback {
|
private final class DefaultPlayerEmsgCallback implements PlayerEmsgCallback {
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||||
windowDefaultStartPositionUs,
|
windowDefaultStartPositionUs,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ !playlist.hasEndTag,
|
/* isDynamic= */ !playlist.hasEndTag,
|
||||||
|
/* isLive= */ true,
|
||||||
manifest,
|
manifest,
|
||||||
tag);
|
tag);
|
||||||
} else /* not live */ {
|
} else /* not live */ {
|
||||||
|
|
@ -455,6 +456,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||||
windowDefaultStartPositionUs,
|
windowDefaultStartPositionUs,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ false,
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
manifest,
|
manifest,
|
||||||
tag);
|
tag);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -696,7 +696,8 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
/* windowPositionInPeriodUs= */ 0,
|
/* windowPositionInPeriodUs= */ 0,
|
||||||
/* windowDefaultStartPositionUs= */ 0,
|
/* windowDefaultStartPositionUs= */ 0,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
manifest.isLive,
|
/* isDynamic= */ manifest.isLive,
|
||||||
|
/* isLive= */ manifest.isLive,
|
||||||
manifest,
|
manifest,
|
||||||
tag);
|
tag);
|
||||||
} else if (manifest.isLive) {
|
} else if (manifest.isLive) {
|
||||||
|
|
@ -719,6 +720,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
defaultStartPositionUs,
|
defaultStartPositionUs,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ true,
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
manifest,
|
manifest,
|
||||||
tag);
|
tag);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -732,6 +734,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||||
/* windowDefaultStartPositionUs= */ 0,
|
/* windowDefaultStartPositionUs= */ 0,
|
||||||
/* isSeekable= */ true,
|
/* isSeekable= */ true,
|
||||||
/* isDynamic= */ false,
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
manifest,
|
manifest,
|
||||||
tag);
|
tag);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,7 @@ public final class FakeTimeline extends Timeline {
|
||||||
/* windowStartTimeMs= */ C.TIME_UNSET,
|
/* windowStartTimeMs= */ C.TIME_UNSET,
|
||||||
windowDefinition.isSeekable,
|
windowDefinition.isSeekable,
|
||||||
windowDefinition.isDynamic,
|
windowDefinition.isDynamic,
|
||||||
|
/* isLive= */ windowDefinition.isDynamic,
|
||||||
/* defaultPositionUs= */ 0,
|
/* defaultPositionUs= */ 0,
|
||||||
windowDefinition.durationUs,
|
windowDefinition.durationUs,
|
||||||
periodOffsets[windowIndex],
|
periodOffsets[windowIndex],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue