mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
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
This commit is contained in:
parent
e0773f705f
commit
7bed85950e
2 changed files with 20 additions and 12 deletions
|
|
@ -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,
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
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,
|
||||||
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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue