diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 0461465672..b167597e16 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -53,7 +53,6 @@ import java.util.concurrent.CopyOnWriteArraySet; // Playback information when there is a pending seek/set source operation. private int maskingPeriodIndex; private long maskingPositionMs; - private long maskingDurationMs; /** * Constructs an instance. Must be called from a thread that has an associated {@link Looper}. @@ -142,11 +141,9 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public void seekTo(int periodIndex, long positionMs) { - boolean periodChanging = periodIndex != getCurrentPeriodIndex(); boolean seekToDefaultPosition = positionMs == ExoPlayer.UNKNOWN_TIME; maskingPeriodIndex = periodIndex; maskingPositionMs = seekToDefaultPosition ? 0 : positionMs; - maskingDurationMs = periodChanging ? ExoPlayer.UNKNOWN_TIME : getDuration(); pendingSeekAcks++; internalPlayer.seekTo(periodIndex, seekToDefaultPosition ? C.UNSET_TIME_US : positionMs * 1000); if (!seekToDefaultPosition) { @@ -184,12 +181,10 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public long getDuration() { - if (pendingSeekAcks == 0) { - long durationUs = playbackInfo.durationUs; - return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : durationUs / 1000; - } else { - return maskingDurationMs; + if (timeline == null) { + return UNKNOWN_TIME; } + return timeline.getPeriodDurationMs(getCurrentPeriodIndex()); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 5c76bc63a6..5a410b78ed 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -54,12 +54,10 @@ import java.io.IOException; public volatile long positionUs; public volatile long bufferedPositionUs; - public volatile long durationUs; public volatile long startPositionUs; public PlaybackInfo(int periodIndex) { this.periodIndex = periodIndex; - durationUs = C.UNSET_TIME_US; } } @@ -394,11 +392,6 @@ import java.io.IOException; } MediaPeriod mediaPeriod = playingPeriod.mediaPeriod; - // Update the duration. - if (playbackInfo.durationUs == C.UNSET_TIME_US) { - playbackInfo.durationUs = mediaPeriod.getDurationUs(); - } - // Update the playback position. long positionUs = mediaPeriod.readDiscontinuity(); if (positionUs != C.UNSET_TIME_US) { @@ -460,9 +453,10 @@ import java.io.IOException; maybeThrowPeriodPrepareError(); } + long playingPeriodDuration = timeline.getPeriodDurationUs(playingPeriod.index); if (allRenderersEnded - && (playbackInfo.durationUs == C.UNSET_TIME_US - || playbackInfo.durationUs <= playbackInfo.positionUs) + && (playingPeriodDuration == C.UNSET_TIME_US + || playingPeriodDuration <= playbackInfo.positionUs) && isTimelineEnded) { setState(ExoPlayer.STATE_ENDED); stopRenderers(); @@ -796,7 +790,7 @@ import java.io.IOException; if (loadingPeriod.isLast) { return true; } - bufferedPositionUs = loadingPeriod.mediaPeriod.getDurationUs(); + bufferedPositionUs = timeline.getPeriodDurationUs(loadingPeriod.index); } return loadControl.shouldStartPlayback(bufferedPositionUs - positionUs, rebuffering); } @@ -945,6 +939,8 @@ import java.io.IOException; newPeriod.isLast = timeline.isFinal() && periodIndex == timeline.getPeriodCount() - 1; if (loadingPeriod != null) { loadingPeriod.setNextPeriod(newPeriod); + newPeriod.offsetUs = loadingPeriod.offsetUs + + timeline.getPeriodDurationUs(loadingPeriod.index); } bufferAheadPeriodCount++; loadingPeriod = newPeriod; @@ -967,7 +963,7 @@ import java.io.IOException; // Update the playing and reading periods. if (playingPeriodEndPositionUs == C.UNSET_TIME_US && playingPeriod.isFullyBuffered()) { playingPeriodEndPositionUs = playingPeriod.offsetUs - + playingPeriod.mediaPeriod.getDurationUs(); + + timeline.getPeriodDurationUs(playingPeriod.index); } while (playingPeriod != readingPeriod && playingPeriod.nextPeriod != null && internalPositionUs >= playingPeriod.nextPeriod.offsetUs) { @@ -1198,7 +1194,6 @@ import java.io.IOException; public void setNextPeriod(Period nextPeriod) { this.nextPeriod = nextPeriod; - nextPeriod.offsetUs = offsetUs + mediaPeriod.getDurationUs(); } public boolean isFullyBuffered() { diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index f97b99b798..6987b18d70 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -148,10 +148,17 @@ public final class ConcatenatingMediaSource implements MediaSource { } @Override - public long getPeriodDuration(int index) { + public long getPeriodDurationMs(int index) { int sourceIndex = getSourceIndexForPeriod(index); int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex); - return timelines[sourceIndex].getPeriodDuration(index - firstPeriodIndexInSource); + return timelines[sourceIndex].getPeriodDurationMs(index - firstPeriodIndexInSource); + } + + @Override + public long getPeriodDurationUs(int index) { + int sourceIndex = getSourceIndexForPeriod(index); + int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex); + return timelines[sourceIndex].getPeriodDurationUs(index - firstPeriodIndexInSource); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index df9a6c9ce8..846bf8aea1 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -228,11 +228,6 @@ public final class ExtractorMediaSource implements MediaPeriod, MediaSource, maybeThrowError(); } - @Override - public long getDurationUs() { - return durationUs; - } - @Override public TrackGroupArray getTrackGroups() { return tracks; @@ -432,6 +427,9 @@ public final class ExtractorMediaSource implements MediaPeriod, MediaSource, long largestQueuedTimestampUs = getLargestQueuedTimestampUs(); durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0 : largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US; + sourceListener.onSourceInfoRefreshed(seekMap.isSeekable() + ? SinglePeriodTimeline.createSeekableFinalTimeline(this, durationUs) + : SinglePeriodTimeline.createUnseekableFinalTimeline(this, durationUs), null); } } diff --git a/library/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java index 422725bc8f..323d5d8864 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java @@ -66,19 +66,6 @@ public interface MediaPeriod extends SequenceableLoader { */ void maybeThrowPrepareError() throws IOException; - /** - * Returns the duration of the period in microseconds, or {@link C#UNSET_TIME_US} if not known. - *

- * If {@link #getBufferedPositionUs()} returns {@link C#END_OF_SOURCE_US}, the duration is - * guaranteed to be known. - *

- * This method should only be called after the period has been prepared. - * - * @return The duration of the period in microseconds, or {@link C#UNSET_TIME_US} if the duration - * is not known. - */ - long getDurationUs(); - /** * Returns the {@link TrackGroup}s exposed by the period. *

diff --git a/library/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java index 5ba321dd54..82029dd940 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java @@ -32,7 +32,6 @@ public final class MergingMediaPeriod implements MediaPeriod, MediaPeriod.Callba private Callback callback; private int pendingChildPrepareCount; - private long durationUs; private TrackGroupArray trackGroups; private MediaPeriod[] enabledPeriods; @@ -59,11 +58,6 @@ public final class MergingMediaPeriod implements MediaPeriod, MediaPeriod.Callba } } - @Override - public long getDurationUs() { - return durationUs; - } - @Override public TrackGroupArray getTrackGroups() { return trackGroups; @@ -194,15 +188,9 @@ public final class MergingMediaPeriod implements MediaPeriod, MediaPeriod.Callba if (--pendingChildPrepareCount > 0) { return; } - durationUs = 0; int totalTrackGroupCount = 0; for (MediaPeriod period : periods) { totalTrackGroupCount += period.getTrackGroups().length; - if (durationUs != C.UNSET_TIME_US) { - long periodDurationUs = period.getDurationUs(); - durationUs = periodDurationUs == C.UNSET_TIME_US - ? C.UNSET_TIME_US : Math.max(durationUs, periodDurationUs); - } } TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount]; int trackGroupIndex = 0; diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java b/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java index fa36d27b59..3e08c6ffa9 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.util.Assertions; /** @@ -52,7 +53,7 @@ public final class SinglePeriodTimeline implements Timeline { * @return A new, unseekable, final timeline with one period. */ public static Timeline createUnseekableFinalTimeline(Object id, long durationUs) { - return new SinglePeriodTimeline(id, true, durationUs / 1000, SeekWindow.UNSEEKABLE); + return new SinglePeriodTimeline(id, true, durationUs, SeekWindow.UNSEEKABLE); } /** @@ -64,19 +65,19 @@ public final class SinglePeriodTimeline implements Timeline { * @return A new, seekable, final timeline with one period. */ public static Timeline createSeekableFinalTimeline(Object id, long durationUs) { - return new SinglePeriodTimeline(id, true, durationUs / 1000, + return new SinglePeriodTimeline(id, true, durationUs, SeekWindow.createWindowFromZero(durationUs)); } private final Object id; private final boolean isFinal; - private final long durationMs; + private final long durationUs; private final SeekWindow seekWindow; - private SinglePeriodTimeline(Object id, boolean isFinal, long durationMs, SeekWindow seekWindow) { + private SinglePeriodTimeline(Object id, boolean isFinal, long durationUs, SeekWindow seekWindow) { this.id = Assertions.checkNotNull(id); this.isFinal = isFinal; - this.durationMs = durationMs; + this.durationUs = durationUs; this.seekWindow = seekWindow; } @@ -96,11 +97,19 @@ public final class SinglePeriodTimeline implements Timeline { } @Override - public long getPeriodDuration(int index) { + public long getPeriodDurationMs(int index) { if (index != 0) { throw new IndexOutOfBoundsException(); } - return durationMs; + return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : (durationUs / 1000); + } + + @Override + public long getPeriodDurationUs(int index) { + if (index != 0) { + throw new IndexOutOfBoundsException(); + } + return durationUs; } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java index 1f1d0c51db..099ceb9481 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java @@ -147,11 +147,6 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource, // Do nothing. } - @Override - public long getDurationUs() { - return durationUs; - } - @Override public TrackGroupArray getTrackGroups() { return tracks; diff --git a/library/src/main/java/com/google/android/exoplayer2/source/Timeline.java b/library/src/main/java/com/google/android/exoplayer2/source/Timeline.java index 0b344d38d5..940e671e51 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/Timeline.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/Timeline.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.source; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; /** @@ -50,7 +51,16 @@ public interface Timeline { * @param index The index of the period. * @return The duration of the period in milliseconds, or {@link ExoPlayer#UNKNOWN_TIME}. */ - long getPeriodDuration(int index); + long getPeriodDurationMs(int index); + + /** + * Returns the duration of the period at {@code index} in the timeline, in microseconds, or + * {@link C#UNSET_TIME_US} if not known. + * + * @param index The index of the period. + * @return The duration of the period in microseconds, or {@link C#UNSET_TIME_US}. + */ + long getPeriodDurationUs(int index); /** * Returns a unique identifier for the period at {@code index}, or {@code null} if the period at diff --git a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 8eee46afbf..03575037eb 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -54,7 +54,6 @@ import java.util.List; private Callback callback; private Allocator allocator; private DashManifest manifest; - private long durationUs; private int index; private Period period; @@ -69,7 +68,6 @@ import java.util.List; this.eventDispatcher = eventDispatcher; this.elapsedRealtimeOffset = elapsedRealtimeOffset; this.manifestLoaderErrorThrower = manifestLoaderErrorThrower; - durationUs = manifest.getPeriodDurationUs(index); period = manifest.getPeriod(index); trackGroups = buildTrackGroups(period); } @@ -77,7 +75,6 @@ import java.util.List; public void updateManifest(DashManifest manifest, int index) { this.manifest = manifest; this.index = index; - durationUs = manifest.getPeriodDurationUs(index); period = manifest.getPeriod(index); if (sampleStreams != null) { for (ChunkSampleStream sampleStream : sampleStreams) { @@ -107,11 +104,6 @@ import java.util.List; manifestLoaderErrorThrower.maybeThrowError(); } - @Override - public long getDurationUs() { - return durationUs; - } - @Override public TrackGroupArray getTrackGroups() { return trackGroups; diff --git a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index ec958994ed..74b6b73f5e 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -509,13 +509,21 @@ public final class DashMediaSource implements MediaSource { } @Override - public long getPeriodDuration(int index) { + public long getPeriodDurationMs(int index) { if (index < 0 || index >= manifest.getPeriodCount()) { throw new IndexOutOfBoundsException(); } return manifest.getPeriodDurationMs(index); } + @Override + public long getPeriodDurationUs(int index) { + if (index < 0 || index >= manifest.getPeriodCount()) { + throw new IndexOutOfBoundsException(); + } + return manifest.getPeriodDurationUs(index); + } + @Override public Object getPeriodId(int index) { if (index < 0 || index >= manifest.getPeriodCount()) { diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 1a84a42642..fd9aebdc1d 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -160,11 +160,6 @@ public final class HlsMediaSource implements MediaPeriod, MediaSource, } } - @Override - public long getDurationUs() { - return durationUs; - } - @Override public TrackGroupArray getTrackGroups() { return trackGroups; diff --git a/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index 018eb46dec..297fbe1151 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -98,11 +98,6 @@ import java.util.ArrayList; manifestLoaderErrorThrower.maybeThrowError(); } - @Override - public long getDurationUs() { - return manifest.durationUs; - } - @Override public TrackGroupArray getTrackGroups() { return trackGroups;