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.
|
// MediaPeriod implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,6 +41,7 @@ import java.io.InputStream;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
private long manifestLoadEndTimestamp;
|
private long manifestLoadEndTimestamp;
|
||||||
private DashManifest manifest;
|
private DashManifest manifest;
|
||||||
private Handler manifestRefreshHandler;
|
private Handler manifestRefreshHandler;
|
||||||
private DashMediaPeriod[] periods;
|
private ArrayList<DashMediaPeriod> periods;
|
||||||
private long elapsedRealtimeOffset;
|
private long elapsedRealtimeOffset;
|
||||||
|
|
||||||
public DashMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory,
|
public DashMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory,
|
||||||
@ -114,10 +115,9 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
if (id == null) {
|
if (id == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < periods.length; i++) {
|
int index = periods.indexOf(id);
|
||||||
if (periods[i] == id) {
|
if (index != -1) {
|
||||||
return i;
|
return index;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
periodIndex++;
|
periodIndex++;
|
||||||
}
|
}
|
||||||
@ -126,11 +126,11 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaPeriod createPeriod(int index) throws IOException {
|
public MediaPeriod createPeriod(int index) throws IOException {
|
||||||
if (periods == null) {
|
if (periods == null || periods.size() <= index) {
|
||||||
loader.maybeThrowError();
|
loader.maybeThrowError();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return periods[index];
|
return periods.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -156,7 +156,29 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
long elapsedRealtimeMs, long loadDurationMs) {
|
long elapsedRealtimeMs, long loadDurationMs) {
|
||||||
eventDispatcher.loadCompleted(loadable.dataSpec, loadable.type, elapsedRealtimeMs,
|
eventDispatcher.loadCompleted(loadable.dataSpec, loadable.type, elapsedRealtimeMs,
|
||||||
loadDurationMs, loadable.bytesLoaded());
|
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;
|
manifestLoadStartTimestamp = elapsedRealtimeMs - loadDurationMs;
|
||||||
manifestLoadEndTimestamp = elapsedRealtimeMs;
|
manifestLoadEndTimestamp = elapsedRealtimeMs;
|
||||||
if (manifest.location != null) {
|
if (manifest.location != null) {
|
||||||
@ -167,16 +189,29 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
if (manifest.utcTiming != null) {
|
if (manifest.utcTiming != null) {
|
||||||
resolveUtcTimingElement(manifest.utcTiming);
|
resolveUtcTimingElement(manifest.utcTiming);
|
||||||
} else {
|
} else {
|
||||||
finishPrepare();
|
finishManifestProcessing();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < periods.length; i++) {
|
// Remove old periods.
|
||||||
periods[i].updateManifest(manifest, i);
|
while (periodsToRemoveCount-- > 0) {
|
||||||
}
|
periods.remove(0);
|
||||||
scheduleManifestRefresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
/* package */ int onManifestLoadError(ParsingLoadable<DashManifest> loadable,
|
||||||
@ -247,22 +282,26 @@ public final class DashMediaSource implements MediaSource {
|
|||||||
|
|
||||||
private void onUtcTimestampResolved(long elapsedRealtimeOffsetMs) {
|
private void onUtcTimestampResolved(long elapsedRealtimeOffsetMs) {
|
||||||
this.elapsedRealtimeOffset = elapsedRealtimeOffsetMs;
|
this.elapsedRealtimeOffset = elapsedRealtimeOffsetMs;
|
||||||
finishPrepare();
|
finishManifestProcessing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUtcTimestampResolutionError(IOException error) {
|
private void onUtcTimestampResolutionError(IOException error) {
|
||||||
Log.e(TAG, "Failed to resolve UtcTiming element.", error);
|
Log.e(TAG, "Failed to resolve UtcTiming element.", error);
|
||||||
// Be optimistic and continue in the hope that the device clock is correct.
|
// Be optimistic and continue in the hope that the device clock is correct.
|
||||||
finishPrepare();
|
finishManifestProcessing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishPrepare() {
|
private void finishManifestProcessing() {
|
||||||
int periodCount = manifest.getPeriodCount();
|
if (periods == null) {
|
||||||
periods = new DashMediaPeriod[periodCount];
|
periods = new ArrayList<>();
|
||||||
for (int i = 0; i < periodCount; i++) {
|
|
||||||
periods[i] = new DashMediaPeriod(manifest, i, chunkSourceFactory, minLoadableRetryCount,
|
|
||||||
eventDispatcher, elapsedRealtimeOffset, loader);
|
|
||||||
}
|
}
|
||||||
|
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();
|
scheduleManifestRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
private final Evaluation evaluation;
|
private final Evaluation evaluation;
|
||||||
|
|
||||||
private DashManifest manifest;
|
private DashManifest manifest;
|
||||||
|
private int periodIndex;
|
||||||
|
|
||||||
private boolean lastChunkWasInitialization;
|
private boolean lastChunkWasInitialization;
|
||||||
private IOException fatalError;
|
private IOException fatalError;
|
||||||
@ -117,11 +118,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
this.trackSelection = trackSelection;
|
this.trackSelection = trackSelection;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.adaptiveFormatEvaluator = adaptiveFormatEvaluator;
|
this.adaptiveFormatEvaluator = adaptiveFormatEvaluator;
|
||||||
|
this.periodIndex = periodIndex;
|
||||||
this.elapsedRealtimeOffsetUs = elapsedRealtimeOffsetMs * 1000;
|
this.elapsedRealtimeOffsetUs = elapsedRealtimeOffsetMs * 1000;
|
||||||
this.evaluation = new Evaluation();
|
this.evaluation = new Evaluation();
|
||||||
|
|
||||||
long periodDurationUs = getPeriodDurationUs(periodIndex);
|
long periodDurationUs = getPeriodDurationUs();
|
||||||
List<Representation> representations = getRepresentations(periodIndex);
|
List<Representation> representations = getRepresentations();
|
||||||
representationHolders = new RepresentationHolder[trackSelection.length];
|
representationHolders = new RepresentationHolder[trackSelection.length];
|
||||||
for (int i = 0; i < trackSelection.length; i++) {
|
for (int i = 0; i < trackSelection.length; i++) {
|
||||||
Representation representation = representations.get(trackSelection.getTrack(i));
|
Representation representation = representations.get(trackSelection.getTrack(i));
|
||||||
@ -136,11 +138,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateManifest(DashManifest newManifest, int periodIndex) {
|
public void updateManifest(DashManifest newManifest, int newPeriodIndex) {
|
||||||
try {
|
try {
|
||||||
manifest = newManifest;
|
manifest = newManifest;
|
||||||
long periodDurationUs = getPeriodDurationUs(periodIndex);
|
periodIndex = newPeriodIndex;
|
||||||
List<Representation> representations = getRepresentations(periodIndex);
|
long periodDurationUs = getPeriodDurationUs();
|
||||||
|
List<Representation> representations = getRepresentations();
|
||||||
for (int i = 0; i < trackSelection.length; i++) {
|
for (int i = 0; i < trackSelection.length; i++) {
|
||||||
Representation representation = representations.get(trackSelection.getTrack(i));
|
Representation representation = representations.get(trackSelection.getTrack(i));
|
||||||
representationHolders[i].updateRepresentation(periodDurationUs, representation);
|
representationHolders[i].updateRepresentation(periodDurationUs, representation);
|
||||||
@ -249,7 +252,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
if (segmentNum > lastAvailableSegmentNum
|
if (segmentNum > lastAvailableSegmentNum
|
||||||
|| (missingLastSegment && segmentNum >= lastAvailableSegmentNum)) {
|
|| (missingLastSegment && segmentNum >= lastAvailableSegmentNum)) {
|
||||||
// This is beyond the last chunk in the current manifest.
|
// This is beyond the last chunk in the current manifest.
|
||||||
out.endOfStream = !manifest.dynamic;
|
out.endOfStream = !manifest.dynamic || (periodIndex < manifest.getPeriodCount() - 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +312,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
|
|
||||||
// Private methods.
|
// Private methods.
|
||||||
|
|
||||||
private List<Representation> getRepresentations(int periodIndex) {
|
private List<Representation> getRepresentations() {
|
||||||
return manifest.getPeriod(periodIndex).adaptationSets.get(adaptationSetIndex).representations;
|
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);
|
long durationMs = manifest.getPeriodDuration(periodIndex);
|
||||||
if (durationMs == -1) {
|
if (durationMs == -1) {
|
||||||
return C.UNSET_TIME_US;
|
return C.UNSET_TIME_US;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user