Expose seek window + start position for SmoothStreaming
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=129867969
This commit is contained in:
parent
2a15480102
commit
c5a2f9b010
@ -19,18 +19,29 @@ import com.google.android.exoplayer2.C;
|
|||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Timeline} consisting of a single period.
|
* A {@link Timeline} consisting of a single period and seek window.
|
||||||
*/
|
*/
|
||||||
public final class SinglePeriodTimeline implements Timeline {
|
public final class SinglePeriodTimeline implements Timeline {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new timeline with one period of unknown duration and no seek window.
|
* Returns a new timeline with one period of unknown duration and an empty seek window.
|
||||||
*
|
*
|
||||||
* @param id The identifier for the period.
|
* @param id The identifier for the period.
|
||||||
* @return A new timeline with one period of unknown duration.
|
* @return A new timeline with one period of unknown duration.
|
||||||
*/
|
*/
|
||||||
public static Timeline createNonFinalTimeline(Object id) {
|
public static Timeline createNonFinalTimeline(Object id) {
|
||||||
return new SinglePeriodTimeline(id, false, C.UNSET_TIME_US);
|
return new SinglePeriodTimeline(id, false, C.UNSET_TIME_US, SeekWindow.UNSEEKABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new timeline with one period of unknown duration and the specified seek window.
|
||||||
|
*
|
||||||
|
* @param id The identifier for the period.
|
||||||
|
* @param seekWindow The seek window.
|
||||||
|
* @return A new timeline with one period of unknown duration.
|
||||||
|
*/
|
||||||
|
public static Timeline createNonFinalTimeline(Object id, SeekWindow seekWindow) {
|
||||||
|
return new SinglePeriodTimeline(id, false, C.UNSET_TIME_US, seekWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,14 +70,13 @@ public final class SinglePeriodTimeline implements Timeline {
|
|||||||
private final Object id;
|
private final Object id;
|
||||||
private final boolean isFinal;
|
private final boolean isFinal;
|
||||||
private final long durationMs;
|
private final long durationMs;
|
||||||
private final SeekWindow[] seekWindows;
|
private final SeekWindow seekWindow;
|
||||||
|
|
||||||
private SinglePeriodTimeline(Object id, boolean isFinal, long durationMs,
|
private SinglePeriodTimeline(Object id, boolean isFinal, long durationMs, SeekWindow seekWindow) {
|
||||||
SeekWindow... seekWindows) {
|
|
||||||
this.id = Assertions.checkNotNull(id);
|
this.id = Assertions.checkNotNull(id);
|
||||||
this.isFinal = isFinal;
|
this.isFinal = isFinal;
|
||||||
this.durationMs = durationMs;
|
this.durationMs = durationMs;
|
||||||
this.seekWindows = seekWindows;
|
this.seekWindow = seekWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -99,12 +109,12 @@ public final class SinglePeriodTimeline implements Timeline {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSeekWindowCount() {
|
public int getSeekWindowCount() {
|
||||||
return seekWindows.length;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SeekWindow getSeekWindow(int index) {
|
public SeekWindow getSeekWindow(int index) {
|
||||||
return seekWindows[index];
|
return seekWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,11 @@ import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
|
|||||||
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
|
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.SeekWindow;
|
||||||
import com.google.android.exoplayer2.source.SinglePeriodTimeline;
|
import com.google.android.exoplayer2.source.SinglePeriodTimeline;
|
||||||
import com.google.android.exoplayer2.source.Timeline;
|
import com.google.android.exoplayer2.source.Timeline;
|
||||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
||||||
|
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement;
|
||||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser;
|
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
import com.google.android.exoplayer2.upstream.Loader;
|
||||||
@ -45,6 +47,11 @@ public final class SsMediaSource implements MediaSource,
|
|||||||
* The default minimum number of times to retry loading data prior to failing.
|
* The default minimum number of times to retry loading data prior to failing.
|
||||||
*/
|
*/
|
||||||
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
|
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
|
||||||
|
/**
|
||||||
|
* The offset in microseconds subtracted from the live edge position when calculating the default
|
||||||
|
* position returned by {@link #getDefaultStartPosition(int)}.
|
||||||
|
*/
|
||||||
|
private static final long LIVE_EDGE_OFFSET_US = 30000000;
|
||||||
|
|
||||||
private static final int MINIMUM_MANIFEST_REFRESH_PERIOD_MS = 5000;
|
private static final int MINIMUM_MANIFEST_REFRESH_PERIOD_MS = 5000;
|
||||||
|
|
||||||
@ -61,6 +68,7 @@ public final class SsMediaSource implements MediaSource,
|
|||||||
|
|
||||||
private long manifestLoadStartTimestamp;
|
private long manifestLoadStartTimestamp;
|
||||||
private SsManifest manifest;
|
private SsManifest manifest;
|
||||||
|
private SeekWindow seekWindow;
|
||||||
|
|
||||||
private Handler manifestRefreshHandler;
|
private Handler manifestRefreshHandler;
|
||||||
private SsMediaPeriod period;
|
private SsMediaPeriod period;
|
||||||
@ -102,7 +110,14 @@ public final class SsMediaSource implements MediaSource,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Position getDefaultStartPosition(int index) {
|
public Position getDefaultStartPosition(int index) {
|
||||||
// TODO: Return the position of the live edge, if applicable.
|
if (seekWindow == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (manifest.isLive) {
|
||||||
|
long startPositionUs = Math.max(seekWindow.startTimeUs,
|
||||||
|
seekWindow.endTimeUs - LIVE_EDGE_OFFSET_US);
|
||||||
|
return new Position(0, startPositionUs);
|
||||||
|
}
|
||||||
return Position.DEFAULT;
|
return Position.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,9 +159,27 @@ public final class SsMediaSource implements MediaSource,
|
|||||||
} else {
|
} else {
|
||||||
period.updateManifest(manifest);
|
period.updateManifest(manifest);
|
||||||
}
|
}
|
||||||
Timeline timeline = manifest.isLive || manifest.durationUs == C.UNSET_TIME_US
|
Timeline timeline;
|
||||||
? SinglePeriodTimeline.createUnseekableFinalTimeline(this, C.UNSET_TIME_US)
|
if (manifest.isLive) {
|
||||||
: SinglePeriodTimeline.createSeekableFinalTimeline(this, manifest.durationUs);
|
long startTimeUs = Long.MAX_VALUE;
|
||||||
|
for (int i = 0; i < manifest.streamElements.length; i++) {
|
||||||
|
StreamElement element = manifest.streamElements[i];
|
||||||
|
if (element.chunkCount > 0) {
|
||||||
|
startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startTimeUs == Long.MAX_VALUE) {
|
||||||
|
timeline = SinglePeriodTimeline.createNonFinalTimeline(this);
|
||||||
|
} else {
|
||||||
|
timeline = SinglePeriodTimeline.createNonFinalTimeline(this,
|
||||||
|
new SeekWindow(0, startTimeUs, 0, startTimeUs + manifest.dvrWindowLengthUs));
|
||||||
|
}
|
||||||
|
} else if (manifest.durationUs == C.UNSET_TIME_US) {
|
||||||
|
timeline = SinglePeriodTimeline.createUnseekableFinalTimeline(this, C.UNSET_TIME_US);
|
||||||
|
} else {
|
||||||
|
timeline = SinglePeriodTimeline.createSeekableFinalTimeline(this, manifest.durationUs);
|
||||||
|
}
|
||||||
|
seekWindow = timeline.getSeekWindow(0);
|
||||||
sourceListener.onSourceInfoRefreshed(timeline, manifest);
|
sourceListener.onSourceInfoRefreshed(timeline, manifest);
|
||||||
scheduleManifestRefresh();
|
scheduleManifestRefresh();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user