diff --git a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java index 7d77ae82d9..dfcb9e72a5 100644 --- a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java +++ b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java @@ -129,13 +129,13 @@ public class DashManifestTest extends TestCase { } private static void assertManifestEquals(DashManifest expected, DashManifest actual) { - assertEquals(expected.availabilityStartTime, actual.availabilityStartTime); - assertEquals(expected.duration, actual.duration); - assertEquals(expected.minBufferTime, actual.minBufferTime); + assertEquals(expected.availabilityStartTimeMs, actual.availabilityStartTimeMs); + assertEquals(expected.durationMs, actual.durationMs); + assertEquals(expected.minBufferTimeMs, actual.minBufferTimeMs); assertEquals(expected.dynamic, actual.dynamic); - assertEquals(expected.minUpdatePeriod, actual.minUpdatePeriod); - assertEquals(expected.timeShiftBufferDepth, actual.timeShiftBufferDepth); - assertEquals(expected.suggestedPresentationDelay, actual.suggestedPresentationDelay); + assertEquals(expected.minUpdatePeriodMs, actual.minUpdatePeriodMs); + assertEquals(expected.timeShiftBufferDepthMs, actual.timeShiftBufferDepthMs); + assertEquals(expected.suggestedPresentationDelayMs, actual.suggestedPresentationDelayMs); assertEquals(expected.utcTiming, actual.utcTiming); assertEquals(expected.location, actual.location); assertEquals(expected.getPeriodCount(), actual.getPeriodCount()); diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 02f928544b..a82b5af583 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -199,7 +199,7 @@ public final class DashMediaSource implements MediaSource { public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; /** * A constant indicating that the presentation delay for live streams should be set to - * {@link DashManifest#suggestedPresentationDelay} if specified by the manifest, or + * {@link DashManifest#suggestedPresentationDelayMs} if specified by the manifest, or * {@link #DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS} otherwise. The presentation delay is the * duration by which the default start position precedes the end of the live window. */ @@ -626,12 +626,12 @@ public final class DashMediaSource implements MediaSource { if (manifest.dynamic && !lastPeriodSeekInfo.isIndexExplicit) { // The manifest describes an incomplete live stream. Update the start/end times to reflect the // live stream duration and the manifest's time shift buffer depth. - long liveStreamDurationUs = getNowUnixTimeUs() - C.msToUs(manifest.availabilityStartTime); + long liveStreamDurationUs = getNowUnixTimeUs() - C.msToUs(manifest.availabilityStartTimeMs); long liveStreamEndPositionInLastPeriodUs = liveStreamDurationUs - C.msToUs(manifest.getPeriod(lastPeriodIndex).startMs); currentEndTimeUs = Math.min(liveStreamEndPositionInLastPeriodUs, currentEndTimeUs); - if (manifest.timeShiftBufferDepth != C.TIME_UNSET) { - long timeShiftBufferDepthUs = C.msToUs(manifest.timeShiftBufferDepth); + if (manifest.timeShiftBufferDepthMs != C.TIME_UNSET) { + long timeShiftBufferDepthUs = C.msToUs(manifest.timeShiftBufferDepthMs); long offsetInPeriodUs = currentEndTimeUs - timeShiftBufferDepthUs; int periodIndex = lastPeriodIndex; while (offsetInPeriodUs < 0 && periodIndex > 0) { @@ -655,8 +655,8 @@ public final class DashMediaSource implements MediaSource { if (manifest.dynamic) { long presentationDelayForManifestMs = livePresentationDelayMs; if (presentationDelayForManifestMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS) { - presentationDelayForManifestMs = manifest.suggestedPresentationDelay != C.TIME_UNSET - ? manifest.suggestedPresentationDelay : DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS; + presentationDelayForManifestMs = manifest.suggestedPresentationDelayMs != C.TIME_UNSET + ? manifest.suggestedPresentationDelayMs : DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS; } // Snap the default position to the start of the segment containing it. windowDefaultStartPositionUs = windowDurationUs - C.msToUs(presentationDelayForManifestMs); @@ -668,9 +668,9 @@ public final class DashMediaSource implements MediaSource { windowDurationUs / 2); } } - long windowStartTimeMs = manifest.availabilityStartTime + long windowStartTimeMs = manifest.availabilityStartTimeMs + manifest.getPeriod(0).startMs + C.usToMs(currentStartTimeUs); - DashTimeline timeline = new DashTimeline(manifest.availabilityStartTime, windowStartTimeMs, + DashTimeline timeline = new DashTimeline(manifest.availabilityStartTimeMs, windowStartTimeMs, firstPeriodId, currentStartTimeUs, windowDurationUs, windowDefaultStartPositionUs, manifest); sourceListener.onSourceInfoRefreshed(this, timeline, manifest); @@ -693,15 +693,15 @@ public final class DashMediaSource implements MediaSource { if (!manifest.dynamic) { return; } - long minUpdatePeriod = manifest.minUpdatePeriod; - if (minUpdatePeriod == 0) { + long minUpdatePeriodMs = manifest.minUpdatePeriodMs; + if (minUpdatePeriodMs == 0) { // TODO: This is a temporary hack to avoid constantly refreshing the MPD in cases where - // minUpdatePeriod is set to 0. In such cases we shouldn't refresh unless there is explicit - // signaling in the stream, according to: + // minimumUpdatePeriod is set to 0. In such cases we shouldn't refresh unless there is + // explicit signaling in the stream, according to: // http://azure.microsoft.com/blog/2014/09/13/dash-live-streaming-with-azure-media-service/ - minUpdatePeriod = 5000; + minUpdatePeriodMs = 5000; } - long nextLoadTimestamp = manifestLoadStartTimestamp + minUpdatePeriod; + long nextLoadTimestamp = manifestLoadStartTimestamp + minUpdatePeriodMs; long delayUntilNextLoad = Math.max(0, nextLoadTimestamp - SystemClock.elapsedRealtime()); handler.postDelayed(refreshManifestRunnable, delayUntilNextLoad); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index 66455b2f04..b254c4f09a 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -220,11 +220,11 @@ public class DefaultDashChunkSource implements DashChunkSource { if (availableSegmentCount == DashSegmentIndex.INDEX_UNBOUNDED) { // The index is itself unbounded. We need to use the current time to calculate the range of // available segments. - long liveEdgeTimeUs = getNowUnixTimeUs() - C.msToUs(manifest.availabilityStartTime); + long liveEdgeTimeUs = getNowUnixTimeUs() - C.msToUs(manifest.availabilityStartTimeMs); long periodStartUs = C.msToUs(manifest.getPeriod(periodIndex).startMs); long liveEdgeTimeInPeriodUs = liveEdgeTimeUs - periodStartUs; - if (manifest.timeShiftBufferDepth != C.TIME_UNSET) { - long bufferDepthUs = C.msToUs(manifest.timeShiftBufferDepth); + if (manifest.timeShiftBufferDepthMs != C.TIME_UNSET) { + long bufferDepthUs = C.msToUs(manifest.timeShiftBufferDepthMs); firstAvailableSegmentNum = Math.max(firstAvailableSegmentNum, representationHolder.getSegmentNum(liveEdgeTimeInPeriodUs - bufferDepthUs)); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java index 1ab94ccd30..cd24526d7c 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java @@ -23,41 +23,74 @@ import java.util.LinkedList; import java.util.List; /** - * Represents a DASH media presentation description (mpd). + * Represents a DASH media presentation description (mpd), as defined by ISO/IEC 23009-1:2014 + * Section 5.3.1.2. */ public class DashManifest { - public final long availabilityStartTime; + /** + * The {@code availabilityStartTime} value in milliseconds since epoch, or {@link C#TIME_UNSET} if + * not present. + */ + public final long availabilityStartTimeMs; - public final long duration; + /** + * The duration of the presentation in milliseconds, or {@link C#TIME_UNSET} if not applicable. + */ + public final long durationMs; - public final long minBufferTime; + /** + * The {@code minBufferTime} value in milliseconds, or {@link C#TIME_UNSET} if not present. + */ + public final long minBufferTimeMs; + /** + * Whether the manifest has value "dynamic" for the {@code type} attribute. + */ public final boolean dynamic; - public final long minUpdatePeriod; + /** + * The {@code minimumUpdatePeriod} value in milliseconds, or {@link C#TIME_UNSET} if not + * applicable. + */ + public final long minUpdatePeriodMs; - public final long timeShiftBufferDepth; + /** + * The {@code timeShiftBufferDepth} value in milliseconds, or {@link C#TIME_UNSET} if not + * present. + */ + public final long timeShiftBufferDepthMs; - public final long suggestedPresentationDelay; + /** + * The {@code suggestedPresentationDelay} value in milliseconds, or {@link C#TIME_UNSET} if not + * present. + */ + public final long suggestedPresentationDelayMs; + /** + * The {@link UtcTimingElement}, or null if not present. Defined in DVB A168:7/2016, Section + * 4.7.2. + */ public final UtcTimingElement utcTiming; + /** + * The location of this manifest. + */ public final Uri location; private final List periods; - public DashManifest(long availabilityStartTime, long duration, long minBufferTime, - boolean dynamic, long minUpdatePeriod, long timeShiftBufferDepth, - long suggestedPresentationDelay, UtcTimingElement utcTiming, Uri location, + public DashManifest(long availabilityStartTimeMs, long durationMs, long minBufferTimeMs, + boolean dynamic, long minUpdatePeriodMs, long timeShiftBufferDepthMs, + long suggestedPresentationDelayMs, UtcTimingElement utcTiming, Uri location, List periods) { - this.availabilityStartTime = availabilityStartTime; - this.duration = duration; - this.minBufferTime = minBufferTime; + this.availabilityStartTimeMs = availabilityStartTimeMs; + this.durationMs = durationMs; + this.minBufferTimeMs = minBufferTimeMs; this.dynamic = dynamic; - this.minUpdatePeriod = minUpdatePeriod; - this.timeShiftBufferDepth = timeShiftBufferDepth; - this.suggestedPresentationDelay = suggestedPresentationDelay; + this.minUpdatePeriodMs = minUpdatePeriodMs; + this.timeShiftBufferDepthMs = timeShiftBufferDepthMs; + this.suggestedPresentationDelayMs = suggestedPresentationDelayMs; this.utcTiming = utcTiming; this.location = location; this.periods = periods == null ? Collections.emptyList() : periods; @@ -73,7 +106,7 @@ public class DashManifest { public final long getPeriodDurationMs(int index) { return index == periods.size() - 1 - ? (duration == C.TIME_UNSET ? C.TIME_UNSET : (duration - periods.get(index).startMs)) + ? (durationMs == C.TIME_UNSET ? C.TIME_UNSET : (durationMs - periods.get(index).startMs)) : (periods.get(index + 1).startMs - periods.get(index).startMs); } @@ -112,10 +145,10 @@ public class DashManifest { copyPeriods.add(copiedPeriod); } } - long newDuration = duration != C.TIME_UNSET ? duration - shiftMs : C.TIME_UNSET; - return new DashManifest(availabilityStartTime, newDuration, minBufferTime, dynamic, - minUpdatePeriod, timeShiftBufferDepth, suggestedPresentationDelay, utcTiming, location, - copyPeriods); + long newDuration = durationMs != C.TIME_UNSET ? durationMs - shiftMs : C.TIME_UNSET; + return new DashManifest(availabilityStartTimeMs, newDuration, minBufferTimeMs, dynamic, + minUpdatePeriodMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, utcTiming, + location, copyPeriods); } private static ArrayList copyAdaptationSets(