mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
Add MediaChunkIterator for SmoothStreaming stream elements.
This allows to iterate through the available chunks of the stream. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=203105813
This commit is contained in:
parent
97120bc6cb
commit
f4bcfe082d
1 changed files with 172 additions and 118 deletions
|
|
@ -20,6 +20,9 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.offline.FilterableManifest;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator;
|
||||
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.UriUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -36,123 +39,7 @@ import java.util.UUID;
|
|||
*/
|
||||
public class SsManifest implements FilterableManifest<SsManifest> {
|
||||
|
||||
public static final int UNSET_LOOKAHEAD = -1;
|
||||
|
||||
/**
|
||||
* The client manifest major version.
|
||||
*/
|
||||
public final int majorVersion;
|
||||
|
||||
/**
|
||||
* The client manifest minor version.
|
||||
*/
|
||||
public final int minorVersion;
|
||||
|
||||
/**
|
||||
* The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if the lookahead is
|
||||
* unspecified.
|
||||
*/
|
||||
public final int lookAheadCount;
|
||||
|
||||
/**
|
||||
* Whether the manifest describes a live presentation still in progress.
|
||||
*/
|
||||
public final boolean isLive;
|
||||
|
||||
/**
|
||||
* Content protection information, or null if the content is not protected.
|
||||
*/
|
||||
public final ProtectionElement protectionElement;
|
||||
|
||||
/**
|
||||
* The contained stream elements.
|
||||
*/
|
||||
public final StreamElement[] streamElements;
|
||||
|
||||
/**
|
||||
* The overall presentation duration of the media in microseconds, or {@link C#TIME_UNSET}
|
||||
* if the duration is unknown.
|
||||
*/
|
||||
public final long durationUs;
|
||||
|
||||
/**
|
||||
* The length of the trailing window for a live broadcast in microseconds, or
|
||||
* {@link C#TIME_UNSET} if the stream is not live or if the window length is unspecified.
|
||||
*/
|
||||
public final long dvrWindowLengthUs;
|
||||
|
||||
/**
|
||||
* @param majorVersion The client manifest major version.
|
||||
* @param minorVersion The client manifest minor version.
|
||||
* @param timescale The timescale of the media as the number of units that pass in one second.
|
||||
* @param duration The overall presentation duration in units of the timescale attribute, or 0
|
||||
* if the duration is unknown.
|
||||
* @param dvrWindowLength The length of the trailing window in units of the timescale attribute,
|
||||
* or 0 if this attribute is unspecified or not applicable.
|
||||
* @param lookAheadCount The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if
|
||||
* this attribute is unspecified or not applicable.
|
||||
* @param isLive True if the manifest describes a live presentation still in progress. False
|
||||
* otherwise.
|
||||
* @param protectionElement Content protection information, or null if the content is not
|
||||
* protected.
|
||||
* @param streamElements The contained stream elements.
|
||||
*/
|
||||
public SsManifest(int majorVersion, int minorVersion, long timescale, long duration,
|
||||
long dvrWindowLength, int lookAheadCount, boolean isLive, ProtectionElement protectionElement,
|
||||
StreamElement[] streamElements) {
|
||||
this(majorVersion, minorVersion,
|
||||
duration == 0 ? C.TIME_UNSET
|
||||
: Util.scaleLargeTimestamp(duration, C.MICROS_PER_SECOND, timescale),
|
||||
dvrWindowLength == 0 ? C.TIME_UNSET
|
||||
: Util.scaleLargeTimestamp(dvrWindowLength, C.MICROS_PER_SECOND, timescale),
|
||||
lookAheadCount, isLive, protectionElement, streamElements);
|
||||
}
|
||||
|
||||
private SsManifest(int majorVersion, int minorVersion, long durationUs, long dvrWindowLengthUs,
|
||||
int lookAheadCount, boolean isLive, ProtectionElement protectionElement,
|
||||
StreamElement[] streamElements) {
|
||||
this.majorVersion = majorVersion;
|
||||
this.minorVersion = minorVersion;
|
||||
this.durationUs = durationUs;
|
||||
this.dvrWindowLengthUs = dvrWindowLengthUs;
|
||||
this.lookAheadCount = lookAheadCount;
|
||||
this.isLive = isLive;
|
||||
this.protectionElement = protectionElement;
|
||||
this.streamElements = streamElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SsManifest copy(List<StreamKey> streamKeys) {
|
||||
ArrayList<StreamKey> sortedKeys = new ArrayList<>(streamKeys);
|
||||
Collections.sort(sortedKeys);
|
||||
|
||||
StreamElement currentStreamElement = null;
|
||||
List<StreamElement> copiedStreamElements = new ArrayList<>();
|
||||
List<Format> copiedFormats = new ArrayList<>();
|
||||
for (int i = 0; i < sortedKeys.size(); i++) {
|
||||
StreamKey key = sortedKeys.get(i);
|
||||
StreamElement streamElement = streamElements[key.groupIndex];
|
||||
if (streamElement != currentStreamElement && currentStreamElement != null) {
|
||||
// We're advancing to a new stream element. Add the current one.
|
||||
copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0])));
|
||||
copiedFormats.clear();
|
||||
}
|
||||
currentStreamElement = streamElement;
|
||||
copiedFormats.add(streamElement.formats[key.trackIndex]);
|
||||
}
|
||||
if (currentStreamElement != null) {
|
||||
// Add the last stream element.
|
||||
copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0])));
|
||||
}
|
||||
|
||||
StreamElement[] copiedStreamElementsArray = copiedStreamElements.toArray(new StreamElement[0]);
|
||||
return new SsManifest(majorVersion, minorVersion, durationUs, dvrWindowLengthUs, lookAheadCount,
|
||||
isLive, protectionElement, copiedStreamElementsArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a protection element containing a single header.
|
||||
*/
|
||||
/** Represents a protection element containing a single header. */
|
||||
public static class ProtectionElement {
|
||||
|
||||
public final UUID uuid;
|
||||
|
|
@ -162,7 +49,45 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
|||
this.uuid = uuid;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/** {@link MediaChunkIterator} wrapping a track of a {@link StreamElement}. */
|
||||
public static final class StreamElementIterator extends BaseMediaChunkIterator {
|
||||
|
||||
private final StreamElement streamElement;
|
||||
private final int trackIndex;
|
||||
|
||||
/**
|
||||
* Creates iterator.
|
||||
*
|
||||
* @param streamElement The {@link StreamElement} to wrap.
|
||||
* @param trackIndex The track index in the stream element.
|
||||
* @param chunkIndex The chunk index at which the iterator will start.
|
||||
*/
|
||||
public StreamElementIterator(StreamElement streamElement, int trackIndex, int chunkIndex) {
|
||||
super(/* fromIndex= */ chunkIndex, /* toIndex= */ streamElement.chunkCount - 1);
|
||||
this.streamElement = streamElement;
|
||||
this.trackIndex = trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSpec getDataSpec() {
|
||||
checkInBounds();
|
||||
Uri uri = streamElement.buildRequestUri(trackIndex, (int) getCurrentIndex());
|
||||
return new DataSpec(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChunkStartTimeUs() {
|
||||
checkInBounds();
|
||||
return streamElement.getStartTimeUs((int) getCurrentIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChunkEndTimeUs() {
|
||||
long chunkStartTimeUs = getChunkStartTimeUs();
|
||||
return chunkStartTimeUs + streamElement.getChunkDurationUs((int) getCurrentIndex());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -302,7 +227,136 @@ public class SsManifest implements FilterableManifest<SsManifest> {
|
|||
.replace(URL_PLACEHOLDER_START_TIME_2, startTimeString);
|
||||
return UriUtil.resolveToUri(baseUri, chunkUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final int UNSET_LOOKAHEAD = -1;
|
||||
|
||||
/** The client manifest major version. */
|
||||
public final int majorVersion;
|
||||
|
||||
/** The client manifest minor version. */
|
||||
public final int minorVersion;
|
||||
|
||||
/**
|
||||
* The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if the lookahead is
|
||||
* unspecified.
|
||||
*/
|
||||
public final int lookAheadCount;
|
||||
|
||||
/** Whether the manifest describes a live presentation still in progress. */
|
||||
public final boolean isLive;
|
||||
|
||||
/** Content protection information, or null if the content is not protected. */
|
||||
public final ProtectionElement protectionElement;
|
||||
|
||||
/** The contained stream elements. */
|
||||
public final StreamElement[] streamElements;
|
||||
|
||||
/**
|
||||
* The overall presentation duration of the media in microseconds, or {@link C#TIME_UNSET} if the
|
||||
* duration is unknown.
|
||||
*/
|
||||
public final long durationUs;
|
||||
|
||||
/**
|
||||
* The length of the trailing window for a live broadcast in microseconds, or {@link C#TIME_UNSET}
|
||||
* if the stream is not live or if the window length is unspecified.
|
||||
*/
|
||||
public final long dvrWindowLengthUs;
|
||||
|
||||
/**
|
||||
* @param majorVersion The client manifest major version.
|
||||
* @param minorVersion The client manifest minor version.
|
||||
* @param timescale The timescale of the media as the number of units that pass in one second.
|
||||
* @param duration The overall presentation duration in units of the timescale attribute, or 0 if
|
||||
* the duration is unknown.
|
||||
* @param dvrWindowLength The length of the trailing window in units of the timescale attribute,
|
||||
* or 0 if this attribute is unspecified or not applicable.
|
||||
* @param lookAheadCount The number of fragments in a lookahead, or {@link #UNSET_LOOKAHEAD} if
|
||||
* this attribute is unspecified or not applicable.
|
||||
* @param isLive True if the manifest describes a live presentation still in progress. False
|
||||
* otherwise.
|
||||
* @param protectionElement Content protection information, or null if the content is not
|
||||
* protected.
|
||||
* @param streamElements The contained stream elements.
|
||||
*/
|
||||
public SsManifest(
|
||||
int majorVersion,
|
||||
int minorVersion,
|
||||
long timescale,
|
||||
long duration,
|
||||
long dvrWindowLength,
|
||||
int lookAheadCount,
|
||||
boolean isLive,
|
||||
ProtectionElement protectionElement,
|
||||
StreamElement[] streamElements) {
|
||||
this(
|
||||
majorVersion,
|
||||
minorVersion,
|
||||
duration == 0
|
||||
? C.TIME_UNSET
|
||||
: Util.scaleLargeTimestamp(duration, C.MICROS_PER_SECOND, timescale),
|
||||
dvrWindowLength == 0
|
||||
? C.TIME_UNSET
|
||||
: Util.scaleLargeTimestamp(dvrWindowLength, C.MICROS_PER_SECOND, timescale),
|
||||
lookAheadCount,
|
||||
isLive,
|
||||
protectionElement,
|
||||
streamElements);
|
||||
}
|
||||
|
||||
private SsManifest(
|
||||
int majorVersion,
|
||||
int minorVersion,
|
||||
long durationUs,
|
||||
long dvrWindowLengthUs,
|
||||
int lookAheadCount,
|
||||
boolean isLive,
|
||||
ProtectionElement protectionElement,
|
||||
StreamElement[] streamElements) {
|
||||
this.majorVersion = majorVersion;
|
||||
this.minorVersion = minorVersion;
|
||||
this.durationUs = durationUs;
|
||||
this.dvrWindowLengthUs = dvrWindowLengthUs;
|
||||
this.lookAheadCount = lookAheadCount;
|
||||
this.isLive = isLive;
|
||||
this.protectionElement = protectionElement;
|
||||
this.streamElements = streamElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SsManifest copy(List<StreamKey> streamKeys) {
|
||||
ArrayList<StreamKey> sortedKeys = new ArrayList<>(streamKeys);
|
||||
Collections.sort(sortedKeys);
|
||||
|
||||
StreamElement currentStreamElement = null;
|
||||
List<StreamElement> copiedStreamElements = new ArrayList<>();
|
||||
List<Format> copiedFormats = new ArrayList<>();
|
||||
for (int i = 0; i < sortedKeys.size(); i++) {
|
||||
StreamKey key = sortedKeys.get(i);
|
||||
StreamElement streamElement = streamElements[key.groupIndex];
|
||||
if (streamElement != currentStreamElement && currentStreamElement != null) {
|
||||
// We're advancing to a new stream element. Add the current one.
|
||||
copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0])));
|
||||
copiedFormats.clear();
|
||||
}
|
||||
currentStreamElement = streamElement;
|
||||
copiedFormats.add(streamElement.formats[key.trackIndex]);
|
||||
}
|
||||
if (currentStreamElement != null) {
|
||||
// Add the last stream element.
|
||||
copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0])));
|
||||
}
|
||||
|
||||
StreamElement[] copiedStreamElementsArray = copiedStreamElements.toArray(new StreamElement[0]);
|
||||
return new SsManifest(
|
||||
majorVersion,
|
||||
minorVersion,
|
||||
durationUs,
|
||||
dvrWindowLengthUs,
|
||||
lookAheadCount,
|
||||
isLive,
|
||||
protectionElement,
|
||||
copiedStreamElementsArray);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue