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:
aquilescanta 2018-01-26 03:37:55 -08:00 committed by Oliver Woodman
parent bc9dbdb49e
commit 677fc291cf
11 changed files with 85 additions and 43 deletions

View File

@ -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

View File

@ -64,7 +64,7 @@ public class ContainerMediaChunk extends BaseMediaChunk {
} }
@Override @Override
public int getNextChunkIndex() { public long getNextChunkIndex() {
return chunkIndex + chunkCount; return chunkIndex + chunkCount;
} }

View File

@ -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;
} }

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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));
} }

View File

@ -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;
} }
/** /**

View File

@ -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();

View File

@ -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 {