/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.exoplayer2; /** * A representation of media currently available for playback. *

* Timeline instances are immutable. For cases where the available media is changing dynamically * (e.g. live streams) a timeline provides a snapshot of the media currently available. *

* A timeline consists of related {@link Period}s and {@link Window}s. A period defines a single * logical piece of media, for example a media file. A window spans one or more periods, defining * the region within those periods that's currently available for playback along with additional * information such as whether seeking is supported within the window. Each window defines a default * position, which is the position from which playback will start when the player starts playing the * window. The following examples illustrate timelines for various use cases. * *

Single media file or on-demand stream

*

* Example timeline for a single file *

* A timeline for a single media file or on-demand stream consists of a single period and window. * The window spans the whole period, indicating that all parts of the media are available for * playback. The window's default position is typically at the start of the period (indicated by the * black dot in the figure above). * *

Playlist of media files or on-demand streams

*

* Example timeline for a playlist of files *

* A timeline for a playlist of media files or on-demand streams consists of multiple periods, each * with its own window. Each window spans the whole of the corresponding period, and typically has a * default position at the start of the period. The properties of the periods and windows (e.g. * their durations and whether the window is seekable) will often only become known when the player * starts buffering the corresponding file or stream. * *

Live stream with limited availability

*

* Example timeline for a live stream with
 *       limited availability *

* A timeline for a live stream consists of a period whose duration is unknown, since it's * continually extending as more content is broadcast. If content only remains available for a * limited period of time then the window may start at a non-zero position, defining the region of * content that can still be played. The window will have {@link Window#isDynamic} set to true if * the stream is still live. Its default position is typically near to the live edge (indicated by * the black dot in the figure above). * *

Live stream with indefinite availability

*

* Example timeline for a live stream with
 *       indefinite availability *

* A timeline for a live stream with indefinite availability is similar to the * Live stream with limited availability case, except that the window * starts at the beginning of the period to indicate that all of the previously broadcast content * can still be played. * *

Live stream with multiple periods

*

* Example timeline for a live stream
 *       with multiple periods *

* This case arises when a live stream is explicitly divided into separate periods, for example at * content and advert boundaries. This case is similar to the Live stream * with limited availability case, except that the window may span more than one period. * Multiple periods are also possible in the indefinite availability case. * *

On-demand pre-roll followed by live stream

*

* Example timeline for an on-demand pre-roll
 *       followed by a live stream *

* This case is the concatenation of the Single media file or on-demand * stream and Live stream with multiple periods cases. When playback * of the pre-roll ends, playback of the live stream will start from its default position near the * live edge. */ public abstract class Timeline { /** * An empty timeline. */ public static final Timeline EMPTY = new Timeline() { @Override public int getWindowCount() { return 0; } @Override public Window getWindow(int windowIndex, Window window, boolean setIds, long defaultPositionProjectionUs) { throw new IndexOutOfBoundsException(); } @Override public int getPeriodCount() { return 0; } @Override public Period getPeriod(int periodIndex, Period period, boolean setIds) { throw new IndexOutOfBoundsException(); } @Override public int getIndexOfPeriod(Object uid) { return C.INDEX_UNSET; } }; /** * Returns whether the timeline is empty. */ public final boolean isEmpty() { return getWindowCount() == 0; } /** * Returns the number of windows in the timeline. */ public abstract int getWindowCount(); /** * Populates a {@link Window} with data for the window at the specified index. Does not populate * {@link Window#id}. * * @param windowIndex The index of the window. * @param window The {@link Window} to populate. Must not be null. * @return The populated {@link Window}, for convenience. */ public final Window getWindow(int windowIndex, Window window) { return getWindow(windowIndex, window, false); } /** * Populates a {@link Window} with data for the window at the specified index. * * @param windowIndex The index of the window. * @param window The {@link Window} to populate. Must not be null. * @param setIds Whether {@link Window#id} should be populated. If false, the field will be set to * null. The caller should pass false for efficiency reasons unless the field is required. * @return The populated {@link Window}, for convenience. */ public Window getWindow(int windowIndex, Window window, boolean setIds) { return getWindow(windowIndex, window, setIds, 0); } /** * Populates a {@link Window} with data for the window at the specified index. * * @param windowIndex The index of the window. * @param window The {@link Window} to populate. Must not be null. * @param setIds Whether {@link Window#id} should be populated. If false, the field will be set to * null. The caller should pass false for efficiency reasons unless the field is required. * @param defaultPositionProjectionUs A duration into the future that the populated window's * default start position should be projected. * @return The populated {@link Window}, for convenience. */ public abstract Window getWindow(int windowIndex, Window window, boolean setIds, long defaultPositionProjectionUs); /** * Returns the number of periods in the timeline. */ public abstract int getPeriodCount(); /** * Populates a {@link Period} with data for the period at the specified index. Does not populate * {@link Period#id} and {@link Period#uid}. * * @param periodIndex The index of the period. * @param period The {@link Period} to populate. Must not be null. * @return The populated {@link Period}, for convenience. */ public final Period getPeriod(int periodIndex, Period period) { return getPeriod(periodIndex, period, false); } /** * Populates a {@link Period} with data for the period at the specified index. * * @param periodIndex The index of the period. * @param period The {@link Period} to populate. Must not be null. * @param setIds Whether {@link Period#id} and {@link Period#uid} should be populated. If false, * the fields will be set to null. The caller should pass false for efficiency reasons unless * the fields are required. * @return The populated {@link Period}, for convenience. */ public abstract Period getPeriod(int periodIndex, Period period, boolean setIds); /** * Returns the index of the period identified by its unique {@code id}, or {@link C#INDEX_UNSET} * if the period is not in the timeline. * * @param uid A unique identifier for a period. * @return The index of the period, or {@link C#INDEX_UNSET} if the period was not found. */ public abstract int getIndexOfPeriod(Object uid); /** * Holds information about a window in a {@link Timeline}. A window defines a region of media * currently available for playback along with additional information such as whether seeking is * supported within the window. See {@link Timeline} for more details. The figure below shows some * of the information defined by a window, as well as how this information relates to * corresponding {@link Period}s in the timeline. *

* Information defined by a timeline window *

*/ public static final class Window { /** * An identifier for the window. Not necessarily unique. */ public Object id; /** * The start time of the presentation to which this window belongs in milliseconds since the * epoch, or {@link C#TIME_UNSET} if unknown or not applicable. For informational purposes only. */ public long presentationStartTimeMs; /** * The window's start time in milliseconds since the epoch, or {@link C#TIME_UNSET} if unknown * or not applicable. For informational purposes only. */ public long windowStartTimeMs; /** * Whether it's possible to seek within this window. */ public boolean isSeekable; /** * Whether this window may change when the timeline is updated. */ public boolean isDynamic; /** * The index of the first period that belongs to this window. */ public int firstPeriodIndex; /** * The index of the last period that belongs to this window. */ public int lastPeriodIndex; /** * The default position relative to the start of the window at which to begin playback, in * microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a * non-zero default position projection, and if the specified projection cannot be performed * whilst remaining within the bounds of the window. */ public long defaultPositionUs; /** * The duration of this window in microseconds, or {@link C#TIME_UNSET} if unknown. */ public long durationUs; /** * The position of the start of this window relative to the start of the first period belonging * to it, in microseconds. */ public long positionInFirstPeriodUs; /** * Sets the data held by this window. */ public Window set(Object id, long presentationStartTimeMs, long windowStartTimeMs, boolean isSeekable, boolean isDynamic, long defaultPositionUs, long durationUs, int firstPeriodIndex, int lastPeriodIndex, long positionInFirstPeriodUs) { this.id = id; this.presentationStartTimeMs = presentationStartTimeMs; this.windowStartTimeMs = windowStartTimeMs; this.isSeekable = isSeekable; this.isDynamic = isDynamic; this.defaultPositionUs = defaultPositionUs; this.durationUs = durationUs; this.firstPeriodIndex = firstPeriodIndex; this.lastPeriodIndex = lastPeriodIndex; this.positionInFirstPeriodUs = positionInFirstPeriodUs; return this; } /** * Returns the default position relative to the start of the window at which to begin playback, * in milliseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a * non-zero default position projection, and if the specified projection cannot be performed * whilst remaining within the bounds of the window. */ public long getDefaultPositionMs() { return C.usToMs(defaultPositionUs); } /** * Returns the default position relative to the start of the window at which to begin playback, * in microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a * non-zero default position projection, and if the specified projection cannot be performed * whilst remaining within the bounds of the window. */ public long getDefaultPositionUs() { return defaultPositionUs; } /** * Returns the duration of the window in milliseconds, or {@link C#TIME_UNSET} if unknown. */ public long getDurationMs() { return C.usToMs(durationUs); } /** * Returns the duration of this window in microseconds, or {@link C#TIME_UNSET} if unknown. */ public long getDurationUs() { return durationUs; } /** * Returns the position of the start of this window relative to the start of the first period * belonging to it, in milliseconds. */ public long getPositionInFirstPeriodMs() { return C.usToMs(positionInFirstPeriodUs); } /** * Returns the position of the start of this window relative to the start of the first period * belonging to it, in microseconds. */ public long getPositionInFirstPeriodUs() { return positionInFirstPeriodUs; } } /** * Holds information about a period in a {@link Timeline}. A period defines a single logical piece * of media, for example a a media file. See {@link Timeline} for more details. The figure below * shows some of the information defined by a period, as well as how this information relates to a * corresponding {@link Window} in the timeline. *

* Information defined by a period *

*/ public static final class Period { /** * An identifier for the period. Not necessarily unique. */ public Object id; /** * A unique identifier for the period. */ public Object uid; /** * The index of the window to which this period belongs. */ public int windowIndex; /** * The duration of this period in microseconds, or {@link C#TIME_UNSET} if unknown. */ public long durationUs; private long positionInWindowUs; /** * Sets the data held by this period. */ public Period set(Object id, Object uid, int windowIndex, long durationUs, long positionInWindowUs) { this.id = id; this.uid = uid; this.windowIndex = windowIndex; this.durationUs = durationUs; this.positionInWindowUs = positionInWindowUs; return this; } /** * Returns the duration of the period in milliseconds, or {@link C#TIME_UNSET} if unknown. */ public long getDurationMs() { return C.usToMs(durationUs); } /** * Returns the duration of this period in microseconds, or {@link C#TIME_UNSET} if unknown. */ public long getDurationUs() { return durationUs; } /** * Returns the position of the start of this period relative to the start of the window to which * it belongs, in milliseconds. May be negative if the start of the period is not within the * window. */ public long getPositionInWindowMs() { return C.usToMs(positionInWindowUs); } /** * Returns the position of the start of this period relative to the start of the window to which * it belongs, in microseconds. May be negative if the start of the period is not within the * window. */ public long getPositionInWindowUs() { return positionInWindowUs; } } }