mirror of
https://github.com/samsonjs/media.git
synced 2026-03-31 10:25:48 +00:00
ClippingMediaSource wraps a single period/window video-on-demand source and exposes a specified time range within it. Issue: #1988 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=141991215
435 lines
16 KiB
Java
435 lines
16 KiB
Java
/*
|
|
* 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.
|
|
* <p>
|
|
* 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.
|
|
* <p>
|
|
* 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.
|
|
*
|
|
* <h3 id="single-file">Single media file or on-demand stream</h3>
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-single-file.svg" alt="Example timeline for a single file">
|
|
* </p>
|
|
* 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).
|
|
*
|
|
* <h3>Playlist of media files or on-demand streams</h3>
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-playlist.svg" alt="Example timeline for a playlist of files">
|
|
* </p>
|
|
* 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.
|
|
*
|
|
* <h3 id="live-limited">Live stream with limited availability</h3>
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-live-limited.svg" alt="Example timeline for a live stream with
|
|
* limited availability">
|
|
* </p>
|
|
* 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).
|
|
*
|
|
* <h3>Live stream with indefinite availability</h3>
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-live-indefinite.svg" alt="Example timeline for a live stream with
|
|
* indefinite availability">
|
|
* </p>
|
|
* A timeline for a live stream with indefinite availability is similar to the
|
|
* <a href="#live-limited">Live stream with limited availability</a> 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.
|
|
*
|
|
* <h3 id="live-multi-period">Live stream with multiple periods</h3>
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-live-multi-period.svg" alt="Example timeline for a live stream
|
|
* with multiple periods">
|
|
* </p>
|
|
* 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 <a href="#live-limited">Live stream
|
|
* with limited availability</a> case, except that the window may span more than one period.
|
|
* Multiple periods are also possible in the indefinite availability case.
|
|
*
|
|
* <h3>On-demand pre-roll followed by live stream</h3>
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-advanced.svg" alt="Example timeline for an on-demand pre-roll
|
|
* followed by a live stream">
|
|
* </p>
|
|
* This case is the concatenation of the <a href="#single-file">Single media file or on-demand
|
|
* stream</a> and <a href="#multi-period">Live stream with multiple periods</a> 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.
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-window.svg" alt="Information defined by a timeline window">
|
|
* </p>
|
|
*/
|
|
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.
|
|
* <p align="center">
|
|
* <img src="doc-files/timeline-period.svg" alt="Information defined by a period">
|
|
* </p>
|
|
*/
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
}
|