Commit 1a909fd1 by olly Committed by Oliver Woodman

Change SeekWindow -> Window, and add window duration.

- This avoids the need to have to use the timeline to
  calculate a window duration, which can be awkward.
- Window now represents a window of availability with
  an isSeekable flag, rather than a window of
  seekability.
- Promoted Timeline and Window to top package; they're
  pretty important :).

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=130278509
parent b120bea0
Showing with 150 additions and 151 deletions
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.ExoPlayer; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.StreamingDrmSessionManager; import com.google.android.exoplayer2.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer;
...@@ -33,7 +34,6 @@ import com.google.android.exoplayer2.metadata.id3.TextInformationFrame; ...@@ -33,7 +34,6 @@ import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.metadata.id3.TxxxFrame; import com.google.android.exoplayer2.metadata.id3.TxxxFrame;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
...@@ -94,11 +94,11 @@ import java.util.Locale; ...@@ -94,11 +94,11 @@ import java.util.Locale;
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
boolean isFinal = timeline.isFinal(); boolean isFinal = timeline.isFinal();
int periodCount = timeline.getPeriodCount(); int periodCount = timeline.getPeriodCount();
int seekWindowCount = timeline.getSeekWindowCount(); int windowCount = timeline.getWindowCount();
Log.d(TAG, "sourceInfo[isFinal=" + isFinal + ", startTime=" + timeline.getAbsoluteStartTime() Log.d(TAG, "sourceInfo[isFinal=" + isFinal + ", startTime=" + timeline.getAbsoluteStartTime()
+ ", periodCount=" + periodCount + ", seekWindows: " + seekWindowCount); + ", periodCount=" + periodCount + ", windows: " + windowCount);
for (int seekWindowIndex = 0; seekWindowIndex < seekWindowCount; seekWindowIndex++) { for (int windowIndex = 0; windowIndex < windowCount; windowIndex++) {
Log.d(TAG, " " + timeline.getSeekWindow(seekWindowIndex)); Log.d(TAG, " " + timeline.getWindow(windowIndex));
} }
Log.d(TAG, "]"); Log.d(TAG, "]");
} }
......
...@@ -41,6 +41,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; ...@@ -41,6 +41,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.StreamingDrmSessionManager; import com.google.android.exoplayer2.drm.StreamingDrmSessionManager;
...@@ -51,7 +52,6 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep ...@@ -51,7 +52,6 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep
import com.google.android.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.dash.DashMediaSource; import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
......
...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException; ...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
......
...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException; ...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
......
...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException; ...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
......
...@@ -17,7 +17,6 @@ package com.google.android.exoplayer2; ...@@ -17,7 +17,6 @@ package com.google.android.exoplayer2;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.Timeline;
/** /**
* An extensible media player exposing traditional high-level media player functionality, such as * An extensible media player exposing traditional high-level media player functionality, such as
......
...@@ -23,7 +23,6 @@ import android.util.Log; ...@@ -23,7 +23,6 @@ import android.util.Log;
import android.util.Pair; import android.util.Pair;
import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo; import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
......
...@@ -26,7 +26,6 @@ import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage; ...@@ -26,7 +26,6 @@ import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
......
...@@ -35,7 +35,6 @@ import com.google.android.exoplayer2.metadata.MetadataRenderer; ...@@ -35,7 +35,6 @@ import com.google.android.exoplayer2.metadata.MetadataRenderer;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder; import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
import com.google.android.exoplayer2.metadata.id3.Id3Frame; import com.google.android.exoplayer2.metadata.id3.Id3Frame;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.text.TextRenderer; import com.google.android.exoplayer2.text.TextRenderer;
import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
......
...@@ -13,10 +13,9 @@ ...@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.source.MediaSource.Listener;
import com.google.android.exoplayer2.ExoPlayer;
/** /**
* The player's timeline consisting of one or more periods. Instances are immutable. * The player's timeline consisting of one or more periods. Instances are immutable.
...@@ -87,15 +86,15 @@ public interface Timeline { ...@@ -87,15 +86,15 @@ public interface Timeline {
int getIndexOfPeriod(Object id); int getIndexOfPeriod(Object id);
/** /**
* Returns the number of seek windows that can be accessed via {@link #getSeekWindow(int)}. * Returns the number of windows that can be accessed via {@link #getWindow(int)}.
*/ */
int getSeekWindowCount(); int getWindowCount();
/** /**
* Returns the {@link SeekWindow} at {@code index}, which represents positions that can be seeked * Returns the {@link Window} at {@code index}, which represents positions that can be seeked
* to in the timeline. The seek windows may change when * to in the timeline. The windows may change when
* {@link MediaSource.Listener#onSourceInfoRefreshed(Timeline, Object)} is called. * {@link Listener#onSourceInfoRefreshed(Timeline, Object)} is called.
*/ */
SeekWindow getSeekWindow(int index); Window getWindow(int index);
} }
...@@ -13,27 +13,26 @@ ...@@ -13,27 +13,26 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2;
/** /**
* A window of times the player can seek to. * A window of available media. Instances are immutable.
*/ */
public final class SeekWindow { public final class Window {
public static final SeekWindow UNSEEKABLE = createWindowFromZero(0);
/** /**
* Creates a new {@link SeekWindow} containing times from zero up to {@code durationUs} in the * Creates a new {@link Window} containing times from zero up to {@code durationUs} in the first
* first period. * period.
* *
* @param durationUs The duration of the window, in microseconds. * @param durationUs The duration of the window, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
*/ */
public static SeekWindow createWindowFromZero(long durationUs) { public static Window createWindowFromZero(long durationUs, boolean isSeekable) {
return createWindow(0, 0, 0, durationUs); return createWindow(0, 0, 0, durationUs, durationUs, isSeekable);
} }
/** /**
* Creates a new {@link SeekWindow} representing the specified time range. * Creates a new {@link Window} representing the specified time range.
* *
* @param startPeriodIndex The index of the period containing the start of the window. * @param startPeriodIndex The index of the period containing the start of the window.
* @param startTimeUs The start time of the window in microseconds, relative to the start of the * @param startTimeUs The start time of the window in microseconds, relative to the start of the
...@@ -41,10 +40,15 @@ public final class SeekWindow { ...@@ -41,10 +40,15 @@ public final class SeekWindow {
* @param endPeriodIndex The index of the period containing the end of the window. * @param endPeriodIndex The index of the period containing the end of the window.
* @param endTimeUs The end time of the window in microseconds, relative to the start of the * @param endTimeUs The end time of the window in microseconds, relative to the start of the
* specified end period. * specified end period.
* @param durationUs The duration of the window in microseconds.
* @param isSeekable Whether seeking is supported within the window.
*/ */
public static SeekWindow createWindow(int startPeriodIndex, long startTimeUs, public static Window createWindow(int startPeriodIndex, long startTimeUs,
int endPeriodIndex, long endTimeUs) { int endPeriodIndex, long endTimeUs, long durationUs, boolean isSeekable) {
return new SeekWindow(startPeriodIndex, startTimeUs / 1000, endPeriodIndex, endTimeUs / 1000); return new Window(startPeriodIndex, startTimeUs / 1000, endPeriodIndex,
endTimeUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : (endTimeUs / 1000),
durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : (durationUs / 1000),
isSeekable);
} }
/** /**
...@@ -65,24 +69,35 @@ public final class SeekWindow { ...@@ -65,24 +69,35 @@ public final class SeekWindow {
* {@link #endPeriodIndex}, in milliseconds. * {@link #endPeriodIndex}, in milliseconds.
*/ */
public final long endTimeMs; public final long endTimeMs;
/**
* The duration of the window in milliseconds, or {@link C#UNSET_TIME_US} if unknown.
*/
public final long durationMs;
/**
* Whether it's possible to seek within the window.
*/
public final boolean isSeekable;
private SeekWindow(int startPeriodIndex, long startTimeMs, int endPeriodIndex, long endTimeMs) { private Window(int startPeriodIndex, long startTimeMs, int endPeriodIndex, long endTimeMs,
long durationMs, boolean isSeekable) {
this.startPeriodIndex = startPeriodIndex; this.startPeriodIndex = startPeriodIndex;
this.startTimeMs = startTimeMs; this.startTimeMs = startTimeMs;
this.endPeriodIndex = endPeriodIndex; this.endPeriodIndex = endPeriodIndex;
this.endTimeMs = endTimeMs; this.endTimeMs = endTimeMs;
this.durationMs = durationMs;
this.isSeekable = isSeekable;
} }
/** /**
* Returns a new seek window that is offset by the specified number of periods. * Returns a new window that is offset by the specified number of periods.
* *
* @param periodCount The number of periods to add to {@link #startPeriodIndex} and * @param periodCount The number of periods to add to {@link #startPeriodIndex} and
* {@link #endPeriodIndex} when constructing the copy. * {@link #endPeriodIndex} when constructing the copy.
* @return A new seek window that is offset by the specified number of periods. * @return A new window that is offset by the specified number of periods.
*/ */
public SeekWindow copyOffsetByPeriodCount(int periodCount) { public Window copyOffsetByPeriodCount(int periodCount) {
return new SeekWindow(startPeriodIndex + periodCount, startTimeMs, endPeriodIndex + periodCount, return new Window(startPeriodIndex + periodCount, startTimeMs, endPeriodIndex + periodCount,
endTimeMs); endTimeMs, durationMs, isSeekable);
} }
@Override @Override
...@@ -103,16 +118,18 @@ public final class SeekWindow { ...@@ -103,16 +118,18 @@ public final class SeekWindow {
if (obj == null || getClass() != obj.getClass()) { if (obj == null || getClass() != obj.getClass()) {
return false; return false;
} }
SeekWindow other = (SeekWindow) obj; Window other = (Window) obj;
return other.startPeriodIndex == startPeriodIndex return other.startPeriodIndex == startPeriodIndex
&& other.startTimeMs == startTimeMs && other.startTimeMs == startTimeMs
&& other.endPeriodIndex == endPeriodIndex && other.endPeriodIndex == endPeriodIndex
&& other.endTimeMs == endTimeMs; && other.endTimeMs == endTimeMs
&& other.durationMs == durationMs
&& other.isSeekable == isSeekable;
} }
@Override @Override
public String toString() { public String toString() {
return "SeekWindow[" + startPeriodIndex + ", " + startTimeMs + ", " + endPeriodIndex + ", " return "Window[" + startPeriodIndex + ", " + startTimeMs + ", " + endPeriodIndex + ", "
+ endTimeMs + "]"; + endTimeMs + "]";
} }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2.source;
import android.util.Pair; import android.util.Pair;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Window;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -130,21 +132,21 @@ public final class ConcatenatingMediaSource implements MediaSource { ...@@ -130,21 +132,21 @@ public final class ConcatenatingMediaSource implements MediaSource {
private final Timeline[] timelines; private final Timeline[] timelines;
private final boolean isFinal; private final boolean isFinal;
private final int[] sourceOffsets; private final int[] sourceOffsets;
private final SeekWindow[] seekWindows; private final Window[] windows;
public ConcatenatedTimeline(Timeline[] timelines) { public ConcatenatedTimeline(Timeline[] timelines) {
boolean isFinal = true; boolean isFinal = true;
int[] sourceOffsets = new int[timelines.length]; int[] sourceOffsets = new int[timelines.length];
int sourceOffset = 0; int sourceOffset = 0;
ArrayList<SeekWindow> concatenatedSeekWindows = new ArrayList<>(); ArrayList<Window> concatenatedWindows = new ArrayList<>();
for (int i = 0; i < timelines.length; i++) { for (int i = 0; i < timelines.length; i++) {
Timeline timeline = timelines[i]; Timeline timeline = timelines[i];
isFinal &= timeline.isFinal(); isFinal &= timeline.isFinal();
// Offset the seek windows so they are relative to the source. // Offset the windows so they are relative to the source.
int seekWindowCount = timeline.getSeekWindowCount(); int windowCount = timeline.getWindowCount();
for (int j = 0; j < seekWindowCount; j++) { for (int j = 0; j < windowCount; j++) {
SeekWindow sourceSeekWindow = timeline.getSeekWindow(j); Window sourceWindow = timeline.getWindow(j);
concatenatedSeekWindows.add(sourceSeekWindow.copyOffsetByPeriodCount(sourceOffset)); concatenatedWindows.add(sourceWindow.copyOffsetByPeriodCount(sourceOffset));
} }
sourceOffset += timeline.getPeriodCount(); sourceOffset += timeline.getPeriodCount();
sourceOffsets[i] = sourceOffset; sourceOffsets[i] = sourceOffset;
...@@ -152,7 +154,7 @@ public final class ConcatenatingMediaSource implements MediaSource { ...@@ -152,7 +154,7 @@ public final class ConcatenatingMediaSource implements MediaSource {
this.timelines = timelines; this.timelines = timelines;
this.isFinal = isFinal; this.isFinal = isFinal;
this.sourceOffsets = sourceOffsets; this.sourceOffsets = sourceOffsets;
seekWindows = concatenatedSeekWindows.toArray(new SeekWindow[concatenatedSeekWindows.size()]); windows = concatenatedWindows.toArray(new Window[concatenatedWindows.size()]);
} }
@Override @Override
...@@ -208,13 +210,13 @@ public final class ConcatenatingMediaSource implements MediaSource { ...@@ -208,13 +210,13 @@ public final class ConcatenatingMediaSource implements MediaSource {
} }
@Override @Override
public int getSeekWindowCount() { public int getWindowCount() {
return seekWindows.length; return windows.length;
} }
@Override @Override
public SeekWindow getSeekWindow(int index) { public Window getWindow(int index) {
return seekWindows[index]; return windows[index];
} }
private int getSourceIndexForPeriod(int periodIndex) { private int getSourceIndexForPeriod(int periodIndex) {
......
...@@ -297,9 +297,8 @@ import java.util.Arrays; ...@@ -297,9 +297,8 @@ import java.util.Arrays;
long largestQueuedTimestampUs = getLargestQueuedTimestampUs(); long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0 durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0
: largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US; : largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US;
sourceListener.onSourceInfoRefreshed(seekMap.isSeekable() sourceListener.onSourceInfoRefreshed(
? SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs) new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null);
: SinglePeriodTimeline.createUnseekableFinalTimeline(0, durationUs), null);
} }
} }
...@@ -382,9 +381,8 @@ import java.util.Arrays; ...@@ -382,9 +381,8 @@ import java.util.Arrays;
tracks = new TrackGroupArray(trackArray); tracks = new TrackGroupArray(trackArray);
prepared = true; prepared = true;
callback.onPrepared(this); callback.onPrepared(this);
sourceListener.onSourceInfoRefreshed(seekMap.isSeekable() sourceListener.onSourceInfoRefreshed(
? SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs) new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null);
: SinglePeriodTimeline.createUnseekableFinalTimeline(0, durationUs), null);
} }
private void copyLengthFromLoader(ExtractingLoadable loadable) { private void copyLengthFromLoader(ExtractingLoadable loadable) {
......
...@@ -19,9 +19,9 @@ import android.net.Uri; ...@@ -19,9 +19,9 @@ import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
...@@ -135,7 +135,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List ...@@ -135,7 +135,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List
@Override @Override
public void prepareSource(MediaSource.Listener listener) { public void prepareSource(MediaSource.Listener listener) {
sourceListener = listener; sourceListener = listener;
timeline = SinglePeriodTimeline.createNonFinalTimeline(0); timeline = new SinglePeriodTimeline(this, C.UNSET_TIME_US, false);
listener.onSourceInfoRefreshed(timeline, null); listener.onSourceInfoRefreshed(timeline, null);
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2.source;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import java.io.IOException; import java.io.IOException;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2.source;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
......
...@@ -17,68 +17,45 @@ package com.google.android.exoplayer2.source; ...@@ -17,68 +17,45 @@ package com.google.android.exoplayer2.source;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Window;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
/** /**
* A {@link Timeline} consisting of a single period and seek window. * A {@link Timeline} consisting of a single period and window.
*/ */
public final class SinglePeriodTimeline implements Timeline { public final class SinglePeriodTimeline implements Timeline {
/** private final Object id;
* Returns a new timeline with one period of unknown duration and an empty seek window. private final boolean isFinal;
* private final long durationUs;
* @param id The identifier for the period. private final Window window;
* @return A new timeline with one period of unknown duration.
*/
public static Timeline createNonFinalTimeline(Object id) {
return new SinglePeriodTimeline(id, false, C.UNSET_TIME_US, SeekWindow.UNSEEKABLE);
}
/**
* Returns a new timeline with one period of unknown duration and the specified seek window.
*
* @param id The identifier for the period.
* @param seekWindow The seek window.
* @return A new timeline with one period of unknown duration.
*/
public static Timeline createNonFinalTimeline(Object id, SeekWindow seekWindow) {
return new SinglePeriodTimeline(id, false, C.UNSET_TIME_US, seekWindow);
}
/** /**
* Creates a final timeline with one period of known duration and an empty seek window. * Creates a final timeline with one period of known duration and a window extending from
* zero to its duration.
* *
* @param id The identifier for the period. * @param id The identifier for the period.
* @param durationUs The duration of the period, in microseconds. * @param durationUs The duration of the period, in microseconds.
* @return A new, unseekable, final timeline with one period. * @param isSeekable Whether seeking is supported within the period.
*/ */
public static Timeline createUnseekableFinalTimeline(Object id, long durationUs) { public SinglePeriodTimeline(Object id, long durationUs, boolean isSeekable) {
return new SinglePeriodTimeline(id, true, durationUs, SeekWindow.UNSEEKABLE); this(id, durationUs, Window.createWindowFromZero(durationUs, isSeekable));
} }
/** /**
* Creates a final timeline with one period of known duration and a seek window extending from * Creates a final timeline with one period of known duration and a window extending from
* zero to its duration. * zero to its duration.
* *
* @param id The identifier for the period. * @param id The identifier for the period.
* @param durationUs The duration of the period, in microseconds. * @param durationUs The duration of the period, in microseconds.
* @return A new, seekable, final timeline with one period. * @param window The available window within the period.
*/ */
public static Timeline createSeekableFinalTimeline(Object id, long durationUs) { public SinglePeriodTimeline(Object id, long durationUs, Window window) {
return new SinglePeriodTimeline(id, true, durationUs,
SeekWindow.createWindowFromZero(durationUs));
}
private final Object id;
private final boolean isFinal;
private final long durationUs;
private final SeekWindow seekWindow;
private SinglePeriodTimeline(Object id, boolean isFinal, long durationUs, SeekWindow seekWindow) {
this.id = Assertions.checkNotNull(id); this.id = Assertions.checkNotNull(id);
this.isFinal = isFinal;
this.durationUs = durationUs; this.durationUs = durationUs;
this.seekWindow = seekWindow; this.window = window;
this.isFinal = true; // TODO: Remove.
} }
@Override @Override
...@@ -126,13 +103,13 @@ public final class SinglePeriodTimeline implements Timeline { ...@@ -126,13 +103,13 @@ public final class SinglePeriodTimeline implements Timeline {
} }
@Override @Override
public int getSeekWindowCount() { public int getWindowCount() {
return 1; return 1;
} }
@Override @Override
public SeekWindow getSeekWindow(int index) { public Window getWindow(int index) {
return seekWindow; return window;
} }
} }
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
...@@ -78,7 +79,7 @@ public final class SingleSampleMediaSource implements MediaSource { ...@@ -78,7 +79,7 @@ public final class SingleSampleMediaSource implements MediaSource {
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
this.eventListener = eventListener; this.eventListener = eventListener;
this.eventSourceId = eventSourceId; this.eventSourceId = eventSourceId;
timeline = SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs); timeline = new SinglePeriodTimeline(0, durationUs, true);
} }
// MediaSource implementation. // MediaSource implementation.
......
...@@ -22,13 +22,13 @@ import android.util.Log; ...@@ -22,13 +22,13 @@ import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Window;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SeekWindow;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest; import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser; import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
import com.google.android.exoplayer2.source.dash.manifest.Period; import com.google.android.exoplayer2.source.dash.manifest.Period;
...@@ -59,7 +59,7 @@ public final class DashMediaSource implements MediaSource { ...@@ -59,7 +59,7 @@ public final class DashMediaSource implements MediaSource {
/** /**
* The interval in milliseconds between invocations of * The interval in milliseconds between invocations of
* {@link MediaSource.Listener#onSourceInfoRefreshed(Timeline, Object)} when the source's * {@link MediaSource.Listener#onSourceInfoRefreshed(Timeline, Object)} when the source's
* {@link SeekWindow} is changing dynamically (for example, for incomplete live streams). * {@link Window} is changing dynamically (for example, for incomplete live streams).
*/ */
private static final int NOTIFY_MANIFEST_INTERVAL_MS = 5000; private static final int NOTIFY_MANIFEST_INTERVAL_MS = 5000;
/** /**
...@@ -89,7 +89,7 @@ public final class DashMediaSource implements MediaSource { ...@@ -89,7 +89,7 @@ public final class DashMediaSource implements MediaSource {
private long manifestLoadEndTimestamp; private long manifestLoadEndTimestamp;
private DashManifest manifest; private DashManifest manifest;
private Handler handler; private Handler handler;
private SeekWindow seekWindow; private Window window;
private long elapsedRealtimeOffsetMs; private long elapsedRealtimeOffsetMs;
private int firstPeriodId; private int firstPeriodId;
...@@ -151,20 +151,20 @@ public final class DashMediaSource implements MediaSource { ...@@ -151,20 +151,20 @@ public final class DashMediaSource implements MediaSource {
@Override @Override
public Position getDefaultStartPosition(int index) { public Position getDefaultStartPosition(int index) {
if (seekWindow == null) { if (window == null) {
return null; return null;
} }
if (index == 0 && manifest.dynamic) { if (index == 0 && manifest.dynamic) {
// The stream is live, so return a position a position offset from the live edge. // The stream is live, so return a position a position offset from the live edge.
int periodIndex = seekWindow.endPeriodIndex; int periodIndex = window.endPeriodIndex;
long positionMs = seekWindow.endTimeMs - LIVE_EDGE_OFFSET_MS; long positionMs = window.endTimeMs - LIVE_EDGE_OFFSET_MS;
while (positionMs < 0 && periodIndex > seekWindow.startPeriodIndex) { while (positionMs < 0 && periodIndex > window.startPeriodIndex) {
periodIndex--; periodIndex--;
positionMs += manifest.getPeriodDurationMs(periodIndex); positionMs += manifest.getPeriodDurationMs(periodIndex);
} }
positionMs = Math.max(positionMs, positionMs = Math.max(positionMs,
periodIndex == seekWindow.startPeriodIndex ? seekWindow.startTimeMs : 0); periodIndex == window.startPeriodIndex ? window.startTimeMs : 0);
return new Position(periodIndex, positionMs * 1000); return new Position(periodIndex, positionMs * 1000);
} }
return new Position(index, 0); return new Position(index, 0);
...@@ -370,7 +370,7 @@ public final class DashMediaSource implements MediaSource { ...@@ -370,7 +370,7 @@ public final class DashMediaSource implements MediaSource {
} }
private void refreshSourceInfo() { private void refreshSourceInfo() {
// Update the seek window. // Update the window.
int lastPeriodIndex = manifest.getPeriodCount() - 1; int lastPeriodIndex = manifest.getPeriodCount() - 1;
PeriodSeekInfo firstPeriodSeekInfo = PeriodSeekInfo.createPeriodSeekInfo(manifest.getPeriod(0), PeriodSeekInfo firstPeriodSeekInfo = PeriodSeekInfo.createPeriodSeekInfo(manifest.getPeriod(0),
manifest.getPeriodDurationUs(0)); manifest.getPeriodDurationUs(0));
...@@ -379,7 +379,7 @@ public final class DashMediaSource implements MediaSource { ...@@ -379,7 +379,7 @@ public final class DashMediaSource implements MediaSource {
long currentStartTimeUs; long currentStartTimeUs;
long currentEndTimeUs; long currentEndTimeUs;
if (manifest.dynamic && !lastPeriodSeekInfo.isIndexExplicit) { if (manifest.dynamic && !lastPeriodSeekInfo.isIndexExplicit) {
// The seek window is changing so post a Runnable to update it. // The window is changing so post a Runnable to update it.
handler.postDelayed(refreshSourceInfoRunnable, NOTIFY_MANIFEST_INTERVAL_MS); handler.postDelayed(refreshSourceInfoRunnable, NOTIFY_MANIFEST_INTERVAL_MS);
long minStartPositionUs = firstPeriodSeekInfo.availableStartTimeUs; long minStartPositionUs = firstPeriodSeekInfo.availableStartTimeUs;
...@@ -395,8 +395,13 @@ public final class DashMediaSource implements MediaSource { ...@@ -395,8 +395,13 @@ public final class DashMediaSource implements MediaSource {
currentStartTimeUs = firstPeriodSeekInfo.availableStartTimeUs; currentStartTimeUs = firstPeriodSeekInfo.availableStartTimeUs;
currentEndTimeUs = lastPeriodSeekInfo.availableEndTimeUs; currentEndTimeUs = lastPeriodSeekInfo.availableEndTimeUs;
} }
seekWindow = SeekWindow.createWindow(0, currentStartTimeUs, lastPeriodIndex, currentEndTimeUs); long windowDurationUs = currentEndTimeUs - currentStartTimeUs;
sourceListener.onSourceInfoRefreshed(new DashTimeline(firstPeriodId, manifest, seekWindow), for (int i = 0; i < manifest.getPeriodCount() - 1; i++) {
windowDurationUs += manifest.getPeriodDurationUs(i);
}
window = Window.createWindow(0, currentStartTimeUs, lastPeriodIndex, currentEndTimeUs,
windowDurationUs, true);
sourceListener.onSourceInfoRefreshed(new DashTimeline(firstPeriodId, manifest, window),
manifest); manifest);
} }
...@@ -481,12 +486,12 @@ public final class DashMediaSource implements MediaSource { ...@@ -481,12 +486,12 @@ public final class DashMediaSource implements MediaSource {
private final int firstPeriodId; private final int firstPeriodId;
private final DashManifest manifest; private final DashManifest manifest;
private final SeekWindow seekWindow; private final Window window;
public DashTimeline(int firstPeriodId, DashManifest manifest, SeekWindow seekWindow) { public DashTimeline(int firstPeriodId, DashManifest manifest, Window window) {
this.firstPeriodId = firstPeriodId; this.firstPeriodId = firstPeriodId;
this.manifest = manifest; this.manifest = manifest;
this.seekWindow = seekWindow; this.window = window;
} }
@Override @Override
...@@ -531,13 +536,13 @@ public final class DashMediaSource implements MediaSource { ...@@ -531,13 +536,13 @@ public final class DashMediaSource implements MediaSource {
} }
@Override @Override
public int getSeekWindowCount() { public int getWindowCount() {
return 1; return 1;
} }
@Override @Override
public SeekWindow getSeekWindow(int index) { public Window getWindow(int index) {
return seekWindow; return window;
} }
} }
......
...@@ -20,13 +20,13 @@ import android.text.TextUtils; ...@@ -20,13 +20,13 @@ import android.text.TextUtils;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.CompositeSequenceableLoader; import com.google.android.exoplayer2.source.CompositeSequenceableLoader;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
...@@ -280,10 +280,8 @@ import java.util.List; ...@@ -280,10 +280,8 @@ import java.util.List;
trackGroups = new TrackGroupArray(trackGroupArray); trackGroups = new TrackGroupArray(trackGroupArray);
callback.onPrepared(this); callback.onPrepared(this);
// TODO[playlists]: Calculate the seek window. // TODO[playlists]: Calculate the window.
Timeline timeline = isLive Timeline timeline = new SinglePeriodTimeline(0, durationUs, !isLive);
? SinglePeriodTimeline.createUnseekableFinalTimeline(0, durationUs)
: SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs);
sourceListener.onSourceInfoRefreshed(timeline, playlist); sourceListener.onSourceInfoRefreshed(timeline, playlist);
} }
......
...@@ -17,13 +17,14 @@ package com.google.android.exoplayer2.source.hls; ...@@ -17,13 +17,14 @@ package com.google.android.exoplayer2.source.hls;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
...@@ -62,9 +63,10 @@ public final class HlsMediaSource implements MediaSource { ...@@ -62,9 +63,10 @@ public final class HlsMediaSource implements MediaSource {
@Override @Override
public void prepareSource(MediaSource.Listener listener) { public void prepareSource(MediaSource.Listener listener) {
// TODO: Defer until the playlist has been loaded.
sourceListener = listener; sourceListener = listener;
listener.onSourceInfoRefreshed(SinglePeriodTimeline.createNonFinalTimeline(this), null); // TODO: Defer until the playlist has been loaded.
listener.onSourceInfoRefreshed(
new SinglePeriodTimeline(this, C.UNSET_TIME_US, false), null);
} }
@Override @Override
......
...@@ -20,14 +20,14 @@ import android.os.Handler; ...@@ -20,14 +20,14 @@ import android.os.Handler;
import android.os.SystemClock; import android.os.SystemClock;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Window;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriod.Callback; import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SeekWindow;
import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser; import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser;
...@@ -72,7 +72,7 @@ public final class SsMediaSource implements MediaSource, ...@@ -72,7 +72,7 @@ public final class SsMediaSource implements MediaSource,
private long manifestLoadStartTimestamp; private long manifestLoadStartTimestamp;
private SsManifest manifest; private SsManifest manifest;
private SeekWindow seekWindow; private Window window;
private Handler manifestRefreshHandler; private Handler manifestRefreshHandler;
...@@ -114,12 +114,12 @@ public final class SsMediaSource implements MediaSource, ...@@ -114,12 +114,12 @@ public final class SsMediaSource implements MediaSource,
@Override @Override
public Position getDefaultStartPosition(int index) { public Position getDefaultStartPosition(int index) {
if (seekWindow == null) { if (window == null) {
return null; return null;
} }
if (manifest.isLive) { if (manifest.isLive) {
long startPositionUs = Math.max(seekWindow.startTimeMs, long startPositionUs = Math.max(window.startTimeMs,
seekWindow.endTimeMs - LIVE_EDGE_OFFSET_MS) * 1000; window.endTimeMs - LIVE_EDGE_OFFSET_MS) * 1000;
return new Position(0, startPositionUs); return new Position(0, startPositionUs);
} }
return Position.DEFAULT; return Position.DEFAULT;
...@@ -183,18 +183,20 @@ public final class SsMediaSource implements MediaSource, ...@@ -183,18 +183,20 @@ public final class SsMediaSource implements MediaSource,
startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0)); startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0));
} }
} }
if (startTimeUs == Long.MAX_VALUE) { if (startTimeUs == Long.MAX_VALUE || manifest.dvrWindowLengthUs == C.UNSET_TIME_US
timeline = SinglePeriodTimeline.createNonFinalTimeline(this); || manifest.dvrWindowLengthUs == 0) {
timeline = new SinglePeriodTimeline(0, C.UNSET_TIME_US, false);
} else { } else {
timeline = SinglePeriodTimeline.createNonFinalTimeline(this, long periodDurationUs = startTimeUs + manifest.dvrWindowLengthUs;
SeekWindow.createWindow(0, startTimeUs, 0, startTimeUs + manifest.dvrWindowLengthUs)); Window window = Window.createWindow(0, startTimeUs, 0, periodDurationUs,
manifest.dvrWindowLengthUs, true);
timeline = new SinglePeriodTimeline(0, periodDurationUs, window);
} }
} else if (manifest.durationUs == C.UNSET_TIME_US) {
timeline = SinglePeriodTimeline.createUnseekableFinalTimeline(0, C.UNSET_TIME_US);
} else { } else {
timeline = SinglePeriodTimeline.createSeekableFinalTimeline(0, manifest.durationUs); boolean isSeekable = manifest.durationUs != C.UNSET_TIME_US;
timeline = new SinglePeriodTimeline(0, manifest.durationUs, isSeekable);
} }
seekWindow = timeline.getSeekWindow(0); window = timeline.getWindow(0);
sourceListener.onSourceInfoRefreshed(timeline, manifest); sourceListener.onSourceInfoRefreshed(timeline, manifest);
scheduleManifestRefresh(); scheduleManifestRefresh();
} }
......
...@@ -20,8 +20,8 @@ import com.google.android.exoplayer2.ExoPlaybackException; ...@@ -20,8 +20,8 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.source.Timeline;
/** /**
* A helper class for periodically updating a {@link TextView} with debug information obtained from * A helper class for periodically updating a {@link TextView} with debug information obtained from
......
...@@ -25,12 +25,12 @@ import com.google.android.exoplayer2.ExoPlayer; ...@@ -25,12 +25,12 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioTrack; import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.playbacktests.util.HostActivity.HostedTest; import com.google.android.exoplayer2.playbacktests.util.HostActivity.HostedTest;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.AdaptiveVideoTrackSelection; import com.google.android.exoplayer2.trackselection.AdaptiveVideoTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment