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;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer2.metadata.MetadataRenderer;
......@@ -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.source.AdaptiveMediaSourceEventListener;
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.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
......@@ -94,11 +94,11 @@ import java.util.Locale;
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
boolean isFinal = timeline.isFinal();
int periodCount = timeline.getPeriodCount();
int seekWindowCount = timeline.getSeekWindowCount();
int windowCount = timeline.getWindowCount();
Log.d(TAG, "sourceInfo[isFinal=" + isFinal + ", startTime=" + timeline.getAbsoluteStartTime()
+ ", periodCount=" + periodCount + ", seekWindows: " + seekWindowCount);
for (int seekWindowIndex = 0; seekWindowIndex < seekWindowCount; seekWindowIndex++) {
Log.d(TAG, " " + timeline.getSeekWindow(seekWindowIndex));
+ ", periodCount=" + periodCount + ", windows: " + windowCount);
for (int windowIndex = 0; windowIndex < windowCount; windowIndex++) {
Log.d(TAG, " " + timeline.getWindow(windowIndex));
}
Log.d(TAG, "]");
}
......
......@@ -41,6 +41,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
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.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.StreamingDrmSessionManager;
......@@ -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.ExtractorMediaSource;
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.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
......
......@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
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.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
......
......@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
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.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
......
......@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
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.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.Timeline;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
......
......@@ -17,7 +17,6 @@ package com.google.android.exoplayer2;
import com.google.android.exoplayer2.source.MediaPeriod;
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
......
......@@ -23,7 +23,6 @@ import android.util.Log;
import android.util.Pair;
import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo;
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.util.Assertions;
import java.util.concurrent.CopyOnWriteArraySet;
......
......@@ -26,7 +26,6 @@ import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource;
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.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
......
......@@ -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.Id3Frame;
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.TextRenderer;
import com.google.android.exoplayer2.trackselection.TrackSelector;
......
......@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* 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.ExoPlayer;
import com.google.android.exoplayer2.source.MediaSource.Listener;
/**
* The player's timeline consisting of one or more periods. Instances are immutable.
......@@ -87,15 +86,15 @@ public interface Timeline {
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
* to in the timeline. The seek windows may change when
* {@link MediaSource.Listener#onSourceInfoRefreshed(Timeline, Object)} is called.
* Returns the {@link Window} at {@code index}, which represents positions that can be seeked
* to in the timeline. The windows may change when
* {@link Listener#onSourceInfoRefreshed(Timeline, Object)} is called.
*/
SeekWindow getSeekWindow(int index);
Window getWindow(int index);
}
......@@ -13,27 +13,26 @@
* See the License for the specific language governing permissions and
* 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 static final SeekWindow UNSEEKABLE = createWindowFromZero(0);
public final class Window {
/**
* Creates a new {@link SeekWindow} containing times from zero up to {@code durationUs} in the
* first period.
* Creates a new {@link Window} containing times from zero up to {@code durationUs} in the first
* period.
*
* @param durationUs The duration of the window, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
*/
public static SeekWindow createWindowFromZero(long durationUs) {
return createWindow(0, 0, 0, durationUs);
public static Window createWindowFromZero(long durationUs, boolean isSeekable) {
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 startTimeUs The start time of the window in microseconds, relative to the start of the
......@@ -41,10 +40,15 @@ public final class SeekWindow {
* @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
* 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,
int endPeriodIndex, long endTimeUs) {
return new SeekWindow(startPeriodIndex, startTimeUs / 1000, endPeriodIndex, endTimeUs / 1000);
public static Window createWindow(int startPeriodIndex, long startTimeUs,
int endPeriodIndex, long endTimeUs, long durationUs, boolean isSeekable) {
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 {
* {@link #endPeriodIndex}, in milliseconds.
*/
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.startTimeMs = startTimeMs;
this.endPeriodIndex = endPeriodIndex;
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
* {@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) {
return new SeekWindow(startPeriodIndex + periodCount, startTimeMs, endPeriodIndex + periodCount,
endTimeMs);
public Window copyOffsetByPeriodCount(int periodCount) {
return new Window(startPeriodIndex + periodCount, startTimeMs, endPeriodIndex + periodCount,
endTimeMs, durationMs, isSeekable);
}
@Override
......@@ -103,16 +118,18 @@ public final class SeekWindow {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
SeekWindow other = (SeekWindow) obj;
Window other = (Window) obj;
return other.startPeriodIndex == startPeriodIndex
&& other.startTimeMs == startTimeMs
&& other.endPeriodIndex == endPeriodIndex
&& other.endTimeMs == endTimeMs;
&& other.endTimeMs == endTimeMs
&& other.durationMs == durationMs
&& other.isSeekable == isSeekable;
}
@Override
public String toString() {
return "SeekWindow[" + startPeriodIndex + ", " + startTimeMs + ", " + endPeriodIndex + ", "
return "Window[" + startPeriodIndex + ", " + startTimeMs + ", " + endPeriodIndex + ", "
+ endTimeMs + "]";
}
......
......@@ -16,6 +16,8 @@
package com.google.android.exoplayer2.source;
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.upstream.Allocator;
import com.google.android.exoplayer2.util.Util;
......@@ -130,21 +132,21 @@ public final class ConcatenatingMediaSource implements MediaSource {
private final Timeline[] timelines;
private final boolean isFinal;
private final int[] sourceOffsets;
private final SeekWindow[] seekWindows;
private final Window[] windows;
public ConcatenatedTimeline(Timeline[] timelines) {
boolean isFinal = true;
int[] sourceOffsets = new int[timelines.length];
int sourceOffset = 0;
ArrayList<SeekWindow> concatenatedSeekWindows = new ArrayList<>();
ArrayList<Window> concatenatedWindows = new ArrayList<>();
for (int i = 0; i < timelines.length; i++) {
Timeline timeline = timelines[i];
isFinal &= timeline.isFinal();
// Offset the seek windows so they are relative to the source.
int seekWindowCount = timeline.getSeekWindowCount();
for (int j = 0; j < seekWindowCount; j++) {
SeekWindow sourceSeekWindow = timeline.getSeekWindow(j);
concatenatedSeekWindows.add(sourceSeekWindow.copyOffsetByPeriodCount(sourceOffset));
// Offset the windows so they are relative to the source.
int windowCount = timeline.getWindowCount();
for (int j = 0; j < windowCount; j++) {
Window sourceWindow = timeline.getWindow(j);
concatenatedWindows.add(sourceWindow.copyOffsetByPeriodCount(sourceOffset));
}
sourceOffset += timeline.getPeriodCount();
sourceOffsets[i] = sourceOffset;
......@@ -152,7 +154,7 @@ public final class ConcatenatingMediaSource implements MediaSource {
this.timelines = timelines;
this.isFinal = isFinal;
this.sourceOffsets = sourceOffsets;
seekWindows = concatenatedSeekWindows.toArray(new SeekWindow[concatenatedSeekWindows.size()]);
windows = concatenatedWindows.toArray(new Window[concatenatedWindows.size()]);
}
@Override
......@@ -208,13 +210,13 @@ public final class ConcatenatingMediaSource implements MediaSource {
}
@Override
public int getSeekWindowCount() {
return seekWindows.length;
public int getWindowCount() {
return windows.length;
}
@Override
public SeekWindow getSeekWindow(int index) {
return seekWindows[index];
public Window getWindow(int index) {
return windows[index];
}
private int getSourceIndexForPeriod(int periodIndex) {
......
......@@ -297,9 +297,8 @@ import java.util.Arrays;
long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0
: largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US;
sourceListener.onSourceInfoRefreshed(seekMap.isSeekable()
? SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs)
: SinglePeriodTimeline.createUnseekableFinalTimeline(0, durationUs), null);
sourceListener.onSourceInfoRefreshed(
new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null);
}
}
......@@ -382,9 +381,8 @@ import java.util.Arrays;
tracks = new TrackGroupArray(trackArray);
prepared = true;
callback.onPrepared(this);
sourceListener.onSourceInfoRefreshed(seekMap.isSeekable()
? SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs)
: SinglePeriodTimeline.createUnseekableFinalTimeline(0, durationUs), null);
sourceListener.onSourceInfoRefreshed(
new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null);
}
private void copyLengthFromLoader(ExtractingLoadable loadable) {
......
......@@ -19,9 +19,9 @@ import android.net.Uri;
import android.os.Handler;
import com.google.android.exoplayer2.C;
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.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.upstream.Allocator;
......@@ -135,7 +135,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List
@Override
public void prepareSource(MediaSource.Listener listener) {
sourceListener = listener;
timeline = SinglePeriodTimeline.createNonFinalTimeline(0);
timeline = new SinglePeriodTimeline(this, C.UNSET_TIME_US, false);
listener.onSourceInfoRefreshed(timeline, null);
}
......
......@@ -15,6 +15,7 @@
*/
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.upstream.Allocator;
import java.io.IOException;
......
......@@ -15,6 +15,7 @@
*/
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.upstream.Allocator;
import com.google.android.exoplayer2.util.Assertions;
......
......@@ -17,68 +17,45 @@ package com.google.android.exoplayer2.source;
import com.google.android.exoplayer2.C;
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;
/**
* 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 {
/**
* Returns a new timeline with one period of unknown duration and an empty seek window.
*
* @param id The identifier for the period.
* @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);
}
private final Object id;
private final boolean isFinal;
private final long durationUs;
private final Window window;
/**
* 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 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) {
return new SinglePeriodTimeline(id, true, durationUs, SeekWindow.UNSEEKABLE);
public SinglePeriodTimeline(Object id, long durationUs, boolean isSeekable) {
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.
*
* @param id The identifier for the period.
* @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) {
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) {
public SinglePeriodTimeline(Object id, long durationUs, Window window) {
this.id = Assertions.checkNotNull(id);
this.isFinal = isFinal;
this.durationUs = durationUs;
this.seekWindow = seekWindow;
this.window = window;
this.isFinal = true; // TODO: Remove.
}
@Override
......@@ -126,13 +103,13 @@ public final class SinglePeriodTimeline implements Timeline {
}
@Override
public int getSeekWindowCount() {
public int getWindowCount() {
return 1;
}
@Override
public SeekWindow getSeekWindow(int index) {
return seekWindow;
public Window getWindow(int index) {
return window;
}
}
......@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source;
import android.net.Uri;
import android.os.Handler;
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.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSource;
......@@ -78,7 +79,7 @@ public final class SingleSampleMediaSource implements MediaSource {
this.eventHandler = eventHandler;
this.eventListener = eventListener;
this.eventSourceId = eventSourceId;
timeline = SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs);
timeline = new SinglePeriodTimeline(0, durationUs, true);
}
// MediaSource implementation.
......
......@@ -22,13 +22,13 @@ import android.util.Log;
import android.util.SparseArray;
import com.google.android.exoplayer2.C;
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.EventDispatcher;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriod.Callback;
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.DashManifestParser;
import com.google.android.exoplayer2.source.dash.manifest.Period;
......@@ -59,7 +59,7 @@ public final class DashMediaSource implements MediaSource {
/**
* The interval in milliseconds between invocations of
* {@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;
/**
......@@ -89,7 +89,7 @@ public final class DashMediaSource implements MediaSource {
private long manifestLoadEndTimestamp;
private DashManifest manifest;
private Handler handler;
private SeekWindow seekWindow;
private Window window;
private long elapsedRealtimeOffsetMs;
private int firstPeriodId;
......@@ -151,20 +151,20 @@ public final class DashMediaSource implements MediaSource {
@Override
public Position getDefaultStartPosition(int index) {
if (seekWindow == null) {
if (window == null) {
return null;
}
if (index == 0 && manifest.dynamic) {
// The stream is live, so return a position a position offset from the live edge.
int periodIndex = seekWindow.endPeriodIndex;
long positionMs = seekWindow.endTimeMs - LIVE_EDGE_OFFSET_MS;
while (positionMs < 0 && periodIndex > seekWindow.startPeriodIndex) {
int periodIndex = window.endPeriodIndex;
long positionMs = window.endTimeMs - LIVE_EDGE_OFFSET_MS;
while (positionMs < 0 && periodIndex > window.startPeriodIndex) {
periodIndex--;
positionMs += manifest.getPeriodDurationMs(periodIndex);
}
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(index, 0);
......@@ -370,7 +370,7 @@ public final class DashMediaSource implements MediaSource {
}
private void refreshSourceInfo() {
// Update the seek window.
// Update the window.
int lastPeriodIndex = manifest.getPeriodCount() - 1;
PeriodSeekInfo firstPeriodSeekInfo = PeriodSeekInfo.createPeriodSeekInfo(manifest.getPeriod(0),
manifest.getPeriodDurationUs(0));
......@@ -379,7 +379,7 @@ public final class DashMediaSource implements MediaSource {
long currentStartTimeUs;
long currentEndTimeUs;
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);
long minStartPositionUs = firstPeriodSeekInfo.availableStartTimeUs;
......@@ -395,8 +395,13 @@ public final class DashMediaSource implements MediaSource {
currentStartTimeUs = firstPeriodSeekInfo.availableStartTimeUs;
currentEndTimeUs = lastPeriodSeekInfo.availableEndTimeUs;
}
seekWindow = SeekWindow.createWindow(0, currentStartTimeUs, lastPeriodIndex, currentEndTimeUs);
sourceListener.onSourceInfoRefreshed(new DashTimeline(firstPeriodId, manifest, seekWindow),
long windowDurationUs = currentEndTimeUs - currentStartTimeUs;
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);
}
......@@ -481,12 +486,12 @@ public final class DashMediaSource implements MediaSource {
private final int firstPeriodId;
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.manifest = manifest;
this.seekWindow = seekWindow;
this.window = window;
}
@Override
......@@ -531,13 +536,13 @@ public final class DashMediaSource implements MediaSource {
}
@Override
public int getSeekWindowCount() {
public int getWindowCount() {
return 1;
}
@Override
public SeekWindow getSeekWindow(int index) {
return seekWindow;
public Window getWindow(int index) {
return window;
}
}
......
......@@ -20,13 +20,13 @@ import android.text.TextUtils;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
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.CompositeSequenceableLoader;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SampleStream;
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.TrackGroupArray;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
......@@ -280,10 +280,8 @@ import java.util.List;
trackGroups = new TrackGroupArray(trackGroupArray);
callback.onPrepared(this);
// TODO[playlists]: Calculate the seek window.
Timeline timeline = isLive
? SinglePeriodTimeline.createUnseekableFinalTimeline(0, durationUs)
: SinglePeriodTimeline.createSeekableFinalTimeline(0, durationUs);
// TODO[playlists]: Calculate the window.
Timeline timeline = new SinglePeriodTimeline(0, durationUs, !isLive);
sourceListener.onSourceInfoRefreshed(timeline, playlist);
}
......
......@@ -17,13 +17,14 @@ package com.google.android.exoplayer2.source.hls;
import android.net.Uri;
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.EventDispatcher;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.source.MediaSource;
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.DataSource;
import com.google.android.exoplayer2.util.Assertions;
......@@ -62,9 +63,10 @@ public final class HlsMediaSource implements MediaSource {
@Override
public void prepareSource(MediaSource.Listener listener) {
// TODO: Defer until the playlist has been loaded.
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
......
......@@ -20,14 +20,14 @@ import android.os.Handler;
import android.os.SystemClock;
import com.google.android.exoplayer2.C;
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.EventDispatcher;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriod.Callback;
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.Timeline;
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.SsManifestParser;
......@@ -72,7 +72,7 @@ public final class SsMediaSource implements MediaSource,
private long manifestLoadStartTimestamp;
private SsManifest manifest;
private SeekWindow seekWindow;
private Window window;
private Handler manifestRefreshHandler;
......@@ -114,12 +114,12 @@ public final class SsMediaSource implements MediaSource,
@Override
public Position getDefaultStartPosition(int index) {
if (seekWindow == null) {
if (window == null) {
return null;
}
if (manifest.isLive) {
long startPositionUs = Math.max(seekWindow.startTimeMs,
seekWindow.endTimeMs - LIVE_EDGE_OFFSET_MS) * 1000;
long startPositionUs = Math.max(window.startTimeMs,
window.endTimeMs - LIVE_EDGE_OFFSET_MS) * 1000;
return new Position(0, startPositionUs);
}
return Position.DEFAULT;
......@@ -183,18 +183,20 @@ public final class SsMediaSource implements MediaSource,
startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0));
}
}
if (startTimeUs == Long.MAX_VALUE) {
timeline = SinglePeriodTimeline.createNonFinalTimeline(this);
if (startTimeUs == Long.MAX_VALUE || manifest.dvrWindowLengthUs == C.UNSET_TIME_US
|| manifest.dvrWindowLengthUs == 0) {
timeline = new SinglePeriodTimeline(0, C.UNSET_TIME_US, false);
} else {
timeline = SinglePeriodTimeline.createNonFinalTimeline(this,
SeekWindow.createWindow(0, startTimeUs, 0, startTimeUs + manifest.dvrWindowLengthUs));
long periodDurationUs = 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 {
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);
scheduleManifestRefresh();
}
......
......@@ -20,8 +20,8 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
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
......
......@@ -25,12 +25,12 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.playbacktests.util.HostActivity.HostedTest;
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.DefaultTrackSelector;
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