Enable HLS sample queues as soon as possible.
Currently, the sample queues are lazily enabled when they are first read from. This causes problems when the player tries to discard buffer and the HlsSampleStreamWrapper assumes the sample queue is disabled even though it's actually enabled but hasn't been read from. This change moves setting the sample queue index of the sample stream back into HlsSampleStreamWrapper. It enables the sample queues at track selection if the queues are already built, or immediately after they have been built for chunkless preparation. Issue:#4241 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=197415741
This commit is contained in:
parent
e162d35689
commit
7b855e45e6
@ -22,6 +22,8 @@
|
|||||||
* HLS:
|
* HLS:
|
||||||
* Fix playback of livestreams with EXT-X-PROGRAM-DATE-TIME tags
|
* Fix playback of livestreams with EXT-X-PROGRAM-DATE-TIME tags
|
||||||
([#4239](https://github.com/google/ExoPlayer/issues/4239)).
|
([#4239](https://github.com/google/ExoPlayer/issues/4239)).
|
||||||
|
* Fix playback of clipped streams starting from non-keyframe positions
|
||||||
|
([#4241](https://github.com/google/ExoPlayer/issues/4241)).
|
||||||
* Caption:
|
* Caption:
|
||||||
* TTML:
|
* TTML:
|
||||||
* Fix a styling issue when there are multiple regions displayed at the same
|
* Fix a styling issue when there are multiple regions displayed at the same
|
||||||
|
@ -19,6 +19,7 @@ import com.google.android.exoplayer2.C;
|
|||||||
import com.google.android.exoplayer2.FormatHolder;
|
import com.google.android.exoplayer2.FormatHolder;
|
||||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer2.source.SampleStream;
|
import com.google.android.exoplayer2.source.SampleStream;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,6 +37,11 @@ import java.io.IOException;
|
|||||||
sampleQueueIndex = HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING;
|
sampleQueueIndex = HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void bindSampleQueue() {
|
||||||
|
Assertions.checkArgument(sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING);
|
||||||
|
sampleQueueIndex = sampleStreamWrapper.bindSampleQueueToSampleStream(trackGroupIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public void unbindSampleQueue() {
|
public void unbindSampleQueue() {
|
||||||
if (sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING) {
|
if (sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING) {
|
||||||
sampleStreamWrapper.unbindSampleQueue(trackGroupIndex);
|
sampleStreamWrapper.unbindSampleQueue(trackGroupIndex);
|
||||||
@ -48,12 +54,11 @@ import java.io.IOException;
|
|||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_NON_FATAL
|
return sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_NON_FATAL
|
||||||
|| (maybeMapToSampleQueue() && sampleStreamWrapper.isReady(sampleQueueIndex));
|
|| (hasValidSampleQueueIndex() && sampleStreamWrapper.isReady(sampleQueueIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void maybeThrowError() throws IOException {
|
public void maybeThrowError() throws IOException {
|
||||||
maybeMapToSampleQueue();
|
|
||||||
if (sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_FATAL) {
|
if (sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_FATAL) {
|
||||||
throw new SampleQueueMappingException(
|
throw new SampleQueueMappingException(
|
||||||
sampleStreamWrapper.getTrackGroups().get(trackGroupIndex).getFormat(0).sampleMimeType);
|
sampleStreamWrapper.getTrackGroups().get(trackGroupIndex).getFormat(0).sampleMimeType);
|
||||||
@ -63,22 +68,21 @@ import java.io.IOException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) {
|
||||||
return maybeMapToSampleQueue()
|
return hasValidSampleQueueIndex()
|
||||||
? sampleStreamWrapper.readData(sampleQueueIndex, formatHolder, buffer, requireFormat)
|
? sampleStreamWrapper.readData(sampleQueueIndex, formatHolder, buffer, requireFormat)
|
||||||
: C.RESULT_NOTHING_READ;
|
: C.RESULT_NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int skipData(long positionUs) {
|
public int skipData(long positionUs) {
|
||||||
return maybeMapToSampleQueue() ? sampleStreamWrapper.skipData(sampleQueueIndex, positionUs) : 0;
|
return hasValidSampleQueueIndex()
|
||||||
|
? sampleStreamWrapper.skipData(sampleQueueIndex, positionUs)
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private boolean maybeMapToSampleQueue() {
|
private boolean hasValidSampleQueueIndex() {
|
||||||
if (sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING) {
|
|
||||||
sampleQueueIndex = sampleStreamWrapper.bindSampleQueueToSampleStream(trackGroupIndex);
|
|
||||||
}
|
|
||||||
return sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING
|
return sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING
|
||||||
&& sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_NON_FATAL
|
&& sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_NON_FATAL
|
||||||
&& sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_FATAL;
|
&& sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_FATAL;
|
||||||
|
@ -102,6 +102,7 @@ import java.util.Arrays;
|
|||||||
private final Runnable maybeFinishPrepareRunnable;
|
private final Runnable maybeFinishPrepareRunnable;
|
||||||
private final Runnable onTracksEndedRunnable;
|
private final Runnable onTracksEndedRunnable;
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
|
private final ArrayList<HlsSampleStream> hlsSampleStreams;
|
||||||
|
|
||||||
private SampleQueue[] sampleQueues;
|
private SampleQueue[] sampleQueues;
|
||||||
private int[] sampleQueueTrackIds;
|
private int[] sampleQueueTrackIds;
|
||||||
@ -166,6 +167,7 @@ import java.util.Arrays;
|
|||||||
sampleQueueIsAudioVideoFlags = new boolean[0];
|
sampleQueueIsAudioVideoFlags = new boolean[0];
|
||||||
sampleQueuesEnabledStates = new boolean[0];
|
sampleQueuesEnabledStates = new boolean[0];
|
||||||
mediaChunks = new ArrayList<>();
|
mediaChunks = new ArrayList<>();
|
||||||
|
hlsSampleStreams = new ArrayList<>();
|
||||||
maybeFinishPrepareRunnable =
|
maybeFinishPrepareRunnable =
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -219,9 +221,6 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int bindSampleQueueToSampleStream(int trackGroupIndex) {
|
public int bindSampleQueueToSampleStream(int trackGroupIndex) {
|
||||||
if (trackGroupToSampleQueueIndex == null) {
|
|
||||||
return SAMPLE_QUEUE_INDEX_PENDING;
|
|
||||||
}
|
|
||||||
int sampleQueueIndex = trackGroupToSampleQueueIndex[trackGroupIndex];
|
int sampleQueueIndex = trackGroupToSampleQueueIndex[trackGroupIndex];
|
||||||
if (sampleQueueIndex == C.INDEX_UNSET) {
|
if (sampleQueueIndex == C.INDEX_UNSET) {
|
||||||
return optionalTrackGroups.indexOf(trackGroups.get(trackGroupIndex)) == C.INDEX_UNSET
|
return optionalTrackGroups.indexOf(trackGroups.get(trackGroupIndex)) == C.INDEX_UNSET
|
||||||
@ -295,6 +294,9 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
streams[i] = new HlsSampleStream(this, trackGroupIndex);
|
streams[i] = new HlsSampleStream(this, trackGroupIndex);
|
||||||
streamResetFlags[i] = true;
|
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 there's still a chance of avoiding a seek, try and seek within the sample queue.
|
||||||
if (sampleQueuesBuilt && !seekRequired) {
|
if (sampleQueuesBuilt && !seekRequired) {
|
||||||
SampleQueue sampleQueue = sampleQueues[trackGroupToSampleQueueIndex[trackGroupIndex]];
|
SampleQueue sampleQueue = sampleQueues[trackGroupToSampleQueueIndex[trackGroupIndex]];
|
||||||
@ -360,6 +362,7 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSampleStreams(streams);
|
||||||
seenFirstTrackSelection = true;
|
seenFirstTrackSelection = true;
|
||||||
return seekRequired;
|
return seekRequired;
|
||||||
}
|
}
|
||||||
@ -411,6 +414,7 @@ import java.util.Arrays;
|
|||||||
loader.release(this);
|
loader.release(this);
|
||||||
handler.removeCallbacksAndMessages(null);
|
handler.removeCallbacksAndMessages(null);
|
||||||
released = true;
|
released = true;
|
||||||
|
hlsSampleStreams.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -750,6 +754,15 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
|
private void updateSampleStreams(SampleStream[] streams) {
|
||||||
|
hlsSampleStreams.clear();
|
||||||
|
for (SampleStream stream : streams) {
|
||||||
|
if (stream != null) {
|
||||||
|
hlsSampleStreams.add((HlsSampleStream) stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean finishedReadingChunk(HlsMediaChunk chunk) {
|
private boolean finishedReadingChunk(HlsMediaChunk chunk) {
|
||||||
int chunkUid = chunk.uid;
|
int chunkUid = chunk.uid;
|
||||||
int sampleQueueCount = sampleQueues.length;
|
int sampleQueueCount = sampleQueues.length;
|
||||||
@ -807,6 +820,9 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (HlsSampleStream sampleStream : hlsSampleStreams) {
|
||||||
|
sampleStream.bindSampleQueue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.hls;
|
package com.google.android.exoplayer2.source.hls;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.source.SampleQueue;
|
import com.google.android.exoplayer2.source.SampleQueue;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -23,7 +24,7 @@ import java.io.IOException;
|
|||||||
public final class SampleQueueMappingException extends IOException {
|
public final class SampleQueueMappingException extends IOException {
|
||||||
|
|
||||||
/** @param mimeType The mime type of the track group whose mapping failed. */
|
/** @param mimeType The mime type of the track group whose mapping failed. */
|
||||||
public SampleQueueMappingException(String mimeType) {
|
public SampleQueueMappingException(@Nullable String mimeType) {
|
||||||
super("Unable to bind a sample queue to TrackGroup with mime type " + mimeType + ".");
|
super("Unable to bind a sample queue to TrackGroup with mime type " + mimeType + ".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user