Use long for HLS media sequences
Issue:#3747 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=183366339
This commit is contained in:
parent
bc9dbdb49e
commit
677fc291cf
@ -67,6 +67,8 @@
|
|||||||
([#3653](https://github.com/google/ExoPlayer/issues/3653)).
|
([#3653](https://github.com/google/ExoPlayer/issues/3653)).
|
||||||
* Fix ID3 context reuse across segment format changes
|
* Fix ID3 context reuse across segment format changes
|
||||||
([#3622](https://github.com/google/ExoPlayer/issues/3622)).
|
([#3622](https://github.com/google/ExoPlayer/issues/3622)).
|
||||||
|
* Use long for media sequence numbers
|
||||||
|
([#3747](https://github.com/google/ExoPlayer/issues/3747))
|
||||||
* New Cast extension: Simplifies toggling between local and Cast playbacks.
|
* New Cast extension: Simplifies toggling between local and Cast playbacks.
|
||||||
* Audio:
|
* Audio:
|
||||||
* Support TrueHD passthrough for rechunked samples in Matroska files
|
* Support TrueHD passthrough for rechunked samples in Matroska files
|
||||||
|
@ -64,7 +64,7 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNextChunkIndex() {
|
public long getNextChunkIndex() {
|
||||||
return chunkIndex + chunkCount;
|
return chunkIndex + chunkCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,10 +26,8 @@ import com.google.android.exoplayer2.util.Assertions;
|
|||||||
*/
|
*/
|
||||||
public abstract class MediaChunk extends Chunk {
|
public abstract class MediaChunk extends Chunk {
|
||||||
|
|
||||||
/**
|
/** The chunk index. */
|
||||||
* The chunk index.
|
public final long chunkIndex;
|
||||||
*/
|
|
||||||
public final int chunkIndex;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dataSource The source from which the data should be loaded.
|
* @param dataSource The source from which the data should be loaded.
|
||||||
@ -41,19 +39,23 @@ public abstract class MediaChunk extends Chunk {
|
|||||||
* @param endTimeUs The end time of the media contained by the chunk, in microseconds.
|
* @param endTimeUs The end time of the media contained by the chunk, in microseconds.
|
||||||
* @param chunkIndex The index of the chunk.
|
* @param chunkIndex The index of the chunk.
|
||||||
*/
|
*/
|
||||||
public MediaChunk(DataSource dataSource, DataSpec dataSpec, Format trackFormat,
|
public MediaChunk(
|
||||||
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs,
|
DataSource dataSource,
|
||||||
int chunkIndex) {
|
DataSpec dataSpec,
|
||||||
|
Format trackFormat,
|
||||||
|
int trackSelectionReason,
|
||||||
|
Object trackSelectionData,
|
||||||
|
long startTimeUs,
|
||||||
|
long endTimeUs,
|
||||||
|
long chunkIndex) {
|
||||||
super(dataSource, dataSpec, C.DATA_TYPE_MEDIA, trackFormat, trackSelectionReason,
|
super(dataSource, dataSpec, C.DATA_TYPE_MEDIA, trackFormat, trackSelectionReason,
|
||||||
trackSelectionData, startTimeUs, endTimeUs);
|
trackSelectionData, startTimeUs, endTimeUs);
|
||||||
Assertions.checkNotNull(trackFormat);
|
Assertions.checkNotNull(trackFormat);
|
||||||
this.chunkIndex = chunkIndex;
|
this.chunkIndex = chunkIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns the next chunk index. */
|
||||||
* Returns the next chunk index.
|
public long getNextChunkIndex() {
|
||||||
*/
|
|
||||||
public int getNextChunkIndex() {
|
|
||||||
return chunkIndex + 1;
|
return chunkIndex + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
segmentNum = Util.constrainValue(representationHolder.getSegmentNum(loadPositionUs),
|
segmentNum = Util.constrainValue(representationHolder.getSegmentNum(loadPositionUs),
|
||||||
firstAvailableSegmentNum, lastAvailableSegmentNum);
|
firstAvailableSegmentNum, lastAvailableSegmentNum);
|
||||||
} else {
|
} else {
|
||||||
segmentNum = previous.getNextChunkIndex();
|
segmentNum = (int) previous.getNextChunkIndex();
|
||||||
if (segmentNum < firstAvailableSegmentNum) {
|
if (segmentNum < firstAvailableSegmentNum) {
|
||||||
// This is before the first chunk in the current manifest.
|
// This is before the first chunk in the current manifest.
|
||||||
fatalError = new BehindLiveWindowException();
|
fatalError = new BehindLiveWindowException();
|
||||||
|
@ -253,7 +253,7 @@ import java.util.List;
|
|||||||
updateLiveEdgeTimeUs(mediaPlaylist);
|
updateLiveEdgeTimeUs(mediaPlaylist);
|
||||||
|
|
||||||
// Select the chunk.
|
// Select the chunk.
|
||||||
int chunkMediaSequence;
|
long chunkMediaSequence;
|
||||||
if (previous == null || switchingVariant) {
|
if (previous == null || switchingVariant) {
|
||||||
long targetPositionUs = (previous == null || independentSegments) ? loadPositionUs
|
long targetPositionUs = (previous == null || independentSegments) ? loadPositionUs
|
||||||
: previous.startTimeUs;
|
: previous.startTimeUs;
|
||||||
@ -281,7 +281,7 @@ import java.util.List;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int chunkIndex = chunkMediaSequence - mediaPlaylist.mediaSequence;
|
int chunkIndex = (int) (chunkMediaSequence - mediaPlaylist.mediaSequence);
|
||||||
if (chunkIndex >= mediaPlaylist.segments.size()) {
|
if (chunkIndex >= mediaPlaylist.segments.size()) {
|
||||||
if (mediaPlaylist.hasEndTag) {
|
if (mediaPlaylist.hasEndTag) {
|
||||||
out.endOfStream = true;
|
out.endOfStream = true;
|
||||||
|
@ -83,8 +83,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
private volatile boolean loadCompleted;
|
private volatile boolean loadCompleted;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param extractorFactory A {@link HlsExtractorFactory} from which the HLS media chunk
|
* @param extractorFactory A {@link HlsExtractorFactory} from which the HLS media chunk extractor
|
||||||
* extractor is obtained.
|
* is obtained.
|
||||||
* @param dataSource The source from which the data should be loaded.
|
* @param dataSource The source from which the data should be loaded.
|
||||||
* @param dataSpec Defines the data to be loaded.
|
* @param dataSpec Defines the data to be loaded.
|
||||||
* @param initDataSpec Defines the initialization data to be fed to new extractors. May be null.
|
* @param initDataSpec Defines the initialization data to be fed to new extractors. May be null.
|
||||||
@ -95,7 +95,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
* @param trackSelectionData See {@link #trackSelectionData}.
|
* @param trackSelectionData See {@link #trackSelectionData}.
|
||||||
* @param startTimeUs The start time of the chunk in microseconds.
|
* @param startTimeUs The start time of the chunk in microseconds.
|
||||||
* @param endTimeUs The end time of the chunk in microseconds.
|
* @param endTimeUs The end time of the chunk in microseconds.
|
||||||
* @param chunkIndex The media sequence number of the chunk.
|
* @param chunkMediaSequence The media sequence number of the chunk.
|
||||||
* @param discontinuitySequenceNumber The discontinuity sequence number of the chunk.
|
* @param discontinuitySequenceNumber The discontinuity sequence number of the chunk.
|
||||||
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
|
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
|
||||||
* @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number.
|
* @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number.
|
||||||
@ -106,15 +106,34 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
* @param encryptionIv The AES initialization vector, or null if the segment is not fully
|
* @param encryptionIv The AES initialization vector, or null if the segment is not fully
|
||||||
* encrypted.
|
* encrypted.
|
||||||
*/
|
*/
|
||||||
public HlsMediaChunk(HlsExtractorFactory extractorFactory, DataSource dataSource,
|
public HlsMediaChunk(
|
||||||
DataSpec dataSpec, DataSpec initDataSpec, HlsUrl hlsUrl, List<Format> muxedCaptionFormats,
|
HlsExtractorFactory extractorFactory,
|
||||||
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs,
|
DataSource dataSource,
|
||||||
int chunkIndex, int discontinuitySequenceNumber, boolean isMasterTimestampSource,
|
DataSpec dataSpec,
|
||||||
TimestampAdjuster timestampAdjuster, HlsMediaChunk previousChunk, DrmInitData drmInitData,
|
DataSpec initDataSpec,
|
||||||
byte[] fullSegmentEncryptionKey, byte[] encryptionIv) {
|
HlsUrl hlsUrl,
|
||||||
super(buildDataSource(dataSource, fullSegmentEncryptionKey, encryptionIv), dataSpec,
|
List<Format> muxedCaptionFormats,
|
||||||
hlsUrl.format, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs,
|
int trackSelectionReason,
|
||||||
chunkIndex);
|
Object trackSelectionData,
|
||||||
|
long startTimeUs,
|
||||||
|
long endTimeUs,
|
||||||
|
long chunkMediaSequence,
|
||||||
|
int discontinuitySequenceNumber,
|
||||||
|
boolean isMasterTimestampSource,
|
||||||
|
TimestampAdjuster timestampAdjuster,
|
||||||
|
HlsMediaChunk previousChunk,
|
||||||
|
DrmInitData drmInitData,
|
||||||
|
byte[] fullSegmentEncryptionKey,
|
||||||
|
byte[] encryptionIv) {
|
||||||
|
super(
|
||||||
|
buildDataSource(dataSource, fullSegmentEncryptionKey, encryptionIv),
|
||||||
|
dataSpec,
|
||||||
|
hlsUrl.format,
|
||||||
|
trackSelectionReason,
|
||||||
|
trackSelectionData,
|
||||||
|
startTimeUs,
|
||||||
|
endTimeUs,
|
||||||
|
chunkMediaSequence);
|
||||||
this.discontinuitySequenceNumber = discontinuitySequenceNumber;
|
this.discontinuitySequenceNumber = discontinuitySequenceNumber;
|
||||||
this.initDataSpec = initDataSpec;
|
this.initDataSpec = initDataSpec;
|
||||||
this.hlsUrl = hlsUrl;
|
this.hlsUrl = hlsUrl;
|
||||||
|
@ -139,7 +139,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
* The media sequence number of the first media segment in the playlist, as defined by
|
* The media sequence number of the first media segment in the playlist, as defined by
|
||||||
* #EXT-X-MEDIA-SEQUENCE.
|
* #EXT-X-MEDIA-SEQUENCE.
|
||||||
*/
|
*/
|
||||||
public final int mediaSequence;
|
public final long mediaSequence;
|
||||||
/**
|
/**
|
||||||
* The compatibility version, as defined by #EXT-X-VERSION.
|
* The compatibility version, as defined by #EXT-X-VERSION.
|
||||||
*/
|
*/
|
||||||
@ -196,11 +196,23 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
* @param initializationSegment See {@link #initializationSegment}.
|
* @param initializationSegment See {@link #initializationSegment}.
|
||||||
* @param segments See {@link #segments}.
|
* @param segments See {@link #segments}.
|
||||||
*/
|
*/
|
||||||
public HlsMediaPlaylist(@PlaylistType int playlistType, String baseUri, List<String> tags,
|
public HlsMediaPlaylist(
|
||||||
long startOffsetUs, long startTimeUs, boolean hasDiscontinuitySequence,
|
@PlaylistType int playlistType,
|
||||||
int discontinuitySequence, int mediaSequence, int version, long targetDurationUs,
|
String baseUri,
|
||||||
boolean hasIndependentSegmentsTag, boolean hasEndTag, boolean hasProgramDateTime,
|
List<String> tags,
|
||||||
DrmInitData drmInitData, Segment initializationSegment, List<Segment> segments) {
|
long startOffsetUs,
|
||||||
|
long startTimeUs,
|
||||||
|
boolean hasDiscontinuitySequence,
|
||||||
|
int discontinuitySequence,
|
||||||
|
long mediaSequence,
|
||||||
|
int version,
|
||||||
|
long targetDurationUs,
|
||||||
|
boolean hasIndependentSegmentsTag,
|
||||||
|
boolean hasEndTag,
|
||||||
|
boolean hasProgramDateTime,
|
||||||
|
DrmInitData drmInitData,
|
||||||
|
Segment initializationSegment,
|
||||||
|
List<Segment> segments) {
|
||||||
super(baseUri, tags);
|
super(baseUri, tags);
|
||||||
this.playlistType = playlistType;
|
this.playlistType = playlistType;
|
||||||
this.startTimeUs = startTimeUs;
|
this.startTimeUs = startTimeUs;
|
||||||
|
@ -339,7 +339,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
@HlsMediaPlaylist.PlaylistType int playlistType = HlsMediaPlaylist.PLAYLIST_TYPE_UNKNOWN;
|
@HlsMediaPlaylist.PlaylistType int playlistType = HlsMediaPlaylist.PLAYLIST_TYPE_UNKNOWN;
|
||||||
long startOffsetUs = C.TIME_UNSET;
|
long startOffsetUs = C.TIME_UNSET;
|
||||||
int mediaSequence = 0;
|
long mediaSequence = 0;
|
||||||
int version = 1; // Default version == 1.
|
int version = 1; // Default version == 1.
|
||||||
long targetDurationUs = C.TIME_UNSET;
|
long targetDurationUs = C.TIME_UNSET;
|
||||||
boolean hasIndependentSegmentsTag = false;
|
boolean hasIndependentSegmentsTag = false;
|
||||||
@ -356,7 +356,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
long segmentStartTimeUs = 0;
|
long segmentStartTimeUs = 0;
|
||||||
long segmentByteRangeOffset = 0;
|
long segmentByteRangeOffset = 0;
|
||||||
long segmentByteRangeLength = C.LENGTH_UNSET;
|
long segmentByteRangeLength = C.LENGTH_UNSET;
|
||||||
int segmentMediaSequence = 0;
|
long segmentMediaSequence = 0;
|
||||||
|
|
||||||
String encryptionKeyUri = null;
|
String encryptionKeyUri = null;
|
||||||
String encryptionIV = null;
|
String encryptionIV = null;
|
||||||
@ -396,7 +396,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
} else if (line.startsWith(TAG_TARGET_DURATION)) {
|
} else if (line.startsWith(TAG_TARGET_DURATION)) {
|
||||||
targetDurationUs = parseIntAttr(line, REGEX_TARGET_DURATION) * C.MICROS_PER_SECOND;
|
targetDurationUs = parseIntAttr(line, REGEX_TARGET_DURATION) * C.MICROS_PER_SECOND;
|
||||||
} else if (line.startsWith(TAG_MEDIA_SEQUENCE)) {
|
} else if (line.startsWith(TAG_MEDIA_SEQUENCE)) {
|
||||||
mediaSequence = parseIntAttr(line, REGEX_MEDIA_SEQUENCE);
|
mediaSequence = parseLongAttr(line, REGEX_MEDIA_SEQUENCE);
|
||||||
segmentMediaSequence = mediaSequence;
|
segmentMediaSequence = mediaSequence;
|
||||||
} else if (line.startsWith(TAG_VERSION)) {
|
} else if (line.startsWith(TAG_VERSION)) {
|
||||||
version = parseIntAttr(line, REGEX_VERSION);
|
version = parseIntAttr(line, REGEX_VERSION);
|
||||||
@ -456,7 +456,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
} else if (encryptionIV != null) {
|
} else if (encryptionIV != null) {
|
||||||
segmentEncryptionIV = encryptionIV;
|
segmentEncryptionIV = encryptionIV;
|
||||||
} else {
|
} else {
|
||||||
segmentEncryptionIV = Integer.toHexString(segmentMediaSequence);
|
segmentEncryptionIV = Long.toHexString(segmentMediaSequence);
|
||||||
}
|
}
|
||||||
segmentMediaSequence++;
|
segmentMediaSequence++;
|
||||||
if (segmentByteRangeLength == C.LENGTH_UNSET) {
|
if (segmentByteRangeLength == C.LENGTH_UNSET) {
|
||||||
@ -504,6 +504,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
return Integer.parseInt(parseStringAttr(line, pattern));
|
return Integer.parseInt(parseStringAttr(line, pattern));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static long parseLongAttr(String line, Pattern pattern) throws ParserException {
|
||||||
|
return Long.parseLong(parseStringAttr(line, pattern));
|
||||||
|
}
|
||||||
|
|
||||||
private static double parseDoubleAttr(String line, Pattern pattern) throws ParserException {
|
private static double parseDoubleAttr(String line, Pattern pattern) throws ParserException {
|
||||||
return Double.parseDouble(parseStringAttr(line, pattern));
|
return Double.parseDouble(parseStringAttr(line, pattern));
|
||||||
}
|
}
|
||||||
|
@ -450,9 +450,11 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
|||||||
|
|
||||||
private static Segment getFirstOldOverlappingSegment(HlsMediaPlaylist oldPlaylist,
|
private static Segment getFirstOldOverlappingSegment(HlsMediaPlaylist oldPlaylist,
|
||||||
HlsMediaPlaylist loadedPlaylist) {
|
HlsMediaPlaylist loadedPlaylist) {
|
||||||
int mediaSequenceOffset = loadedPlaylist.mediaSequence - oldPlaylist.mediaSequence;
|
long mediaSequenceOffset = loadedPlaylist.mediaSequence - oldPlaylist.mediaSequence;
|
||||||
List<Segment> oldSegments = oldPlaylist.segments;
|
List<Segment> oldSegments = oldPlaylist.segments;
|
||||||
return mediaSequenceOffset < oldSegments.size() ? oldSegments.get(mediaSequenceOffset) : null;
|
return mediaSequenceOffset < oldSegments.size()
|
||||||
|
? oldSegments.get((int) mediaSequenceOffset)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,7 +183,7 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
if (previous == null) {
|
if (previous == null) {
|
||||||
chunkIndex = streamElement.getChunkIndex(loadPositionUs);
|
chunkIndex = streamElement.getChunkIndex(loadPositionUs);
|
||||||
} else {
|
} else {
|
||||||
chunkIndex = previous.getNextChunkIndex() - currentManifestChunkOffset;
|
chunkIndex = (int) (previous.getNextChunkIndex() - currentManifestChunkOffset);
|
||||||
if (chunkIndex < 0) {
|
if (chunkIndex < 0) {
|
||||||
// This is before the first chunk in the current manifest.
|
// This is before the first chunk in the current manifest.
|
||||||
fatalError = new BehindLiveWindowException();
|
fatalError = new BehindLiveWindowException();
|
||||||
|
@ -30,7 +30,6 @@ import com.google.android.exoplayer2.upstream.DataSource;
|
|||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -100,8 +99,10 @@ public final class FakeChunkSource implements ChunkSource {
|
|||||||
ChunkHolder out) {
|
ChunkHolder out) {
|
||||||
long bufferedDurationUs = loadPositionUs - playbackPositionUs;
|
long bufferedDurationUs = loadPositionUs - playbackPositionUs;
|
||||||
trackSelection.updateSelectedTrack(playbackPositionUs, bufferedDurationUs, C.TIME_UNSET);
|
trackSelection.updateSelectedTrack(playbackPositionUs, bufferedDurationUs, C.TIME_UNSET);
|
||||||
int chunkIndex = previous == null ? dataSet.getChunkIndexByPosition(playbackPositionUs)
|
int chunkIndex =
|
||||||
: previous.getNextChunkIndex();
|
previous == null
|
||||||
|
? dataSet.getChunkIndexByPosition(playbackPositionUs)
|
||||||
|
: (int) previous.getNextChunkIndex();
|
||||||
if (chunkIndex >= dataSet.getChunkCount()) {
|
if (chunkIndex >= dataSet.getChunkCount()) {
|
||||||
out.endOfStream = true;
|
out.endOfStream = true;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user