diff --git a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java index 8bf7199da8..76b40483d8 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java @@ -309,10 +309,26 @@ public class DashChunkSource implements ChunkSource { RepresentationHolder representationHolder = representationHolders.get(representation.format.id); DashSegmentIndex oldIndex = representationHolder.segmentIndex; + int oldIndexLastSegmentNum = oldIndex.getLastSegmentNum(); + long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum) + + oldIndex.getDurationUs(oldIndexLastSegmentNum); DashSegmentIndex newIndex = representation.getIndex(); - int newFirstSegmentNum = newIndex.getFirstSegmentNum(); - int segmentNumShift = oldIndex.getSegmentNum(newIndex.getTimeUs(newFirstSegmentNum)) - - newFirstSegmentNum; + int newIndexFirstSegmentNum = newIndex.getFirstSegmentNum(); + long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum); + if (oldIndexEndTimeUs < newIndexStartTimeUs) { + // There's a gap between the old manifest and the new one which means we've slipped behind + // the live window and can't proceed. + fatalError = new BehindLiveWindowException(); + return; + } + int segmentNumShift; + if (oldIndexEndTimeUs == newIndexStartTimeUs) { + // The new manifest continues where the old one ended, with no overlap. + segmentNumShift = oldIndex.getLastSegmentNum() + 1 - newIndexFirstSegmentNum; + } else { + // The new manifest overlaps with the old one. + segmentNumShift = oldIndex.getSegmentNum(newIndexStartTimeUs) - newIndexFirstSegmentNum; + } representationHolder.segmentNumShift += segmentNumShift; representationHolder.segmentIndex = newIndex; } diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java index c7a3f2e517..77b187d464 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java @@ -217,11 +217,22 @@ public class SmoothStreamingChunkSource implements ChunkSource { SmoothStreamingManifest newManifest = manifestFetcher.getManifest(); if (currentManifest != newManifest && newManifest != null) { StreamElement currentElement = getElement(currentManifest); + int currentElementChunkCount = currentElement.chunkCount; StreamElement newElement = getElement(newManifest); - if (newElement.chunkCount == 0) { - currentManifestChunkOffset += currentElement.chunkCount; - } else if (currentElement.chunkCount > 0) { - currentManifestChunkOffset += currentElement.getChunkIndex(newElement.getStartTimeUs(0)); + if (currentElementChunkCount == 0 || newElement.chunkCount == 0) { + // There's no overlap between the old and new elements because at least one is empty. + currentManifestChunkOffset += currentElementChunkCount; + } else { + long currentElementEndTimeUs = currentElement.getStartTimeUs(currentElementChunkCount - 1) + + currentElement.getChunkDurationUs(currentElementChunkCount - 1); + long newElementStartTimeUs = newElement.getStartTimeUs(0); + if (currentElementEndTimeUs <= newElementStartTimeUs) { + // There's no overlap between the old and new elements. + currentManifestChunkOffset += currentElementChunkCount; + } else { + // The new element overlaps with the old one. + currentManifestChunkOffset += currentElement.getChunkIndex(newElementStartTimeUs); + } } currentManifest = newManifest; finishedCurrentManifest = false;