Allow applications to specify the live edge offset.

Also allow use of suggestedPresentationDelay taken from the
manifest, and enable this by default.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=130409924
This commit is contained in:
olly 2016-08-16 09:22:18 -07:00 committed by Oliver Woodman
parent 76f7fffb8d
commit e0773f705f
4 changed files with 41 additions and 16 deletions

View file

@ -57,23 +57,31 @@ public final class DashMediaSource implements MediaSource {
* The default minimum number of times to retry loading data prior to failing.
*/
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
/**
* A constant indicating that the live edge offset (the offset subtracted from the live edge
* when calculating the default position returned by {@link #getDefaultStartPosition(int)}) should
* be set to {@link DashManifest#suggestedPresentationDelay} if specified by the manifest, or
* {@link #DEFAULT_LIVE_EDGE_OFFSET_FIXED_MS} otherwise.
*/
public static final long DEFAULT_LIVE_EDGE_OFFSET_PREFER_MANIFEST_MS = -1;
/**
* A fixed default live edge offset (the offset subtracted from the live edge when calculating the
* default position returned by {@link #getDefaultStartPosition(int)}).
*/
public static final long DEFAULT_LIVE_EDGE_OFFSET_FIXED_MS = 30000;
/**
* The interval in milliseconds between invocations of
* {@link MediaSource.Listener#onSourceInfoRefreshed(Timeline, Object)} when the source's
* {@link Window} is changing dynamically (for example, for incomplete live streams).
*/
private static final int NOTIFY_MANIFEST_INTERVAL_MS = 5000;
/**
* The offset in milliseconds subtracted from the live edge position when calculating the default
* position returned by {@link #getDefaultStartPosition(int)}.
*/
private static final long LIVE_EDGE_OFFSET_MS = 30000;
private static final String TAG = "DashMediaSource";
private final DataSource.Factory manifestDataSourceFactory;
private final DashChunkSource.Factory chunkSourceFactory;
private final int minLoadableRetryCount;
private final long liveEdgeOffsetMs;
private final EventDispatcher eventDispatcher;
private final DashManifestParser manifestParser;
private final ManifestCallback manifestCallback;
@ -99,16 +107,18 @@ public final class DashMediaSource implements MediaSource {
DashChunkSource.Factory chunkSourceFactory, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) {
this(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
DEFAULT_MIN_LOADABLE_RETRY_COUNT, eventHandler, eventListener);
DEFAULT_MIN_LOADABLE_RETRY_COUNT, DEFAULT_LIVE_EDGE_OFFSET_PREFER_MANIFEST_MS, eventHandler,
eventListener);
}
public DashMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory,
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, long liveEdgeOffsetMs,
Handler eventHandler, AdaptiveMediaSourceEventListener eventListener) {
this.manifestUri = manifestUri;
this.manifestDataSourceFactory = manifestDataSourceFactory;
this.chunkSourceFactory = chunkSourceFactory;
this.minLoadableRetryCount = minLoadableRetryCount;
this.liveEdgeOffsetMs = liveEdgeOffsetMs;
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
manifestParser = new DashManifestParser(generateContentId());
manifestCallback = new ManifestCallback();
@ -159,7 +169,12 @@ public final class DashMediaSource implements MediaSource {
if (index == 0 && manifest.dynamic) {
// The stream is live, so return a position a position offset from the live edge.
int periodIndex = window.endPeriodIndex;
long positionMs = window.endTimeMs - LIVE_EDGE_OFFSET_MS;
long liveEdgeOffsetForManifest = liveEdgeOffsetMs;
if (liveEdgeOffsetForManifest == DEFAULT_LIVE_EDGE_OFFSET_PREFER_MANIFEST_MS) {
liveEdgeOffsetForManifest = manifest.suggestedPresentationDelay != -1
? manifest.suggestedPresentationDelay : DEFAULT_LIVE_EDGE_OFFSET_FIXED_MS;
}
long positionMs = window.endTimeMs - liveEdgeOffsetForManifest;
while (positionMs < 0 && periodIndex > window.startPeriodIndex) {
periodIndex--;
positionMs += manifest.getPeriodDurationMs(periodIndex);

View file

@ -37,6 +37,8 @@ public class DashManifest {
public final long timeShiftBufferDepth;
public final long suggestedPresentationDelay;
public final UtcTimingElement utcTiming;
public final Uri location;
@ -44,14 +46,16 @@ public class DashManifest {
private final List<Period> periods;
public DashManifest(long availabilityStartTime, long duration, long minBufferTime,
boolean dynamic, long minUpdatePeriod, long timeShiftBufferDepth, UtcTimingElement utcTiming,
Uri location, List<Period> periods) {
boolean dynamic, long minUpdatePeriod, long timeShiftBufferDepth,
long suggestedPresentationDelay, UtcTimingElement utcTiming, Uri location,
List<Period> periods) {
this.availabilityStartTime = availabilityStartTime;
this.duration = duration;
this.minBufferTime = minBufferTime;
this.dynamic = dynamic;
this.minUpdatePeriod = minUpdatePeriod;
this.timeShiftBufferDepth = timeShiftBufferDepth;
this.suggestedPresentationDelay = suggestedPresentationDelay;
this.utcTiming = utcTiming;
this.location = location;
this.periods = periods == null ? Collections.<Period>emptyList() : periods;

View file

@ -106,8 +106,10 @@ public class DashManifestParser extends DefaultHandler
long minBufferTimeMs = parseDuration(xpp, "minBufferTime", -1);
String typeString = xpp.getAttributeValue(null, "type");
boolean dynamic = typeString != null && typeString.equals("dynamic");
long minUpdateTimeMs = (dynamic) ? parseDuration(xpp, "minimumUpdatePeriod", -1) : -1;
long timeShiftBufferDepthMs = (dynamic) ? parseDuration(xpp, "timeShiftBufferDepth", -1) : -1;
long minUpdateTimeMs = dynamic ? parseDuration(xpp, "minimumUpdatePeriod", -1) : -1;
long timeShiftBufferDepthMs = dynamic ? parseDuration(xpp, "timeShiftBufferDepth", -1) : -1;
long suggestedPresentationDelayMs = dynamic
? parseDuration(xpp, "suggestedPresentationDelay", -1) : -1;
UtcTimingElement utcTiming = null;
Uri location = null;
@ -159,14 +161,17 @@ public class DashManifestParser extends DefaultHandler
}
return buildMediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs,
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, location, periods);
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, utcTiming,
location, periods);
}
protected DashManifest buildMediaPresentationDescription(long availabilityStartTime,
long durationMs, long minBufferTimeMs, boolean dynamic, long minUpdateTimeMs,
long timeShiftBufferDepthMs, UtcTimingElement utcTiming, Uri location, List<Period> periods) {
long timeShiftBufferDepthMs, long suggestedPresentationDelayMs, UtcTimingElement utcTiming,
Uri location, List<Period> periods) {
return new DashManifest(availabilityStartTime, durationMs, minBufferTimeMs,
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, location, periods);
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, utcTiming,
location, periods);
}
protected UtcTimingElement parseUtcTiming(XmlPullParser xpp) {

View file

@ -743,7 +743,8 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
DefaultDashChunkSource.Factory chunkSourceFactory = new DefaultDashChunkSource.Factory(
mediaDataSourceFactory);
return new DashMediaSource(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
MIN_LOADABLE_RETRY_COUNT, null, null);
MIN_LOADABLE_RETRY_COUNT, DashMediaSource.DEFAULT_LIVE_EDGE_OFFSET_PREFER_MANIFEST_MS,
null, null);
}
@Override