mirror of
https://github.com/androidx/media.git
synced 2025-05-17 04:29:55 +08:00
Project default start pos to fix VOD->Live transitions
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=138493584
This commit is contained in:
parent
89ad5e6db3
commit
7b0effc2d0
@ -1014,6 +1014,15 @@ import java.io.IOException;
|
|||||||
return getPeriodPosition(timeline, windowIndex, windowPositionUs);
|
return getPeriodPosition(timeline, windowIndex, windowPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls {@link #getPeriodPosition(Timeline, int, long, long)} with a zero default position
|
||||||
|
* projection.
|
||||||
|
*/
|
||||||
|
private Pair<Integer, Long> getPeriodPosition(Timeline timeline, int windowIndex,
|
||||||
|
long windowPositionUs) {
|
||||||
|
return getPeriodPosition(timeline, windowIndex, windowPositionUs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts (windowIndex, windowPositionUs) to the corresponding (periodIndex, periodPositionUs).
|
* Converts (windowIndex, windowPositionUs) to the corresponding (periodIndex, periodPositionUs).
|
||||||
*
|
*
|
||||||
@ -1021,14 +1030,23 @@ import java.io.IOException;
|
|||||||
* @param windowIndex The window index.
|
* @param windowIndex The window index.
|
||||||
* @param windowPositionUs The window time, or {@link C#TIME_UNSET} to use the window's default
|
* @param windowPositionUs The window time, or {@link C#TIME_UNSET} to use the window's default
|
||||||
* start position.
|
* start position.
|
||||||
* @return The corresponding (periodIndex, periodPositionUs).
|
* @param defaultPositionProjectionUs If {@code windowPositionUs} is {@link C#TIME_UNSET}, the
|
||||||
|
* duration into the future by which the window's position should be projected.
|
||||||
|
* @return The corresponding (periodIndex, periodPositionUs), or null if {@code #windowPositionUs}
|
||||||
|
* is {@link C#TIME_UNSET}, {@code defaultPositionProjectionUs} is non-zero, and the window's
|
||||||
|
* position could not be projected by {@code defaultPositionProjectionUs}.
|
||||||
*/
|
*/
|
||||||
private Pair<Integer, Long> getPeriodPosition(Timeline timeline, int windowIndex,
|
private Pair<Integer, Long> getPeriodPosition(Timeline timeline, int windowIndex,
|
||||||
long windowPositionUs) {
|
long windowPositionUs, long defaultPositionProjectionUs) {
|
||||||
timeline.getWindow(windowIndex, window);
|
timeline.getWindow(windowIndex, window, false, defaultPositionProjectionUs);
|
||||||
|
if (windowPositionUs == C.TIME_UNSET) {
|
||||||
|
windowPositionUs = window.getDefaultPositionUs();
|
||||||
|
if (windowPositionUs == C.TIME_UNSET) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
int periodIndex = window.firstPeriodIndex;
|
int periodIndex = window.firstPeriodIndex;
|
||||||
long periodPositionUs = window.getPositionInFirstPeriodUs()
|
long periodPositionUs = window.getPositionInFirstPeriodUs() + windowPositionUs;
|
||||||
+ (windowPositionUs == C.TIME_UNSET ? window.getDefaultPositionUs() : windowPositionUs);
|
|
||||||
long periodDurationUs = timeline.getPeriod(periodIndex, period).getDurationUs();
|
long periodDurationUs = timeline.getPeriod(periodIndex, period).getDurationUs();
|
||||||
while (periodDurationUs != C.TIME_UNSET && periodPositionUs >= periodDurationUs
|
while (periodDurationUs != C.TIME_UNSET && periodPositionUs >= periodDurationUs
|
||||||
&& periodIndex < window.lastPeriodIndex) {
|
&& periodIndex < window.lastPeriodIndex) {
|
||||||
@ -1062,30 +1080,44 @@ import java.io.IOException;
|
|||||||
: (isFirstPeriodInWindow ? C.TIME_UNSET : 0);
|
: (isFirstPeriodInWindow ? C.TIME_UNSET : 0);
|
||||||
if (periodStartPositionUs == C.TIME_UNSET) {
|
if (periodStartPositionUs == C.TIME_UNSET) {
|
||||||
// This is the first period of a new window or we don't have a start position, so seek to
|
// This is the first period of a new window or we don't have a start position, so seek to
|
||||||
// the default position for the window.
|
// the default position for the window. If we're buffering ahead we also project the
|
||||||
Pair<Integer, Long> defaultPosition = getPeriodPosition(windowIndex, C.TIME_UNSET);
|
// default position so that it's correct for starting playing the buffered duration of
|
||||||
newLoadingPeriodIndex = defaultPosition.first;
|
// time in the future.
|
||||||
periodStartPositionUs = defaultPosition.second;
|
long defaultPositionProjectionUs = loadingPeriodHolder == null ? 0
|
||||||
|
: (loadingPeriodHolder.rendererPositionOffsetUs
|
||||||
|
+ timeline.getPeriod(loadingPeriodHolder.index, period).getDurationUs()
|
||||||
|
- loadingPeriodHolder.startPositionUs - rendererPositionUs);
|
||||||
|
Pair<Integer, Long> defaultPosition = getPeriodPosition(timeline, windowIndex,
|
||||||
|
C.TIME_UNSET, Math.max(0, defaultPositionProjectionUs));
|
||||||
|
if (defaultPosition == null) {
|
||||||
|
newLoadingPeriodIndex = C.INDEX_UNSET;
|
||||||
|
periodStartPositionUs = C.TIME_UNSET;
|
||||||
|
} else {
|
||||||
|
newLoadingPeriodIndex = defaultPosition.first;
|
||||||
|
periodStartPositionUs = defaultPosition.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Object newPeriodUid = timeline.getPeriod(newLoadingPeriodIndex, period, true).uid;
|
if (newLoadingPeriodIndex != C.INDEX_UNSET) {
|
||||||
MediaPeriod newMediaPeriod = mediaSource.createPeriod(newLoadingPeriodIndex,
|
Object newPeriodUid = timeline.getPeriod(newLoadingPeriodIndex, period, true).uid;
|
||||||
loadControl.getAllocator(), periodStartPositionUs);
|
MediaPeriod newMediaPeriod = mediaSource.createPeriod(newLoadingPeriodIndex,
|
||||||
newMediaPeriod.prepare(this);
|
loadControl.getAllocator(), periodStartPositionUs);
|
||||||
MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities,
|
newMediaPeriod.prepare(this);
|
||||||
trackSelector, mediaSource, newMediaPeriod, newPeriodUid, periodStartPositionUs);
|
MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities,
|
||||||
timeline.getWindow(windowIndex, window);
|
trackSelector, mediaSource, newMediaPeriod, newPeriodUid, periodStartPositionUs);
|
||||||
newPeriodHolder.setIndex(timeline, window, newLoadingPeriodIndex);
|
timeline.getWindow(windowIndex, window);
|
||||||
if (loadingPeriodHolder != null) {
|
newPeriodHolder.setIndex(timeline, window, newLoadingPeriodIndex);
|
||||||
loadingPeriodHolder.setNext(newPeriodHolder);
|
if (loadingPeriodHolder != null) {
|
||||||
newPeriodHolder.rendererPositionOffsetUs = loadingPeriodHolder.rendererPositionOffsetUs
|
loadingPeriodHolder.setNext(newPeriodHolder);
|
||||||
+ timeline.getPeriod(loadingPeriodHolder.index, period).getDurationUs()
|
newPeriodHolder.rendererPositionOffsetUs = loadingPeriodHolder.rendererPositionOffsetUs
|
||||||
- loadingPeriodHolder.startPositionUs;
|
+ timeline.getPeriod(loadingPeriodHolder.index, period).getDurationUs()
|
||||||
} else {
|
- loadingPeriodHolder.startPositionUs;
|
||||||
newPeriodHolder.rendererPositionOffsetUs = periodStartPositionUs;
|
} else {
|
||||||
|
newPeriodHolder.rendererPositionOffsetUs = periodStartPositionUs;
|
||||||
|
}
|
||||||
|
bufferAheadPeriodCount++;
|
||||||
|
loadingPeriodHolder = newPeriodHolder;
|
||||||
|
setIsLoading(true);
|
||||||
}
|
}
|
||||||
bufferAheadPeriodCount++;
|
|
||||||
loadingPeriodHolder = newPeriodHolder;
|
|
||||||
setIsLoading(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,10 +114,26 @@ public abstract class Timeline {
|
|||||||
* @param windowIndex The index of the window.
|
* @param windowIndex The index of the window.
|
||||||
* @param window The {@link Window} to populate. Must not be null.
|
* @param window The {@link Window} to populate. Must not be null.
|
||||||
* @param setIds Whether {@link Window#id} should be populated. If false, the field will be set to
|
* @param setIds Whether {@link Window#id} should be populated. If false, the field will be set to
|
||||||
* null. The caller should pass false for efficiency reasons unless the field is required.
|
* null. The caller should pass false for efficiency reasons unless the field is required.
|
||||||
* @return The populated {@link Window}, for convenience.
|
* @return The populated {@link Window}, for convenience.
|
||||||
*/
|
*/
|
||||||
public abstract Window getWindow(int windowIndex, Window window, boolean setIds);
|
public Window getWindow(int windowIndex, Window window, boolean setIds) {
|
||||||
|
return getWindow(windowIndex, window, setIds, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates a {@link Window} with data for the window at the specified index.
|
||||||
|
*
|
||||||
|
* @param windowIndex The index of the window.
|
||||||
|
* @param window The {@link Window} to populate. Must not be null.
|
||||||
|
* @param setIds Whether {@link Window#id} should be populated. If false, the field will be set to
|
||||||
|
* null. The caller should pass false for efficiency reasons unless the field is required.
|
||||||
|
* @param defaultPositionProjectionUs A duration into the future that the populated window's
|
||||||
|
* default start position should be projected.
|
||||||
|
* @return The populated {@link Window}, for convenience.
|
||||||
|
*/
|
||||||
|
public abstract Window getWindow(int windowIndex, Window window, boolean setIds,
|
||||||
|
long defaultPositionProjectionUs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of periods in the timeline.
|
* Returns the number of periods in the timeline.
|
||||||
@ -231,7 +247,9 @@ public abstract class Timeline {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default position relative to the start of the window at which to begin playback,
|
* Returns the default position relative to the start of the window at which to begin playback,
|
||||||
* in milliseconds.
|
* in milliseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a
|
||||||
|
* non-zero default position projection, and if the specified projection cannot be performed
|
||||||
|
* whilst remaining within the bounds of the window.
|
||||||
*/
|
*/
|
||||||
public long getDefaultPositionMs() {
|
public long getDefaultPositionMs() {
|
||||||
return C.usToMs(defaultPositionUs);
|
return C.usToMs(defaultPositionUs);
|
||||||
@ -239,7 +257,9 @@ public abstract class Timeline {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default position relative to the start of the window at which to begin playback,
|
* Returns the default position relative to the start of the window at which to begin playback,
|
||||||
* in microseconds.
|
* in microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a
|
||||||
|
* non-zero default position projection, and if the specified projection cannot be performed
|
||||||
|
* whilst remaining within the bounds of the window.
|
||||||
*/
|
*/
|
||||||
public long getDefaultPositionUs() {
|
public long getDefaultPositionUs() {
|
||||||
return defaultPositionUs;
|
return defaultPositionUs;
|
||||||
|
@ -171,11 +171,13 @@ public final class ConcatenatingMediaSource implements MediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Window getWindow(int windowIndex, Window window, boolean setIds) {
|
public Window getWindow(int windowIndex, Window window, boolean setIds,
|
||||||
|
long defaultPositionProjectionUs) {
|
||||||
int sourceIndex = getSourceIndexForWindow(windowIndex);
|
int sourceIndex = getSourceIndexForWindow(windowIndex);
|
||||||
int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex);
|
int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex);
|
||||||
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
|
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
|
||||||
timelines[sourceIndex].getWindow(windowIndex - firstWindowIndexInSource, window, setIds);
|
timelines[sourceIndex].getWindow(windowIndex - firstWindowIndexInSource, window, setIds,
|
||||||
|
defaultPositionProjectionUs);
|
||||||
window.firstPeriodIndex += firstPeriodIndexInSource;
|
window.firstPeriodIndex += firstPeriodIndexInSource;
|
||||||
window.lastPeriodIndex += firstPeriodIndexInSource;
|
window.lastPeriodIndex += firstPeriodIndexInSource;
|
||||||
return window;
|
return window;
|
||||||
|
@ -118,8 +118,10 @@ public final class LoopingMediaSource implements MediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Window getWindow(int windowIndex, Window window, boolean setIds) {
|
public Window getWindow(int windowIndex, Window window, boolean setIds,
|
||||||
childTimeline.getWindow(windowIndex % childWindowCount, window, setIds);
|
long defaultPositionProjectionUs) {
|
||||||
|
childTimeline.getWindow(windowIndex % childWindowCount, window, setIds,
|
||||||
|
defaultPositionProjectionUs);
|
||||||
int periodIndexOffset = (windowIndex / childWindowCount) * childPeriodCount;
|
int periodIndexOffset = (windowIndex / childWindowCount) * childPeriodCount;
|
||||||
window.firstPeriodIndex += periodIndexOffset;
|
window.firstPeriodIndex += periodIndexOffset;
|
||||||
window.lastPeriodIndex += periodIndexOffset;
|
window.lastPeriodIndex += periodIndexOffset;
|
||||||
|
@ -74,9 +74,18 @@ public final class SinglePeriodTimeline extends Timeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Window getWindow(int windowIndex, Window window, boolean setIds) {
|
public Window getWindow(int windowIndex, Window window, boolean setIds,
|
||||||
|
long defaultPositionProjectionUs) {
|
||||||
Assertions.checkIndex(windowIndex, 0, 1);
|
Assertions.checkIndex(windowIndex, 0, 1);
|
||||||
Object id = setIds ? ID : null;
|
Object id = setIds ? ID : null;
|
||||||
|
long windowDefaultStartPositionUs = this.windowDefaultStartPositionUs;
|
||||||
|
if (isDynamic) {
|
||||||
|
windowDefaultStartPositionUs += defaultPositionProjectionUs;
|
||||||
|
if (windowDefaultStartPositionUs > windowDurationUs) {
|
||||||
|
// The projection takes us beyond the end of the live window.
|
||||||
|
windowDefaultStartPositionUs = C.TIME_UNSET;
|
||||||
|
}
|
||||||
|
}
|
||||||
return window.set(id, C.TIME_UNSET, C.TIME_UNSET, isSeekable, isDynamic,
|
return window.set(id, C.TIME_UNSET, C.TIME_UNSET, isSeekable, isDynamic,
|
||||||
windowDefaultStartPositionUs, windowDurationUs, 0, 0, windowPositionInPeriodUs);
|
windowDefaultStartPositionUs, windowDurationUs, 0, 0, windowPositionInPeriodUs);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ 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.dash.manifest.DashManifest;
|
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
|
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.Period;
|
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement;
|
import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
@ -400,39 +399,13 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
? manifest.suggestedPresentationDelay : DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS;
|
? manifest.suggestedPresentationDelay : DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS;
|
||||||
}
|
}
|
||||||
// Snap the default position to the start of the segment containing it.
|
// Snap the default position to the start of the segment containing it.
|
||||||
long defaultStartPositionUs = windowDurationUs - C.msToUs(presentationDelayForManifestMs);
|
windowDefaultStartPositionUs = windowDurationUs - C.msToUs(presentationDelayForManifestMs);
|
||||||
if (defaultStartPositionUs < MIN_LIVE_DEFAULT_START_POSITION_US) {
|
if (windowDefaultStartPositionUs < MIN_LIVE_DEFAULT_START_POSITION_US) {
|
||||||
// The default start position is too close to the start of the live window. Set it to the
|
// The default start position is too close to the start of the live window. Set it to the
|
||||||
// minimum default start position provided the window is at least twice as big. Else set
|
// minimum default start position provided the window is at least twice as big. Else set
|
||||||
// it to the middle of the window.
|
// it to the middle of the window.
|
||||||
defaultStartPositionUs = Math.min(MIN_LIVE_DEFAULT_START_POSITION_US, windowDurationUs / 2);
|
windowDefaultStartPositionUs = Math.min(MIN_LIVE_DEFAULT_START_POSITION_US,
|
||||||
}
|
windowDurationUs / 2);
|
||||||
|
|
||||||
int periodIndex = 0;
|
|
||||||
long defaultStartPositionInPeriodUs = currentStartTimeUs + defaultStartPositionUs;
|
|
||||||
long periodDurationUs = manifest.getPeriodDurationUs(periodIndex);
|
|
||||||
while (periodIndex < manifest.getPeriodCount() - 1
|
|
||||||
&& defaultStartPositionInPeriodUs >= periodDurationUs) {
|
|
||||||
defaultStartPositionInPeriodUs -= periodDurationUs;
|
|
||||||
periodIndex++;
|
|
||||||
periodDurationUs = manifest.getPeriodDurationUs(periodIndex);
|
|
||||||
}
|
|
||||||
Period period = manifest.getPeriod(periodIndex);
|
|
||||||
int videoAdaptationSetIndex = period.getAdaptationSetIndex(C.TRACK_TYPE_VIDEO);
|
|
||||||
if (videoAdaptationSetIndex != C.INDEX_UNSET) {
|
|
||||||
// If there are multiple video adaptation sets with unaligned segments, the initial time may
|
|
||||||
// not correspond to the start of a segment in both, but this is an edge case.
|
|
||||||
DashSegmentIndex index =
|
|
||||||
period.adaptationSets.get(videoAdaptationSetIndex).representations.get(0).getIndex();
|
|
||||||
if (index != null) {
|
|
||||||
int segmentNum = index.getSegmentNum(defaultStartPositionInPeriodUs, periodDurationUs);
|
|
||||||
windowDefaultStartPositionUs =
|
|
||||||
defaultStartPositionUs - defaultStartPositionInPeriodUs + index.getTimeUs(segmentNum);
|
|
||||||
} else {
|
|
||||||
windowDefaultStartPositionUs = defaultStartPositionUs;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
windowDefaultStartPositionUs = defaultStartPositionUs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long windowStartTimeMs = manifest.availabilityStartTime
|
long windowStartTimeMs = manifest.availabilityStartTime
|
||||||
@ -561,8 +534,11 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Window getWindow(int windowIndex, Window window, boolean setIdentifier) {
|
public Window getWindow(int windowIndex, Window window, boolean setIdentifier,
|
||||||
|
long defaultPositionProjectionUs) {
|
||||||
Assertions.checkIndex(windowIndex, 0, 1);
|
Assertions.checkIndex(windowIndex, 0, 1);
|
||||||
|
long windowDefaultStartPositionUs = getAdjustedWindowDefaultStartPositionUs(
|
||||||
|
defaultPositionProjectionUs);
|
||||||
return window.set(null, presentationStartTimeMs, windowStartTimeMs, true /* isSeekable */,
|
return window.set(null, presentationStartTimeMs, windowStartTimeMs, true /* isSeekable */,
|
||||||
manifest.dynamic, windowDefaultStartPositionUs, windowDurationUs, 0,
|
manifest.dynamic, windowDefaultStartPositionUs, windowDurationUs, 0,
|
||||||
manifest.getPeriodCount() - 1, offsetInFirstPeriodUs);
|
manifest.getPeriodCount() - 1, offsetInFirstPeriodUs);
|
||||||
@ -578,6 +554,48 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
? C.INDEX_UNSET : (periodId - firstPeriodId);
|
? C.INDEX_UNSET : (periodId - firstPeriodId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getAdjustedWindowDefaultStartPositionUs(long defaultPositionProjectionUs) {
|
||||||
|
long windowDefaultStartPositionUs = this.windowDefaultStartPositionUs;
|
||||||
|
if (!manifest.dynamic) {
|
||||||
|
return windowDefaultStartPositionUs;
|
||||||
|
}
|
||||||
|
if (defaultPositionProjectionUs > 0) {
|
||||||
|
windowDefaultStartPositionUs += defaultPositionProjectionUs;
|
||||||
|
if (windowDefaultStartPositionUs > windowDurationUs) {
|
||||||
|
// The projection takes us beyond the end of the live window.
|
||||||
|
return C.TIME_UNSET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Attempt to snap to the start of the corresponding video segment.
|
||||||
|
int periodIndex = 0;
|
||||||
|
long defaultStartPositionInPeriodUs = offsetInFirstPeriodUs + windowDefaultStartPositionUs;
|
||||||
|
long periodDurationUs = manifest.getPeriodDurationUs(periodIndex);
|
||||||
|
while (periodIndex < manifest.getPeriodCount() - 1
|
||||||
|
&& defaultStartPositionInPeriodUs >= periodDurationUs) {
|
||||||
|
defaultStartPositionInPeriodUs -= periodDurationUs;
|
||||||
|
periodIndex++;
|
||||||
|
periodDurationUs = manifest.getPeriodDurationUs(periodIndex);
|
||||||
|
}
|
||||||
|
com.google.android.exoplayer2.source.dash.manifest.Period period =
|
||||||
|
manifest.getPeriod(periodIndex);
|
||||||
|
int videoAdaptationSetIndex = period.getAdaptationSetIndex(C.TRACK_TYPE_VIDEO);
|
||||||
|
if (videoAdaptationSetIndex == C.INDEX_UNSET) {
|
||||||
|
// No video adaptation set for snapping.
|
||||||
|
return windowDefaultStartPositionUs;
|
||||||
|
}
|
||||||
|
// If there are multiple video adaptation sets with unaligned segments, the initial time may
|
||||||
|
// not correspond to the start of a segment in both, but this is an edge case.
|
||||||
|
DashSegmentIndex snapIndex = period.adaptationSets.get(videoAdaptationSetIndex)
|
||||||
|
.representations.get(0).getIndex();
|
||||||
|
if (snapIndex == null) {
|
||||||
|
// Video adaptation set does not include an index for snapping.
|
||||||
|
return windowDefaultStartPositionUs;
|
||||||
|
}
|
||||||
|
int segmentNum = snapIndex.getSegmentNum(defaultStartPositionInPeriodUs, periodDurationUs);
|
||||||
|
return windowDefaultStartPositionUs + snapIndex.getTimeUs(segmentNum)
|
||||||
|
- defaultStartPositionInPeriodUs;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ManifestCallback implements
|
private final class ManifestCallback implements
|
||||||
|
Loading…
x
Reference in New Issue
Block a user