Use integers as identifiers for DASH periods.
This is in preparation for making it so that periods aren't reused. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=130113382
This commit is contained in:
parent
0ca81b1a4c
commit
6e24372414
@ -894,8 +894,7 @@ import java.io.IOException;
|
||||
// TODO[playlists]: Signal the identifier discontinuity, even if the index hasn't changed.
|
||||
if (oldTimeline != null) {
|
||||
int newPlayingIndex = playingPeriod != null ? playingPeriod.index
|
||||
: loadingPeriod != null ? loadingPeriod.index
|
||||
: mediaSource.getNewPlayingPeriodIndex(playbackInfo.periodIndex, oldTimeline);
|
||||
: loadingPeriod != null ? loadingPeriod.index : Timeline.NO_PERIOD_INDEX;
|
||||
if (newPlayingIndex != Timeline.NO_PERIOD_INDEX
|
||||
&& newPlayingIndex != playbackInfo.periodIndex) {
|
||||
long oldPositionUs = playbackInfo.positionUs;
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source;
|
||||
|
||||
import android.util.Pair;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -64,14 +65,12 @@ public final class ConcatenatingMediaSource implements MediaSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewPlayingPeriodIndex(int oldPlayingPeriodIndex, Timeline oldConcatenatedTimeline)
|
||||
throws IOException {
|
||||
public int getNewPlayingPeriodIndex(int oldPlayingPeriodIndex, Timeline oldConcatenatedTimeline) {
|
||||
ConcatenatedTimeline oldTimeline = (ConcatenatedTimeline) oldConcatenatedTimeline;
|
||||
int sourceIndex = oldTimeline.getSourceIndexForPeriod(oldPlayingPeriodIndex);
|
||||
int oldFirstPeriodIndex = oldTimeline.getFirstPeriodIndexInSource(sourceIndex);
|
||||
int firstPeriodIndex = timeline.getFirstPeriodIndexInSource(sourceIndex);
|
||||
return firstPeriodIndex == Timeline.NO_PERIOD_INDEX ? Timeline.NO_PERIOD_INDEX
|
||||
: firstPeriodIndex + mediaSources[sourceIndex].getNewPlayingPeriodIndex(
|
||||
return firstPeriodIndex + mediaSources[sourceIndex].getNewPlayingPeriodIndex(
|
||||
oldPlayingPeriodIndex - oldFirstPeriodIndex, oldTimeline.timelines[sourceIndex]);
|
||||
}
|
||||
|
||||
@ -165,18 +164,22 @@ public final class ConcatenatingMediaSource implements MediaSource {
|
||||
public Object getPeriodId(int index) {
|
||||
int sourceIndex = getSourceIndexForPeriod(index);
|
||||
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(index);
|
||||
return timelines[sourceIndex].getPeriodId(index - firstPeriodIndexInSource);
|
||||
Object periodId = timelines[sourceIndex].getPeriodId(index - firstPeriodIndexInSource);
|
||||
return Pair.create(sourceIndex, periodId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexOfPeriod(Object id) {
|
||||
for (int sourceIndex = 0; sourceIndex < timelines.length; sourceIndex++) {
|
||||
int periodIndexInSource = timelines[sourceIndex].getIndexOfPeriod(id);
|
||||
// The id was returned by getPeriodId, so it is always a Pair<Integer, Object>.
|
||||
@SuppressWarnings("unchecked")
|
||||
Pair<Integer, Object> sourceIndexAndPeriodId = (Pair<Integer, Object>) id;
|
||||
int sourceIndex = sourceIndexAndPeriodId.first;
|
||||
Object periodId = sourceIndexAndPeriodId.second;
|
||||
int periodIndexInSource = timelines[sourceIndex].getIndexOfPeriod(periodId);
|
||||
if (periodIndexInSource != NO_PERIOD_INDEX) {
|
||||
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
|
||||
return firstPeriodIndexInSource + periodIndexInSource;
|
||||
}
|
||||
}
|
||||
return NO_PERIOD_INDEX;
|
||||
}
|
||||
|
||||
@ -195,8 +198,7 @@ public final class ConcatenatingMediaSource implements MediaSource {
|
||||
}
|
||||
|
||||
private int getFirstPeriodIndexInSource(int sourceIndex) {
|
||||
return sourceIndex == 0 ? 0 : sourceIndex > sourceOffsets.length
|
||||
? Timeline.NO_PERIOD_INDEX : sourceOffsets[sourceIndex - 1];
|
||||
return sourceIndex == 0 ? 0 : sourceOffsets[sourceIndex - 1];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -78,25 +78,28 @@ public interface MediaSource {
|
||||
void prepareSource(Listener listener);
|
||||
|
||||
/**
|
||||
* Returns the period index to play in this source's new timeline.
|
||||
* Returns the period index to play in this source's new timeline, or
|
||||
* {@link Timeline#NO_PERIOD_INDEX} if the player should stop playback. The
|
||||
* {@code oldPlayingPeriodIndex} should be an index of a period in the old timeline that is no
|
||||
* longer present (based on its identifier) in the new timeline.
|
||||
*
|
||||
* @param oldPlayingPeriodIndex The period index that was being played in the old timeline.
|
||||
* @param oldTimeline The old timeline.
|
||||
* @return The period index to play in this source's new timeline.
|
||||
* @throws IOException Thrown if the required period can't be loaded.
|
||||
* @return The new period index to play in this source's new timeline. Playback will resume from
|
||||
* the default start position in the new period index.
|
||||
*/
|
||||
int getNewPlayingPeriodIndex(int oldPlayingPeriodIndex, Timeline oldTimeline) throws IOException;
|
||||
int getNewPlayingPeriodIndex(int oldPlayingPeriodIndex, Timeline oldTimeline);
|
||||
|
||||
/**
|
||||
* Returns the default {@link Position} that the player should play when it reaches the period at
|
||||
* {@code index}, or {@code null} if the default start period and position are not yet known.
|
||||
* Returns the default {@link Position} that the player should play when when starting to play the
|
||||
* period at {@code index}, or {@code null} if the default position is not yet known.
|
||||
* <p>
|
||||
* For example, sources can return a {@link Position} with the passed period {@code index} to play
|
||||
* the period at {@code index} immediately after the period at {@code index - 1}. Or, sources
|
||||
* the period at {@code index} immediately after the period at {@code index - 1}. Sources
|
||||
* providing multi-period live streams may return the index and position of the live edge when
|
||||
* passed {@code index == 0} so that the playback position jumps to the live edge.
|
||||
* passed {@code index == 0} to play from the live edge.
|
||||
*
|
||||
* @param index The index of the period the player has just reached.
|
||||
* @param index The index of the requested period.
|
||||
* @return The default start position.
|
||||
*/
|
||||
Position getDefaultStartPosition(int index);
|
||||
|
@ -63,8 +63,7 @@ public final class MergingMediaSource implements MediaSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewPlayingPeriodIndex(int oldPlayingPeriodIndex, Timeline oldTimeline)
|
||||
throws IOException {
|
||||
public int getNewPlayingPeriodIndex(int oldPlayingPeriodIndex, Timeline oldTimeline) {
|
||||
return mediaSources[0].getNewPlayingPeriodIndex(oldPlayingPeriodIndex, oldTimeline);
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,6 @@ import java.util.List;
|
||||
}
|
||||
}
|
||||
|
||||
public long getStartUs() {
|
||||
return period.startMs * 1000;
|
||||
}
|
||||
|
||||
// MediaPeriod implementation.
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@ import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
|
||||
@ -41,7 +42,6 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@ -75,6 +75,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
private final DashManifestParser manifestParser;
|
||||
private final ManifestCallback manifestCallback;
|
||||
private final Object manifestUriLock;
|
||||
private final SparseArray<DashMediaPeriod> periodsById;
|
||||
private final Runnable refreshSourceInfoRunnable;
|
||||
|
||||
private MediaSource.Listener sourceListener;
|
||||
@ -86,10 +87,11 @@ public final class DashMediaSource implements MediaSource {
|
||||
private long manifestLoadEndTimestamp;
|
||||
private DashManifest manifest;
|
||||
private Handler handler;
|
||||
private ArrayList<DashMediaPeriod> periods;
|
||||
private SeekWindow seekWindow;
|
||||
private long elapsedRealtimeOffsetMs;
|
||||
|
||||
private int firstPeriodId;
|
||||
|
||||
public DashMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory,
|
||||
DashChunkSource.Factory chunkSourceFactory, Handler eventHandler,
|
||||
AdaptiveMediaSourceEventListener eventListener) {
|
||||
@ -108,6 +110,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
manifestParser = new DashManifestParser();
|
||||
manifestCallback = new ManifestCallback();
|
||||
manifestUriLock = new Object();
|
||||
periodsById = new SparseArray<>();
|
||||
refreshSourceInfoRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -140,20 +143,8 @@ public final class DashMediaSource implements MediaSource {
|
||||
|
||||
@Override
|
||||
public int getNewPlayingPeriodIndex(int oldPlayingPeriodIndex, Timeline oldTimeline) {
|
||||
int periodIndex = oldPlayingPeriodIndex;
|
||||
int oldPeriodCount = oldTimeline.getPeriodCount();
|
||||
while (periodIndex < oldPeriodCount) {
|
||||
Object id = oldTimeline.getPeriodId(periodIndex);
|
||||
if (id == null) {
|
||||
break;
|
||||
}
|
||||
int index = periods.indexOf(id);
|
||||
if (index != -1) {
|
||||
return index;
|
||||
}
|
||||
periodIndex++;
|
||||
}
|
||||
return Timeline.NO_PERIOD_INDEX;
|
||||
// Seek to the default position, which is the live edge for live sources.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -179,11 +170,14 @@ public final class DashMediaSource implements MediaSource {
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(int index) throws IOException {
|
||||
if (periods == null || periods.size() <= index) {
|
||||
if (index >= manifest.getPeriodCount()) {
|
||||
loader.maybeThrowError();
|
||||
return null;
|
||||
}
|
||||
return periods.get(index);
|
||||
DashMediaPeriod mediaPeriod = new DashMediaPeriod(manifest, index, chunkSourceFactory,
|
||||
minLoadableRetryCount, eventDispatcher, elapsedRealtimeOffsetMs, loader);
|
||||
periodsById.put(firstPeriodId + index, mediaPeriod);
|
||||
return mediaPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -201,6 +195,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
handler = null;
|
||||
}
|
||||
elapsedRealtimeOffsetMs = 0;
|
||||
periodsById.clear();
|
||||
}
|
||||
|
||||
// Loadable callbacks.
|
||||
@ -211,12 +206,11 @@ public final class DashMediaSource implements MediaSource {
|
||||
loadDurationMs, loadable.bytesLoaded());
|
||||
DashManifest newManifest = loadable.getResult();
|
||||
|
||||
int periodCount = manifest == null ? 0 : manifest.getPeriodCount();
|
||||
int periodsToRemoveCount = 0;
|
||||
if (periods != null) {
|
||||
int periodCount = periods.size();
|
||||
long newFirstPeriodStartTimeUs = newManifest.getPeriod(0).startMs * 1000;
|
||||
long newFirstPeriodStartTimeMs = newManifest.getPeriod(0).startMs;
|
||||
while (periodsToRemoveCount < periodCount
|
||||
&& periods.get(periodsToRemoveCount).getStartUs() < newFirstPeriodStartTimeUs) {
|
||||
&& manifest.getPeriod(periodsToRemoveCount).startMs < newFirstPeriodStartTimeMs) {
|
||||
periodsToRemoveCount++;
|
||||
}
|
||||
|
||||
@ -229,7 +223,6 @@ public final class DashMediaSource implements MediaSource {
|
||||
scheduleManifestRefresh();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
manifest = newManifest;
|
||||
manifestLoadStartTimestamp = elapsedRealtimeMs - loadDurationMs;
|
||||
@ -244,7 +237,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
}
|
||||
}
|
||||
|
||||
if (periods == null) {
|
||||
if (periodCount == 0) {
|
||||
if (manifest.utcTiming != null) {
|
||||
resolveUtcTimingElement(manifest.utcTiming);
|
||||
} else {
|
||||
@ -253,11 +246,12 @@ public final class DashMediaSource implements MediaSource {
|
||||
} else {
|
||||
// Remove old periods.
|
||||
while (periodsToRemoveCount-- > 0) {
|
||||
periods.remove(0);
|
||||
periodsById.remove(firstPeriodId);
|
||||
firstPeriodId++;
|
||||
periodCount--;
|
||||
}
|
||||
|
||||
// Update existing periods. Only the first and the last periods can change.
|
||||
int periodCount = periods.size();
|
||||
if (periodCount > 0) {
|
||||
updatePeriod(0);
|
||||
if (periodCount > 1) {
|
||||
@ -270,7 +264,10 @@ public final class DashMediaSource implements MediaSource {
|
||||
}
|
||||
|
||||
private void updatePeriod(int index) {
|
||||
periods.get(index).updateManifest(manifest, index);
|
||||
DashMediaPeriod period = periodsById.get(firstPeriodId + index);
|
||||
if (period != null) {
|
||||
period.updateManifest(manifest, index);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ int onManifestLoadError(ParsingLoadable<DashManifest> loadable,
|
||||
@ -355,15 +352,6 @@ public final class DashMediaSource implements MediaSource {
|
||||
}
|
||||
|
||||
private void finishManifestProcessing() {
|
||||
if (periods == null) {
|
||||
periods = new ArrayList<>();
|
||||
}
|
||||
int periodCount = manifest.getPeriodCount();
|
||||
for (int i = periods.size(); i < periodCount; i++) {
|
||||
periods.add(new DashMediaPeriod(manifest, i, chunkSourceFactory, minLoadableRetryCount,
|
||||
eventDispatcher, elapsedRealtimeOffsetMs, loader));
|
||||
}
|
||||
|
||||
handler.removeCallbacks(refreshSourceInfoRunnable);
|
||||
refreshSourceInfo();
|
||||
scheduleManifestRefresh();
|
||||
@ -371,8 +359,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
|
||||
private void refreshSourceInfo() {
|
||||
// Update the seek window.
|
||||
int periodCount = manifest.getPeriodCount();
|
||||
int lastPeriodIndex = periodCount - 1;
|
||||
int lastPeriodIndex = manifest.getPeriodCount() - 1;
|
||||
PeriodSeekInfo firstPeriodSeekInfo = PeriodSeekInfo.createPeriodSeekInfo(manifest.getPeriod(0),
|
||||
manifest.getPeriodDurationUs(0));
|
||||
PeriodSeekInfo lastPeriodSeekInfo = PeriodSeekInfo.createPeriodSeekInfo(
|
||||
@ -397,10 +384,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
currentEndTimeUs = lastPeriodSeekInfo.availableEndTimeUs;
|
||||
}
|
||||
seekWindow = SeekWindow.createWindow(0, currentStartTimeUs, lastPeriodIndex, currentEndTimeUs);
|
||||
|
||||
DashMediaPeriod[] mediaPeriods =
|
||||
periods.toArray(new DashMediaPeriod[manifest.getPeriodCount()]);
|
||||
sourceListener.onSourceInfoRefreshed(new DashTimeline(manifest, mediaPeriods, seekWindow),
|
||||
sourceListener.onSourceInfoRefreshed(new DashTimeline(firstPeriodId, manifest, seekWindow),
|
||||
manifest);
|
||||
}
|
||||
|
||||
@ -483,13 +467,13 @@ public final class DashMediaSource implements MediaSource {
|
||||
|
||||
private static final class DashTimeline implements Timeline {
|
||||
|
||||
private final int firstPeriodId;
|
||||
private final DashManifest manifest;
|
||||
private final DashMediaPeriod[] periods;
|
||||
private final SeekWindow seekWindow;
|
||||
|
||||
public DashTimeline(DashManifest manifest, DashMediaPeriod[] periods, SeekWindow seekWindow) {
|
||||
public DashTimeline(int firstPeriodId, DashManifest manifest, SeekWindow seekWindow) {
|
||||
this.firstPeriodId = firstPeriodId;
|
||||
this.manifest = manifest;
|
||||
this.periods = periods;
|
||||
this.seekWindow = seekWindow;
|
||||
}
|
||||
|
||||
@ -526,20 +510,12 @@ public final class DashMediaSource implements MediaSource {
|
||||
|
||||
@Override
|
||||
public Object getPeriodId(int index) {
|
||||
if (index < 0 || index >= manifest.getPeriodCount()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return periods[index];
|
||||
return firstPeriodId + index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexOfPeriod(Object id) {
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
if (id == periods[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return Timeline.NO_PERIOD_INDEX;
|
||||
return ((Integer) id) - firstPeriodId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user