Commit 7bed8595 by olly Committed by Oliver Woodman

Fix/improve SmoothStreaming live window

- Add missing callback call.
- Allow injection of live edge offset.
- Refine calculation of live window size to correctly
  handle just-started streams where the DVR window
  hasn't yet grown to full size.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=130412465
parent e0773f70
...@@ -77,6 +77,7 @@ import java.util.ArrayList; ...@@ -77,6 +77,7 @@ import java.util.ArrayList;
this.manifest = manifest; this.manifest = manifest;
sampleStreams = newSampleStreamArray(0); sampleStreams = newSampleStreamArray(0);
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams); sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
callback.onPrepared(this);
} }
public void updateManifest(SsManifest manifest) { public void updateManifest(SsManifest manifest) {
......
...@@ -51,10 +51,10 @@ public final class SsMediaSource implements MediaSource, ...@@ -51,10 +51,10 @@ public final class SsMediaSource implements MediaSource,
*/ */
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
/** /**
* The offset in milliseconds subtracted from the live edge position when calculating the default * A default live edge offset (the offset subtracted from the live edge when calculating the
* position returned by {@link #getDefaultStartPosition(int)}. * default position returned by {@link #getDefaultStartPosition(int)}).
*/ */
private static final long LIVE_EDGE_OFFSET_MS = 30000; public static final long DEFAULT_LIVE_EDGE_OFFSET_MS = 30000;
private static final int MINIMUM_MANIFEST_REFRESH_PERIOD_MS = 5000; private static final int MINIMUM_MANIFEST_REFRESH_PERIOD_MS = 5000;
...@@ -62,6 +62,7 @@ public final class SsMediaSource implements MediaSource, ...@@ -62,6 +62,7 @@ public final class SsMediaSource implements MediaSource,
private final DataSource.Factory dataSourceFactory; private final DataSource.Factory dataSourceFactory;
private final SsChunkSource.Factory chunkSourceFactory; private final SsChunkSource.Factory chunkSourceFactory;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private final long liveEdgeOffsetMs;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final SsManifestParser manifestParser; private final SsManifestParser manifestParser;
private final ArrayList<SsMediaPeriod> mediaPeriods; private final ArrayList<SsMediaPeriod> mediaPeriods;
...@@ -80,17 +81,18 @@ public final class SsMediaSource implements MediaSource, ...@@ -80,17 +81,18 @@ public final class SsMediaSource implements MediaSource,
SsChunkSource.Factory chunkSourceFactory, Handler eventHandler, SsChunkSource.Factory chunkSourceFactory, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) { AdaptiveMediaSourceEventListener eventListener) {
this(manifestUri, manifestDataSourceFactory, chunkSourceFactory, this(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
DEFAULT_MIN_LOADABLE_RETRY_COUNT, eventHandler, eventListener); DEFAULT_MIN_LOADABLE_RETRY_COUNT, DEFAULT_LIVE_EDGE_OFFSET_MS, eventHandler, eventListener);
} }
public SsMediaSource(Uri manifestUri, DataSource.Factory dataSourceFactory, public SsMediaSource(Uri manifestUri, DataSource.Factory dataSourceFactory,
SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
Handler eventHandler, AdaptiveMediaSourceEventListener eventListener) { long liveEdgeOffsetMs, Handler eventHandler, AdaptiveMediaSourceEventListener eventListener) {
this.manifestUri = Util.toLowerInvariant(manifestUri.getLastPathSegment()).equals("manifest") this.manifestUri = Util.toLowerInvariant(manifestUri.getLastPathSegment()).equals("manifest")
? manifestUri : Uri.withAppendedPath(manifestUri, "Manifest"); ? manifestUri : Uri.withAppendedPath(manifestUri, "Manifest");
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
this.chunkSourceFactory = chunkSourceFactory; this.chunkSourceFactory = chunkSourceFactory;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.liveEdgeOffsetMs = liveEdgeOffsetMs;
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener); this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
manifestParser = new SsManifestParser(); manifestParser = new SsManifestParser();
mediaPeriods = new ArrayList<>(); mediaPeriods = new ArrayList<>();
...@@ -119,7 +121,7 @@ public final class SsMediaSource implements MediaSource, ...@@ -119,7 +121,7 @@ public final class SsMediaSource implements MediaSource,
} }
if (manifest.isLive) { if (manifest.isLive) {
long startPositionUs = Math.max(window.startTimeMs, long startPositionUs = Math.max(window.startTimeMs,
window.endTimeMs - LIVE_EDGE_OFFSET_MS) * 1000; window.endTimeMs - liveEdgeOffsetMs) * 1000;
return new Position(0, startPositionUs); return new Position(0, startPositionUs);
} }
return Position.DEFAULT; return Position.DEFAULT;
...@@ -177,20 +179,25 @@ public final class SsMediaSource implements MediaSource, ...@@ -177,20 +179,25 @@ public final class SsMediaSource implements MediaSource,
Timeline timeline; Timeline timeline;
if (manifest.isLive) { if (manifest.isLive) {
long startTimeUs = Long.MAX_VALUE; long startTimeUs = Long.MAX_VALUE;
long endTimeUs = Long.MIN_VALUE;
for (int i = 0; i < manifest.streamElements.length; i++) { for (int i = 0; i < manifest.streamElements.length; i++) {
StreamElement element = manifest.streamElements[i]; StreamElement element = manifest.streamElements[i];
if (element.chunkCount > 0) { if (element.chunkCount > 0) {
startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0)); startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0));
endTimeUs = Math.max(endTimeUs, element.getStartTimeUs(element.chunkCount - 1)
+ element.getChunkDurationUs(element.chunkCount - 1));
} }
} }
if (startTimeUs == Long.MAX_VALUE || manifest.dvrWindowLengthUs == C.UNSET_TIME_US if (startTimeUs == Long.MAX_VALUE) {
|| manifest.dvrWindowLengthUs == 0) {
timeline = new SinglePeriodTimeline(C.UNSET_TIME_US, false); timeline = new SinglePeriodTimeline(C.UNSET_TIME_US, false);
} else { } else {
long periodDurationUs = startTimeUs + manifest.dvrWindowLengthUs; if (manifest.dvrWindowLengthUs != C.UNSET_TIME_US
Window window = Window.createWindow(0, startTimeUs, 0, periodDurationUs, && manifest.dvrWindowLengthUs > 0) {
manifest.dvrWindowLengthUs, true); startTimeUs = Math.max(startTimeUs, endTimeUs - manifest.dvrWindowLengthUs);
timeline = new SinglePeriodTimeline(periodDurationUs, window); }
long durationUs = endTimeUs - startTimeUs;
Window window = Window.createWindow(0, startTimeUs, 0, endTimeUs, durationUs, true);
timeline = new SinglePeriodTimeline(endTimeUs, window);
} }
} else { } else {
boolean isSeekable = manifest.durationUs != C.UNSET_TIME_US; boolean isSeekable = manifest.durationUs != C.UNSET_TIME_US;
......
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