Support for added and removed DASH periods.
Logic and some code is copied from V1. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=128706688
This commit is contained in:
parent
c82a3db5ac
commit
2040615cc8
@ -87,6 +87,10 @@ import java.util.List;
|
||||
}
|
||||
}
|
||||
|
||||
public long getStartUs() {
|
||||
return period.startMs * 1000;
|
||||
}
|
||||
|
||||
// MediaPeriod implementation.
|
||||
|
||||
@Override
|
||||
|
@ -41,6 +41,7 @@ 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;
|
||||
|
||||
@ -72,7 +73,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
private long manifestLoadEndTimestamp;
|
||||
private DashManifest manifest;
|
||||
private Handler manifestRefreshHandler;
|
||||
private DashMediaPeriod[] periods;
|
||||
private ArrayList<DashMediaPeriod> periods;
|
||||
private long elapsedRealtimeOffset;
|
||||
|
||||
public DashMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory,
|
||||
@ -114,10 +115,9 @@ public final class DashMediaSource implements MediaSource {
|
||||
if (id == null) {
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
if (periods[i] == id) {
|
||||
return i;
|
||||
}
|
||||
int index = periods.indexOf(id);
|
||||
if (index != -1) {
|
||||
return index;
|
||||
}
|
||||
periodIndex++;
|
||||
}
|
||||
@ -126,11 +126,11 @@ public final class DashMediaSource implements MediaSource {
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(int index) throws IOException {
|
||||
if (periods == null) {
|
||||
if (periods == null || periods.size() <= index) {
|
||||
loader.maybeThrowError();
|
||||
return null;
|
||||
}
|
||||
return periods[index];
|
||||
return periods.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,7 +156,29 @@ public final class DashMediaSource implements MediaSource {
|
||||
long elapsedRealtimeMs, long loadDurationMs) {
|
||||
eventDispatcher.loadCompleted(loadable.dataSpec, loadable.type, elapsedRealtimeMs,
|
||||
loadDurationMs, loadable.bytesLoaded());
|
||||
manifest = loadable.getResult();
|
||||
DashManifest newManifest = loadable.getResult();
|
||||
|
||||
int periodsToRemoveCount = 0;
|
||||
if (periods != null) {
|
||||
int periodCount = periods.size();
|
||||
long newFirstPeriodStartTimeUs = newManifest.getPeriod(0).startMs * 1000;
|
||||
while (periodsToRemoveCount < periodCount
|
||||
&& periods.get(periodsToRemoveCount).getStartUs() < newFirstPeriodStartTimeUs) {
|
||||
periodsToRemoveCount++;
|
||||
}
|
||||
|
||||
// After discarding old periods, we should never have more periods than listed in the new
|
||||
// manifest. That would mean that a previously announced period is no longer advertised. If
|
||||
// this condition occurs, assume that we are hitting a manifest server that is out of sync and
|
||||
// behind, discard this manifest, and try again later.
|
||||
if (periodCount - periodsToRemoveCount > newManifest.getPeriodCount()) {
|
||||
Log.w(TAG, "Out of sync manifest");
|
||||
scheduleManifestRefresh();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
manifest = newManifest;
|
||||
manifestLoadStartTimestamp = elapsedRealtimeMs - loadDurationMs;
|
||||
manifestLoadEndTimestamp = elapsedRealtimeMs;
|
||||
if (manifest.location != null) {
|
||||
@ -167,16 +189,29 @@ public final class DashMediaSource implements MediaSource {
|
||||
if (manifest.utcTiming != null) {
|
||||
resolveUtcTimingElement(manifest.utcTiming);
|
||||
} else {
|
||||
finishPrepare();
|
||||
finishManifestProcessing();
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
periods[i].updateManifest(manifest, i);
|
||||
}
|
||||
scheduleManifestRefresh();
|
||||
// Remove old periods.
|
||||
while (periodsToRemoveCount-- > 0) {
|
||||
periods.remove(0);
|
||||
}
|
||||
|
||||
invalidationListener.onTimelineChanged(new DashTimeline(manifest, periods));
|
||||
// Update existing periods. Only the first and the last periods can change.
|
||||
int periodCount = periods.size();
|
||||
if (periodCount > 0) {
|
||||
updatePeriod(0);
|
||||
if (periodCount > 1) {
|
||||
updatePeriod(periodCount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
finishManifestProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePeriod(int index) {
|
||||
periods.get(index).updateManifest(manifest, index);
|
||||
}
|
||||
|
||||
/* package */ int onManifestLoadError(ParsingLoadable<DashManifest> loadable,
|
||||
@ -247,22 +282,26 @@ public final class DashMediaSource implements MediaSource {
|
||||
|
||||
private void onUtcTimestampResolved(long elapsedRealtimeOffsetMs) {
|
||||
this.elapsedRealtimeOffset = elapsedRealtimeOffsetMs;
|
||||
finishPrepare();
|
||||
finishManifestProcessing();
|
||||
}
|
||||
|
||||
private void onUtcTimestampResolutionError(IOException error) {
|
||||
Log.e(TAG, "Failed to resolve UtcTiming element.", error);
|
||||
// Be optimistic and continue in the hope that the device clock is correct.
|
||||
finishPrepare();
|
||||
finishManifestProcessing();
|
||||
}
|
||||
|
||||
private void finishPrepare() {
|
||||
int periodCount = manifest.getPeriodCount();
|
||||
periods = new DashMediaPeriod[periodCount];
|
||||
for (int i = 0; i < periodCount; i++) {
|
||||
periods[i] = new DashMediaPeriod(manifest, i, chunkSourceFactory, minLoadableRetryCount,
|
||||
eventDispatcher, elapsedRealtimeOffset, loader);
|
||||
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, elapsedRealtimeOffset, loader));
|
||||
}
|
||||
invalidationListener.onTimelineChanged(new DashTimeline(manifest,
|
||||
periods.toArray(new DashMediaPeriod[periods.size()])));
|
||||
scheduleManifestRefresh();
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
private final Evaluation evaluation;
|
||||
|
||||
private DashManifest manifest;
|
||||
private int periodIndex;
|
||||
|
||||
private boolean lastChunkWasInitialization;
|
||||
private IOException fatalError;
|
||||
@ -117,11 +118,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
this.trackSelection = trackSelection;
|
||||
this.dataSource = dataSource;
|
||||
this.adaptiveFormatEvaluator = adaptiveFormatEvaluator;
|
||||
this.periodIndex = periodIndex;
|
||||
this.elapsedRealtimeOffsetUs = elapsedRealtimeOffsetMs * 1000;
|
||||
this.evaluation = new Evaluation();
|
||||
|
||||
long periodDurationUs = getPeriodDurationUs(periodIndex);
|
||||
List<Representation> representations = getRepresentations(periodIndex);
|
||||
long periodDurationUs = getPeriodDurationUs();
|
||||
List<Representation> representations = getRepresentations();
|
||||
representationHolders = new RepresentationHolder[trackSelection.length];
|
||||
for (int i = 0; i < trackSelection.length; i++) {
|
||||
Representation representation = representations.get(trackSelection.getTrack(i));
|
||||
@ -136,11 +138,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateManifest(DashManifest newManifest, int periodIndex) {
|
||||
public void updateManifest(DashManifest newManifest, int newPeriodIndex) {
|
||||
try {
|
||||
manifest = newManifest;
|
||||
long periodDurationUs = getPeriodDurationUs(periodIndex);
|
||||
List<Representation> representations = getRepresentations(periodIndex);
|
||||
periodIndex = newPeriodIndex;
|
||||
long periodDurationUs = getPeriodDurationUs();
|
||||
List<Representation> representations = getRepresentations();
|
||||
for (int i = 0; i < trackSelection.length; i++) {
|
||||
Representation representation = representations.get(trackSelection.getTrack(i));
|
||||
representationHolders[i].updateRepresentation(periodDurationUs, representation);
|
||||
@ -249,7 +252,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
if (segmentNum > lastAvailableSegmentNum
|
||||
|| (missingLastSegment && segmentNum >= lastAvailableSegmentNum)) {
|
||||
// This is beyond the last chunk in the current manifest.
|
||||
out.endOfStream = !manifest.dynamic;
|
||||
out.endOfStream = !manifest.dynamic || (periodIndex < manifest.getPeriodCount() - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -309,7 +312,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
|
||||
// Private methods.
|
||||
|
||||
private List<Representation> getRepresentations(int periodIndex) {
|
||||
private List<Representation> getRepresentations() {
|
||||
return manifest.getPeriod(periodIndex).adaptationSets.get(adaptationSetIndex).representations;
|
||||
}
|
||||
|
||||
@ -362,7 +365,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
}
|
||||
}
|
||||
|
||||
private long getPeriodDurationUs(int periodIndex) {
|
||||
private long getPeriodDurationUs() {
|
||||
long durationMs = manifest.getPeriodDuration(periodIndex);
|
||||
if (durationMs == -1) {
|
||||
return C.UNSET_TIME_US;
|
||||
|
Loading…
x
Reference in New Issue
Block a user