mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add available segment logic to SegmentIndex
This allows to use the same logic from multiple places without duplicating it, encapsulates in its logical place, and allows to change the available segments based on the new availabilityTimeOffset value. The overall effect of this change is a no-op. PiperOrigin-RevId: 333044186
This commit is contained in:
parent
fb4b705cfe
commit
12e887438b
@ -64,38 +64,54 @@ public interface DashSegmentIndex {
|
||||
*/
|
||||
RangedUri getSegmentUrl(long segmentNum);
|
||||
|
||||
/**
|
||||
* Returns the segment number of the first segment.
|
||||
*
|
||||
* @return The segment number of the first segment.
|
||||
*/
|
||||
/** Returns the segment number of the first defined segment in the index. */
|
||||
long getFirstSegmentNum();
|
||||
|
||||
/**
|
||||
* Returns the number of segments in the index, or {@link #INDEX_UNBOUNDED}.
|
||||
* <p>
|
||||
* An unbounded index occurs if a dynamic manifest uses SegmentTemplate elements without a
|
||||
* SegmentTimeline element, and if the period duration is not yet known. In this case the caller
|
||||
* must manually determine the window of currently available segments.
|
||||
* Returns the segment number of the first available segment in the index.
|
||||
*
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or
|
||||
* {@link C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or {@link
|
||||
* C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @param nowUnixTimeUs The current time in milliseconds since the Unix epoch.
|
||||
* @return The number of the first available segment.
|
||||
*/
|
||||
long getFirstAvailableSegmentNum(long periodDurationUs, long nowUnixTimeUs);
|
||||
|
||||
/**
|
||||
* Returns the number of segments defined in the index, or {@link #INDEX_UNBOUNDED}.
|
||||
*
|
||||
* <p>An unbounded index occurs if a dynamic manifest uses SegmentTemplate elements without a
|
||||
* SegmentTimeline element, and if the period duration is not yet known. In this case the caller
|
||||
* can query the available segment using {@link #getFirstAvailableSegmentNum(long, long)} and
|
||||
* {@link #getAvailableSegmentCount(long, long)}.
|
||||
*
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or {@link
|
||||
* C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @return The number of segments in the index, or {@link #INDEX_UNBOUNDED}.
|
||||
*/
|
||||
int getSegmentCount(long periodDurationUs);
|
||||
|
||||
/**
|
||||
* Returns the number of available segments in the index.
|
||||
*
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or {@link
|
||||
* C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @param nowUnixTimeUs The current time in milliseconds since the Unix epoch.
|
||||
* @return The number of available segments in the index.
|
||||
*/
|
||||
int getAvailableSegmentCount(long periodDurationUs, long nowUnixTimeUs);
|
||||
|
||||
/**
|
||||
* Returns true if segments are defined explicitly by the index.
|
||||
* <p>
|
||||
* If true is returned, each segment is defined explicitly by the index data, and all of the
|
||||
*
|
||||
* <p>If true is returned, each segment is defined explicitly by the index data, and all of the
|
||||
* listed segments are guaranteed to be available at the time when the index was obtained.
|
||||
* <p>
|
||||
* If false is returned then segment information was derived from properties such as a fixed
|
||||
*
|
||||
* <p>If false is returned then segment information was derived from properties such as a fixed
|
||||
* segment duration. If the presentation is dynamic, it's possible that only a subset of the
|
||||
* segments are available.
|
||||
*
|
||||
* @return Whether segments are defined explicitly by the index.
|
||||
*/
|
||||
boolean isExplicit();
|
||||
|
||||
}
|
||||
|
@ -41,11 +41,21 @@ public final class DashWrappingSegmentIndex implements DashSegmentIndex {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFirstAvailableSegmentNum(long periodDurationUs, long nowUnixTimeUs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSegmentCount(long periodDurationUs) {
|
||||
return chunkIndex.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailableSegmentCount(long periodDurationUs, long nowUnixTimeUs) {
|
||||
return chunkIndex.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeUs(long segmentNum) {
|
||||
return chunkIndex.timesUs[(int) segmentNum] - timeOffsetUs;
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.dash;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import android.net.Uri;
|
||||
@ -288,9 +287,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
chunkIterators[i] = MediaChunkIterator.EMPTY;
|
||||
} else {
|
||||
long firstAvailableSegmentNum =
|
||||
representationHolder.getFirstAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
|
||||
representationHolder.getFirstAvailableSegmentNum(nowUnixTimeUs);
|
||||
long lastAvailableSegmentNum =
|
||||
representationHolder.getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
|
||||
representationHolder.getLastAvailableSegmentNum(nowUnixTimeUs);
|
||||
long segmentNum =
|
||||
getSegmentNum(
|
||||
representationHolder,
|
||||
@ -342,10 +341,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return;
|
||||
}
|
||||
|
||||
long firstAvailableSegmentNum =
|
||||
representationHolder.getFirstAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
|
||||
long lastAvailableSegmentNum =
|
||||
representationHolder.getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
|
||||
long firstAvailableSegmentNum = representationHolder.getFirstAvailableSegmentNum(nowUnixTimeUs);
|
||||
long lastAvailableSegmentNum = representationHolder.getLastAvailableSegmentNum(nowUnixTimeUs);
|
||||
|
||||
updateLiveEdgeTimeUs(representationHolder, lastAvailableSegmentNum);
|
||||
|
||||
@ -739,6 +736,11 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return segmentIndex.getFirstSegmentNum() + segmentNumShift;
|
||||
}
|
||||
|
||||
public long getFirstAvailableSegmentNum(long nowUnixTimeUs) {
|
||||
return segmentIndex.getFirstAvailableSegmentNum(periodDurationUs, nowUnixTimeUs)
|
||||
+ segmentNumShift;
|
||||
}
|
||||
|
||||
public int getSegmentCount() {
|
||||
return segmentIndex.getSegmentCount(periodDurationUs);
|
||||
}
|
||||
@ -760,35 +762,10 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return segmentIndex.getSegmentUrl(segmentNum - segmentNumShift);
|
||||
}
|
||||
|
||||
public long getFirstAvailableSegmentNum(
|
||||
DashManifest manifest, int periodIndex, long nowUnixTimeUs) {
|
||||
if (getSegmentCount() == DashSegmentIndex.INDEX_UNBOUNDED
|
||||
&& manifest.timeShiftBufferDepthMs != C.TIME_UNSET) {
|
||||
// The index is itself unbounded. We need to use the current time to calculate the range of
|
||||
// available segments.
|
||||
long liveEdgeTimeUs = nowUnixTimeUs - C.msToUs(manifest.availabilityStartTimeMs);
|
||||
long periodStartUs = C.msToUs(manifest.getPeriod(periodIndex).startMs);
|
||||
long liveEdgeTimeInPeriodUs = liveEdgeTimeUs - periodStartUs;
|
||||
long bufferDepthUs = C.msToUs(manifest.timeShiftBufferDepthMs);
|
||||
return max(getFirstSegmentNum(), getSegmentNum(liveEdgeTimeInPeriodUs - bufferDepthUs));
|
||||
}
|
||||
return getFirstSegmentNum();
|
||||
}
|
||||
|
||||
public long getLastAvailableSegmentNum(
|
||||
DashManifest manifest, int periodIndex, long nowUnixTimeUs) {
|
||||
int availableSegmentCount = getSegmentCount();
|
||||
if (availableSegmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
|
||||
// The index is itself unbounded. We need to use the current time to calculate the range of
|
||||
// available segments.
|
||||
long liveEdgeTimeUs = nowUnixTimeUs - C.msToUs(manifest.availabilityStartTimeMs);
|
||||
long periodStartUs = C.msToUs(manifest.getPeriod(periodIndex).startMs);
|
||||
long liveEdgeTimeInPeriodUs = liveEdgeTimeUs - periodStartUs;
|
||||
// getSegmentNum(liveEdgeTimeInPeriodUs) will not be completed yet, so subtract one to get
|
||||
// the index of the last completed segment.
|
||||
return getSegmentNum(liveEdgeTimeInPeriodUs) - 1;
|
||||
}
|
||||
return getFirstSegmentNum() + availableSegmentCount - 1;
|
||||
public long getLastAvailableSegmentNum(long nowUnixTimeUs) {
|
||||
return getFirstAvailableSegmentNum(nowUnixTimeUs)
|
||||
+ segmentIndex.getAvailableSegmentCount(periodDurationUs, nowUnixTimeUs)
|
||||
- 1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -138,7 +138,13 @@ public class DashManifestParser extends DefaultHandler
|
||||
location = Uri.parse(xpp.nextText());
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) {
|
||||
Pair<Period, Long> periodWithDurationMs =
|
||||
parsePeriod(xpp, baseUrl, nextPeriodStartMs, baseUrlAvailabilityTimeOffsetUs);
|
||||
parsePeriod(
|
||||
xpp,
|
||||
baseUrl,
|
||||
nextPeriodStartMs,
|
||||
baseUrlAvailabilityTimeOffsetUs,
|
||||
availabilityStartTime,
|
||||
timeShiftBufferDepthMs);
|
||||
Period period = periodWithDurationMs.first;
|
||||
if (period.startMs == C.TIME_UNSET) {
|
||||
if (dynamic) {
|
||||
@ -226,10 +232,17 @@ public class DashManifestParser extends DefaultHandler
|
||||
}
|
||||
|
||||
protected Pair<Period, Long> parsePeriod(
|
||||
XmlPullParser xpp, String baseUrl, long defaultStartMs, long baseUrlAvailabilityTimeOffsetUs)
|
||||
XmlPullParser xpp,
|
||||
String baseUrl,
|
||||
long defaultStartMs,
|
||||
long baseUrlAvailabilityTimeOffsetUs,
|
||||
long availabilityStartTimeMs,
|
||||
long timeShiftBufferDepthMs)
|
||||
throws XmlPullParserException, IOException {
|
||||
@Nullable String id = xpp.getAttributeValue(null, "id");
|
||||
long startMs = parseDuration(xpp, "start", defaultStartMs);
|
||||
long periodStartUnixTimeMs =
|
||||
availabilityStartTimeMs != C.TIME_UNSET ? availabilityStartTimeMs + startMs : C.TIME_UNSET;
|
||||
long durationMs = parseDuration(xpp, "duration", C.TIME_UNSET);
|
||||
@Nullable SegmentBase segmentBase = null;
|
||||
@Nullable Descriptor assetIdentifier = null;
|
||||
@ -254,7 +267,9 @@ public class DashManifestParser extends DefaultHandler
|
||||
segmentBase,
|
||||
durationMs,
|
||||
baseUrlAvailabilityTimeOffsetUs,
|
||||
segmentBaseAvailabilityTimeOffsetUs));
|
||||
segmentBaseAvailabilityTimeOffsetUs,
|
||||
periodStartUnixTimeMs,
|
||||
timeShiftBufferDepthMs));
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "EventStream")) {
|
||||
eventStreams.add(parseEventStream(xpp));
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
||||
@ -308,7 +323,9 @@ public class DashManifestParser extends DefaultHandler
|
||||
@Nullable SegmentBase segmentBase,
|
||||
long periodDurationMs,
|
||||
long baseUrlAvailabilityTimeOffsetUs,
|
||||
long segmentBaseAvailabilityTimeOffsetUs)
|
||||
long segmentBaseAvailabilityTimeOffsetUs,
|
||||
long periodStartUnixTimeMs,
|
||||
long timeShiftBufferDepthMs)
|
||||
throws XmlPullParserException, IOException {
|
||||
int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET);
|
||||
int contentType = parseContentType(xpp);
|
||||
@ -428,7 +445,9 @@ public class DashManifestParser extends DefaultHandler
|
||||
label,
|
||||
drmSchemeType,
|
||||
drmSchemeDatas,
|
||||
inbandEventStreams));
|
||||
inbandEventStreams,
|
||||
periodStartUnixTimeMs,
|
||||
timeShiftBufferDepthMs));
|
||||
}
|
||||
|
||||
return buildAdaptationSet(
|
||||
@ -725,7 +744,9 @@ public class DashManifestParser extends DefaultHandler
|
||||
@Nullable String label,
|
||||
@Nullable String extraDrmSchemeType,
|
||||
ArrayList<SchemeData> extraDrmSchemeDatas,
|
||||
ArrayList<Descriptor> extraInbandEventStreams) {
|
||||
ArrayList<Descriptor> extraInbandEventStreams,
|
||||
long periodStartUnixTimeMs,
|
||||
long timeShiftBufferDepthMs) {
|
||||
Format.Builder formatBuilder = representationInfo.format.buildUpon();
|
||||
if (label != null) {
|
||||
formatBuilder.setLabel(label);
|
||||
@ -747,7 +768,9 @@ public class DashManifestParser extends DefaultHandler
|
||||
formatBuilder.build(),
|
||||
representationInfo.baseUrl,
|
||||
representationInfo.segmentBase,
|
||||
inbandEventStreams);
|
||||
inbandEventStreams,
|
||||
periodStartUnixTimeMs,
|
||||
timeShiftBufferDepthMs);
|
||||
}
|
||||
|
||||
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.dash.manifest;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@ -71,7 +73,14 @@ public abstract class Representation {
|
||||
*/
|
||||
public static Representation newInstance(
|
||||
long revisionId, Format format, String baseUrl, SegmentBase segmentBase) {
|
||||
return newInstance(revisionId, format, baseUrl, segmentBase, /* inbandEventStreams= */ null);
|
||||
return newInstance(
|
||||
revisionId,
|
||||
format,
|
||||
baseUrl,
|
||||
segmentBase,
|
||||
/* inbandEventStreams= */ null,
|
||||
/* periodStartUnixTimeMs= */ C.TIME_UNSET,
|
||||
/* timeShiftBufferDepthMs= */ C.TIME_UNSET);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,6 +91,9 @@ public abstract class Representation {
|
||||
* @param baseUrl The base URL.
|
||||
* @param segmentBase A segment base element for the representation.
|
||||
* @param inbandEventStreams The in-band event streams in the representation. May be null.
|
||||
* @param periodStartUnixTimeMs The start time of the enclosing {@link Period} in milliseconds
|
||||
* since the Unix epoch, or {@link C#TIME_UNSET} is not applicable.
|
||||
* @param timeShiftBufferDepthMs The {@link DashManifest#timeShiftBufferDepthMs}.
|
||||
* @return The constructed instance.
|
||||
*/
|
||||
public static Representation newInstance(
|
||||
@ -89,9 +101,18 @@ public abstract class Representation {
|
||||
Format format,
|
||||
String baseUrl,
|
||||
SegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams) {
|
||||
@Nullable List<Descriptor> inbandEventStreams,
|
||||
long periodStartUnixTimeMs,
|
||||
long timeShiftBufferDepthMs) {
|
||||
return newInstance(
|
||||
revisionId, format, baseUrl, segmentBase, inbandEventStreams, /* cacheKey= */ null);
|
||||
revisionId,
|
||||
format,
|
||||
baseUrl,
|
||||
segmentBase,
|
||||
inbandEventStreams,
|
||||
periodStartUnixTimeMs,
|
||||
timeShiftBufferDepthMs,
|
||||
/* cacheKey= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,6 +123,9 @@ public abstract class Representation {
|
||||
* @param baseUrl The base URL of the representation.
|
||||
* @param segmentBase A segment base element for the representation.
|
||||
* @param inbandEventStreams The in-band event streams in the representation. May be null.
|
||||
* @param periodStartUnixTimeMs The start time of the enclosing {@link Period} in milliseconds
|
||||
* since the Unix epoch, or {@link C#TIME_UNSET} is not applicable.
|
||||
* @param timeShiftBufferDepthMs The {@link DashManifest#timeShiftBufferDepthMs}.
|
||||
* @param cacheKey An optional key to be returned from {@link #getCacheKey()}, or null. This
|
||||
* parameter is ignored if {@code segmentBase} consists of multiple segments.
|
||||
* @return The constructed instance.
|
||||
@ -112,6 +136,8 @@ public abstract class Representation {
|
||||
String baseUrl,
|
||||
SegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams,
|
||||
long periodStartUnixTimeMs,
|
||||
long timeShiftBufferDepthMs,
|
||||
@Nullable String cacheKey) {
|
||||
if (segmentBase instanceof SingleSegmentBase) {
|
||||
return new SingleSegmentRepresentation(
|
||||
@ -124,7 +150,13 @@ public abstract class Representation {
|
||||
C.LENGTH_UNSET);
|
||||
} else if (segmentBase instanceof MultiSegmentBase) {
|
||||
return new MultiSegmentRepresentation(
|
||||
revisionId, format, baseUrl, (MultiSegmentBase) segmentBase, inbandEventStreams);
|
||||
revisionId,
|
||||
format,
|
||||
baseUrl,
|
||||
(MultiSegmentBase) segmentBase,
|
||||
inbandEventStreams,
|
||||
periodStartUnixTimeMs,
|
||||
timeShiftBufferDepthMs);
|
||||
} else {
|
||||
throw new IllegalArgumentException("segmentBase must be of type SingleSegmentBase or "
|
||||
+ "MultiSegmentBase");
|
||||
@ -277,22 +309,33 @@ public abstract class Representation {
|
||||
implements DashSegmentIndex {
|
||||
|
||||
@VisibleForTesting /* package */ final MultiSegmentBase segmentBase;
|
||||
private final long periodStartUnixTimeUs;
|
||||
private final long timeShiftBufferDepthUs;
|
||||
|
||||
/**
|
||||
* Creates the multi-segment Representation.
|
||||
*
|
||||
* @param revisionId Identifies the revision of the content.
|
||||
* @param format The format of the representation.
|
||||
* @param baseUrl The base URL of the representation.
|
||||
* @param segmentBase The segment base underlying the representation.
|
||||
* @param inbandEventStreams The in-band event streams in the representation. May be null.
|
||||
* @param periodStartUnixTimeMs The start time of the enclosing {@link Period} in milliseconds
|
||||
* since the Unix epoch, or {@link C#TIME_UNSET} is not applicable.
|
||||
* @param timeShiftBufferDepthMs The {@link DashManifest#timeShiftBufferDepthMs}.
|
||||
*/
|
||||
public MultiSegmentRepresentation(
|
||||
long revisionId,
|
||||
Format format,
|
||||
String baseUrl,
|
||||
MultiSegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams) {
|
||||
@Nullable List<Descriptor> inbandEventStreams,
|
||||
long periodStartUnixTimeMs,
|
||||
long timeShiftBufferDepthMs) {
|
||||
super(revisionId, format, baseUrl, segmentBase, inbandEventStreams);
|
||||
this.segmentBase = segmentBase;
|
||||
this.periodStartUnixTimeUs = C.msToUs(periodStartUnixTimeMs);
|
||||
this.timeShiftBufferDepthUs = C.msToUs(timeShiftBufferDepthMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -339,11 +382,41 @@ public abstract class Representation {
|
||||
return segmentBase.getFirstSegmentNum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFirstAvailableSegmentNum(long periodDurationUs, long nowUnixTimeUs) {
|
||||
long segmentCount = segmentBase.getSegmentCount(periodDurationUs);
|
||||
if (segmentCount != INDEX_UNBOUNDED || timeShiftBufferDepthUs == C.TIME_UNSET) {
|
||||
return segmentBase.getFirstSegmentNum();
|
||||
}
|
||||
// The index is itself unbounded. We need to use the current time to calculate the range of
|
||||
// available segments.
|
||||
long liveEdgeTimeInPeriodUs = nowUnixTimeUs - periodStartUnixTimeUs;
|
||||
long timeShiftBufferStartInPeriodUs = liveEdgeTimeInPeriodUs - timeShiftBufferDepthUs;
|
||||
long timeShiftBufferStartSegmentNum =
|
||||
getSegmentNum(timeShiftBufferStartInPeriodUs, periodDurationUs);
|
||||
return max(getFirstSegmentNum(), timeShiftBufferStartSegmentNum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSegmentCount(long periodDurationUs) {
|
||||
return segmentBase.getSegmentCount(periodDurationUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailableSegmentCount(long periodDurationUs, long nowUnixTimeUs) {
|
||||
int segmentCount = segmentBase.getSegmentCount(periodDurationUs);
|
||||
if (segmentCount != INDEX_UNBOUNDED) {
|
||||
return segmentCount;
|
||||
}
|
||||
// The index is itself unbounded. We need to use the current time to calculate the range of
|
||||
// available segments.
|
||||
long liveEdgeTimeInPeriodUs = nowUnixTimeUs - periodStartUnixTimeUs;
|
||||
// getSegmentNum(liveEdgeTimeInPeriodUs) will not be completed yet.
|
||||
long firstIncompleteSegmentNum = getSegmentNum(liveEdgeTimeInPeriodUs, periodDurationUs);
|
||||
long firstAvailableSegmentNum = getFirstAvailableSegmentNum(periodDurationUs, nowUnixTimeUs);
|
||||
return (int) (firstIncompleteSegmentNum - firstAvailableSegmentNum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExplicit() {
|
||||
return segmentBase.isExplicit();
|
||||
|
@ -56,11 +56,21 @@ import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFirstAvailableSegmentNum(long periodDurationUs, long nowUnixTimeUs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSegmentCount(long periodDurationUs) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailableSegmentCount(long periodDurationUs, long nowUnixTimeUs) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExplicit() {
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user