use of com.google.android.exoplayer2.source.SampleQueue in project ExoPlayer by google.
the class SampleQueueTest method writeTestData.
/**
* Writes the specified test data to {@code sampleQueue}.
*/
@SuppressWarnings("ReferenceEquality")
private void writeTestData(byte[] data, int[] sampleSizes, int[] sampleOffsets, long[] sampleTimestamps, Format[] sampleFormats, int[] sampleFlags) {
sampleQueue.sampleData(new ParsableByteArray(data), data.length);
Format format = null;
for (int i = 0; i < sampleTimestamps.length; i++) {
if (sampleFormats[i] != format) {
sampleQueue.format(sampleFormats[i]);
format = sampleFormats[i];
}
sampleQueue.sampleMetadata(sampleTimestamps[i], sampleFlags[i], sampleSizes[i], sampleOffsets[i], (sampleFlags[i] & C.BUFFER_FLAG_ENCRYPTED) != 0 ? CRYPTO_DATA : null);
}
}
use of com.google.android.exoplayer2.source.SampleQueue in project ExoPlayer by google.
the class RtspMediaPeriod method buildTrackGroups.
private static ImmutableList<TrackGroup> buildTrackGroups(ImmutableList<RtspLoaderWrapper> rtspLoaderWrappers) {
ImmutableList.Builder<TrackGroup> listBuilder = new ImmutableList.Builder<>();
SampleQueue sampleQueue;
for (int i = 0; i < rtspLoaderWrappers.size(); i++) {
sampleQueue = rtspLoaderWrappers.get(i).sampleQueue;
listBuilder.add(new TrackGroup(/* id= */
Integer.toString(i), checkNotNull(sampleQueue.getUpstreamFormat())));
}
return listBuilder.build();
}
use of com.google.android.exoplayer2.source.SampleQueue in project ExoPlayer by google.
the class HlsSampleStreamWrapper method initMediaChunkLoad.
// Called by the consuming thread, but only when there is no loading thread.
/**
* Performs initialization for a media chunk that's about to start loading.
*
* @param chunk The media chunk that's about to start loading.
*/
private void initMediaChunkLoad(HlsMediaChunk chunk) {
sourceChunk = chunk;
upstreamTrackFormat = chunk.trackFormat;
pendingResetPositionUs = C.TIME_UNSET;
mediaChunks.add(chunk);
ImmutableList.Builder<Integer> sampleQueueWriteIndicesBuilder = ImmutableList.builder();
for (SampleQueue sampleQueue : sampleQueues) {
sampleQueueWriteIndicesBuilder.add(sampleQueue.getWriteIndex());
}
chunk.init(/* output= */
this, sampleQueueWriteIndicesBuilder.build());
for (HlsSampleQueue sampleQueue : sampleQueues) {
sampleQueue.setSourceChunk(chunk);
if (chunk.shouldSpliceIn) {
sampleQueue.splice();
}
}
}
use of com.google.android.exoplayer2.source.SampleQueue in project ExoPlayer by google.
the class HlsSampleStreamWrapper method seekInsideBufferUs.
/**
* Attempts to seek to the specified position within the sample queues.
*
* @param positionUs The seek position in microseconds.
* @return Whether the in-buffer seek was successful.
*/
private boolean seekInsideBufferUs(long positionUs) {
int sampleQueueCount = sampleQueues.length;
for (int i = 0; i < sampleQueueCount; i++) {
SampleQueue sampleQueue = sampleQueues[i];
boolean seekInsideQueue = sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */
false);
// successful only if the seek into every queue succeeds.
if (!seekInsideQueue && (sampleQueueIsAudioVideoFlags[i] || !haveAudioVideoSampleQueues)) {
return false;
}
}
return true;
}
use of com.google.android.exoplayer2.source.SampleQueue in project ExoPlayer by google.
the class HlsSampleStreamWrapper method selectTracks.
/**
* Called by the parent {@link HlsMediaPeriod} when a track selection occurs.
*
* @param selections The renderer track selections.
* @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained
* for each selection. A {@code true} value indicates that the selection is unchanged, and
* that the caller does not require that the sample stream be recreated.
* @param streams The existing sample streams, which will be updated to reflect the provided
* selections.
* @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that
* have been retained but with the requirement that the consuming renderer be reset.
* @param positionUs The current playback position in microseconds.
* @param forceReset If true then a reset is forced (i.e. a seek will be performed with in-buffer
* seeking disabled).
* @return Whether this wrapper requires the parent {@link HlsMediaPeriod} to perform a seek as
* part of the track selection.
*/
public boolean selectTracks(@NullableType ExoTrackSelection[] selections, boolean[] mayRetainStreamFlags, @NullableType SampleStream[] streams, boolean[] streamResetFlags, long positionUs, boolean forceReset) {
assertIsPrepared();
int oldEnabledTrackGroupCount = enabledTrackGroupCount;
// Deselect old tracks.
for (int i = 0; i < selections.length; i++) {
HlsSampleStream stream = (HlsSampleStream) streams[i];
if (stream != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
enabledTrackGroupCount--;
stream.unbindSampleQueue();
streams[i] = null;
}
}
// We'll always need to seek if we're being forced to reset, or if this is a first selection to
// a position other than the one we started preparing with, or if we're making a selection
// having previously disabled all tracks.
boolean seekRequired = forceReset || (seenFirstTrackSelection ? oldEnabledTrackGroupCount == 0 : positionUs != lastSeekPositionUs);
// Get the old (i.e. current before the loop below executes) primary track selection. The new
// primary selection will equal the old one unless it's changed in the loop.
ExoTrackSelection oldPrimaryTrackSelection = chunkSource.getTrackSelection();
ExoTrackSelection primaryTrackSelection = oldPrimaryTrackSelection;
// Select new tracks.
for (int i = 0; i < selections.length; i++) {
ExoTrackSelection selection = selections[i];
if (selection == null) {
continue;
}
int trackGroupIndex = trackGroups.indexOf(selection.getTrackGroup());
if (trackGroupIndex == primaryTrackGroupIndex) {
primaryTrackSelection = selection;
chunkSource.setTrackSelection(selection);
}
if (streams[i] == null) {
enabledTrackGroupCount++;
streams[i] = new HlsSampleStream(this, trackGroupIndex);
streamResetFlags[i] = true;
if (trackGroupToSampleQueueIndex != null) {
((HlsSampleStream) streams[i]).bindSampleQueue();
// If there's still a chance of avoiding a seek, try and seek within the sample queue.
if (!seekRequired) {
SampleQueue sampleQueue = sampleQueues[trackGroupToSampleQueueIndex[trackGroupIndex]];
// A seek can be avoided if we're able to seek to the current playback position in
// the sample queue, or if we haven't read anything from the queue since the previous
// seek (this case is common for sparse tracks such as metadata tracks). In all other
// cases a seek is required.
seekRequired = !sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */
true) && sampleQueue.getReadIndex() != 0;
}
}
}
}
if (enabledTrackGroupCount == 0) {
chunkSource.reset();
downstreamTrackFormat = null;
pendingResetUpstreamFormats = true;
mediaChunks.clear();
if (loader.isLoading()) {
if (sampleQueuesBuilt) {
// Discard as much as we can synchronously.
for (SampleQueue sampleQueue : sampleQueues) {
sampleQueue.discardToEnd();
}
}
loader.cancelLoading();
} else {
resetSampleQueues();
}
} else {
if (!mediaChunks.isEmpty() && !Util.areEqual(primaryTrackSelection, oldPrimaryTrackSelection)) {
// The primary track selection has changed and we have buffered media. The buffered media
// may need to be discarded.
boolean primarySampleQueueDirty = false;
if (!seenFirstTrackSelection) {
long bufferedDurationUs = positionUs < 0 ? -positionUs : 0;
HlsMediaChunk lastMediaChunk = getLastMediaChunk();
MediaChunkIterator[] mediaChunkIterators = chunkSource.createMediaChunkIterators(lastMediaChunk, positionUs);
primaryTrackSelection.updateSelectedTrack(positionUs, bufferedDurationUs, C.TIME_UNSET, readOnlyMediaChunks, mediaChunkIterators);
int chunkIndex = chunkSource.getTrackGroup().indexOf(lastMediaChunk.trackFormat);
if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) {
// This is the first selection and the chunk loaded during preparation does not match
// the initially selected format.
primarySampleQueueDirty = true;
}
} else {
// The primary sample queue contains media buffered for the old primary track selection.
primarySampleQueueDirty = true;
}
if (primarySampleQueueDirty) {
forceReset = true;
seekRequired = true;
pendingResetUpstreamFormats = true;
}
}
if (seekRequired) {
seekToUs(positionUs, forceReset);
// We'll need to reset renderers consuming from all streams due to the seek.
for (int i = 0; i < streams.length; i++) {
if (streams[i] != null) {
streamResetFlags[i] = true;
}
}
}
}
updateSampleStreams(streams);
seenFirstTrackSelection = true;
return seekRequired;
}
Aggregations