use of com.google.android.exoplayer2.extractor.ChunkIndex in project ExoPlayer by google.
the class FakeChunkSource method getNextChunk.
@Override
public void getNextChunk(long playbackPositionUs, long loadPositionUs, List<? extends MediaChunk> queue, ChunkHolder out) {
long bufferedDurationUs = loadPositionUs - playbackPositionUs;
int chunkIndex = queue.isEmpty() ? dataSet.getChunkIndexByPosition(playbackPositionUs) : (int) queue.get(queue.size() - 1).getNextChunkIndex();
MediaChunkIterator[] chunkIterators = new MediaChunkIterator[trackSelection.length()];
for (int i = 0; i < chunkIterators.length; i++) {
int trackGroupIndex = trackSelection.getIndexInTrackGroup(i);
chunkIterators[i] = new FakeAdaptiveDataSet.Iterator(dataSet, trackGroupIndex, chunkIndex);
}
trackSelection.updateSelectedTrack(playbackPositionUs, bufferedDurationUs, C.TIME_UNSET, queue, chunkIterators);
if (chunkIndex >= dataSet.getChunkCount()) {
out.endOfStream = true;
} else {
Format selectedFormat = trackSelection.getSelectedFormat();
long startTimeUs = dataSet.getStartTime(chunkIndex);
long endTimeUs = startTimeUs + dataSet.getChunkDuration(chunkIndex);
int trackGroupIndex = trackSelection.getIndexInTrackGroup(trackSelection.getSelectedIndex());
String uri = dataSet.getUri(trackGroupIndex);
Segment fakeDataChunk = Assertions.checkStateNotNull(dataSet.getData(uri)).getSegments().get(chunkIndex);
DataSpec dataSpec = new DataSpec(Uri.parse(uri), fakeDataChunk.byteOffset, fakeDataChunk.length);
int trackType = MimeTypes.getTrackType(selectedFormat.sampleMimeType);
out.chunk = new SingleSampleMediaChunk(dataSource, dataSpec, selectedFormat, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), startTimeUs, endTimeUs, chunkIndex, trackType, selectedFormat);
}
}
use of com.google.android.exoplayer2.extractor.ChunkIndex in project ExoPlayer by google.
the class FragmentedMp4Extractor method parseSidx.
/**
* Parses a sidx atom (defined in 14496-12).
*
* @param atom The atom data.
* @param inputPosition The input position of the first byte after the atom.
* @return A pair consisting of the earliest presentation time in microseconds, and the parsed
* {@link ChunkIndex}.
*/
private static Pair<Long, ChunkIndex> parseSidx(ParsableByteArray atom, long inputPosition) throws ParserException {
atom.setPosition(Atom.HEADER_SIZE);
int fullAtom = atom.readInt();
int version = Atom.parseFullAtomVersion(fullAtom);
atom.skipBytes(4);
long timescale = atom.readUnsignedInt();
long earliestPresentationTime;
long offset = inputPosition;
if (version == 0) {
earliestPresentationTime = atom.readUnsignedInt();
offset += atom.readUnsignedInt();
} else {
earliestPresentationTime = atom.readUnsignedLongToLong();
offset += atom.readUnsignedLongToLong();
}
long earliestPresentationTimeUs = Util.scaleLargeTimestamp(earliestPresentationTime, C.MICROS_PER_SECOND, timescale);
atom.skipBytes(2);
int referenceCount = atom.readUnsignedShort();
int[] sizes = new int[referenceCount];
long[] offsets = new long[referenceCount];
long[] durationsUs = new long[referenceCount];
long[] timesUs = new long[referenceCount];
long time = earliestPresentationTime;
long timeUs = earliestPresentationTimeUs;
for (int i = 0; i < referenceCount; i++) {
int firstInt = atom.readInt();
int type = 0x80000000 & firstInt;
if (type != 0) {
throw ParserException.createForMalformedContainer("Unhandled indirect reference", /* cause= */
null);
}
long referenceDuration = atom.readUnsignedInt();
sizes[i] = 0x7FFFFFFF & firstInt;
offsets[i] = offset;
// Calculate time and duration values such that any rounding errors are consistent. i.e. That
// timesUs[i] + durationsUs[i] == timesUs[i + 1].
timesUs[i] = timeUs;
time += referenceDuration;
timeUs = Util.scaleLargeTimestamp(time, C.MICROS_PER_SECOND, timescale);
durationsUs[i] = timeUs - timesUs[i];
atom.skipBytes(4);
offset += sizes[i];
}
return Pair.create(earliestPresentationTimeUs, new ChunkIndex(sizes, offsets, durationsUs, timesUs));
}
use of com.google.android.exoplayer2.extractor.ChunkIndex in project ExoPlayer by google.
the class DefaultSsChunkSource method getNextChunk.
@Override
public final void getNextChunk(long playbackPositionUs, long loadPositionUs, List<? extends MediaChunk> queue, ChunkHolder out) {
if (fatalError != null) {
return;
}
StreamElement streamElement = manifest.streamElements[streamElementIndex];
if (streamElement.chunkCount == 0) {
// There aren't any chunks for us to load.
out.endOfStream = !manifest.isLive;
return;
}
int chunkIndex;
if (queue.isEmpty()) {
chunkIndex = streamElement.getChunkIndex(loadPositionUs);
} else {
chunkIndex = (int) (queue.get(queue.size() - 1).getNextChunkIndex() - currentManifestChunkOffset);
if (chunkIndex < 0) {
// This is before the first chunk in the current manifest.
fatalError = new BehindLiveWindowException();
return;
}
}
if (chunkIndex >= streamElement.chunkCount) {
// This is beyond the last chunk in the current manifest.
out.endOfStream = !manifest.isLive;
return;
}
long bufferedDurationUs = loadPositionUs - playbackPositionUs;
long timeToLiveEdgeUs = resolveTimeToLiveEdgeUs(playbackPositionUs);
MediaChunkIterator[] chunkIterators = new MediaChunkIterator[trackSelection.length()];
for (int i = 0; i < chunkIterators.length; i++) {
int trackIndex = trackSelection.getIndexInTrackGroup(i);
chunkIterators[i] = new StreamElementIterator(streamElement, trackIndex, chunkIndex);
}
trackSelection.updateSelectedTrack(playbackPositionUs, bufferedDurationUs, timeToLiveEdgeUs, queue, chunkIterators);
long chunkStartTimeUs = streamElement.getStartTimeUs(chunkIndex);
long chunkEndTimeUs = chunkStartTimeUs + streamElement.getChunkDurationUs(chunkIndex);
long chunkSeekTimeUs = queue.isEmpty() ? loadPositionUs : C.TIME_UNSET;
int currentAbsoluteChunkIndex = chunkIndex + currentManifestChunkOffset;
int trackSelectionIndex = trackSelection.getSelectedIndex();
ChunkExtractor chunkExtractor = chunkExtractors[trackSelectionIndex];
int manifestTrackIndex = trackSelection.getIndexInTrackGroup(trackSelectionIndex);
Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex);
out.chunk = newMediaChunk(trackSelection.getSelectedFormat(), dataSource, uri, currentAbsoluteChunkIndex, chunkStartTimeUs, chunkEndTimeUs, chunkSeekTimeUs, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), chunkExtractor);
}
use of com.google.android.exoplayer2.extractor.ChunkIndex in project ExoPlayer by google.
the class OutputConsumerAdapterV30 method maybeObtainChunkIndex.
// Private methods.
private boolean maybeObtainChunkIndex(MediaFormat mediaFormat) {
@Nullable ByteBuffer chunkIndexSizesByteBuffer = mediaFormat.getByteBuffer(MEDIA_FORMAT_KEY_CHUNK_INDEX_SIZES);
if (chunkIndexSizesByteBuffer == null) {
return false;
}
IntBuffer chunkIndexSizes = chunkIndexSizesByteBuffer.asIntBuffer();
LongBuffer chunkIndexOffsets = Assertions.checkNotNull(mediaFormat.getByteBuffer(MEDIA_FORMAT_KEY_CHUNK_INDEX_OFFSETS)).asLongBuffer();
LongBuffer chunkIndexDurationsUs = Assertions.checkNotNull(mediaFormat.getByteBuffer(MEDIA_FORMAT_KEY_CHUNK_INDEX_DURATIONS)).asLongBuffer();
LongBuffer chunkIndexTimesUs = Assertions.checkNotNull(mediaFormat.getByteBuffer(MEDIA_FORMAT_KEY_CHUNK_INDEX_TIMES)).asLongBuffer();
int[] sizes = new int[chunkIndexSizes.remaining()];
long[] offsets = new long[chunkIndexOffsets.remaining()];
long[] durationsUs = new long[chunkIndexDurationsUs.remaining()];
long[] timesUs = new long[chunkIndexTimesUs.remaining()];
chunkIndexSizes.get(sizes);
chunkIndexOffsets.get(offsets);
chunkIndexDurationsUs.get(durationsUs);
chunkIndexTimesUs.get(timesUs);
lastChunkIndex = new ChunkIndex(sizes, offsets, durationsUs, timesUs);
extractorOutput.seekMap(lastChunkIndex);
return true;
}
Aggregations