From 15543f13b7d10c8280d9560d48346e28112899dc Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 7 Nov 2017 09:16:47 -0800 Subject: [PATCH] Decouple TrackGroups from SampleQueues in HlsSampleStreamWrapper This CL does not aim to introduce any functionality changes. Issue:#3149 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=174864875 --- .../source/hls/HlsSampleStream.java | 14 +-- .../source/hls/HlsSampleStreamWrapper.java | 92 ++++++++++--------- 2 files changed, 58 insertions(+), 48 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java index e423a682f3d..0388f354ce2 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java @@ -21,22 +21,22 @@ import java.io.IOException; /** - * {@link SampleStream} for a particular track group in HLS. + * {@link SampleStream} for a particular sample queue in HLS. */ /* package */ final class HlsSampleStream implements SampleStream { - public final int group; + public final int sampleQueueIndex; private final HlsSampleStreamWrapper sampleStreamWrapper; - public HlsSampleStream(HlsSampleStreamWrapper sampleStreamWrapper, int group) { + public HlsSampleStream(HlsSampleStreamWrapper sampleStreamWrapper, int sampleQueueIndex) { this.sampleStreamWrapper = sampleStreamWrapper; - this.group = group; + this.sampleQueueIndex = sampleQueueIndex; } @Override public boolean isReady() { - return sampleStreamWrapper.isReady(group); + return sampleStreamWrapper.isReady(sampleQueueIndex); } @Override @@ -46,12 +46,12 @@ public void maybeThrowError() throws IOException { @Override public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) { - return sampleStreamWrapper.readData(group, formatHolder, buffer, requireFormat); + return sampleStreamWrapper.readData(sampleQueueIndex, formatHolder, buffer, requireFormat); } @Override public int skipData(long positionUs) { - return sampleStreamWrapper.skipData(group, positionUs); + return sampleStreamWrapper.skipData(sampleQueueIndex, positionUs); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 9816e4041cd..0d2f758599c 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -89,18 +89,19 @@ public interface Callback extends SequenceableLoader.Callback(); maybeFinishPrepareRunnable = new Runnable() { @Override @@ -190,12 +193,11 @@ public TrackGroupArray getTrackGroups() { public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs, boolean forceReset) { Assertions.checkState(prepared); - int oldEnabledTrackCount = enabledTrackCount; + int oldEnabledSampleQueueCount = enabledSampleQueueCount; // Deselect old tracks. for (int i = 0; i < selections.length; i++) { if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) { - int group = ((HlsSampleStream) streams[i]).group; - setTrackGroupEnabledState(group, false); + setSampleQueueEnabledState(((HlsSampleStream) streams[i]).sampleQueueIndex, false); streams[i] = null; } } @@ -203,7 +205,8 @@ public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStre // 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 ? oldEnabledTrackCount == 0 : positionUs != lastSeekPositionUs); + || (seenFirstTrackSelection ? oldEnabledSampleQueueCount == 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. TrackSelection oldPrimaryTrackSelection = chunkSource.getTrackSelection(); @@ -213,16 +216,17 @@ public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStre if (streams[i] == null && selections[i] != null) { TrackSelection selection = selections[i]; int trackGroupIndex = trackGroups.indexOf(selection.getTrackGroup()); - setTrackGroupEnabledState(trackGroupIndex, true); + int sampleQueueIndex = trackGroupToSampleQueueIndex[trackGroupIndex]; + setSampleQueueEnabledState(sampleQueueIndex, true); if (trackGroupIndex == primaryTrackGroupIndex) { primaryTrackSelection = selection; chunkSource.selectTracks(selection); } - streams[i] = new HlsSampleStream(this, trackGroupIndex); + streams[i] = new HlsSampleStream(this, sampleQueueIndex); streamResetFlags[i] = true; // If there's still a chance of avoiding a seek, try and seek within the sample queue. if (!seekRequired) { - SampleQueue sampleQueue = sampleQueues[trackGroupIndex]; + SampleQueue sampleQueue = sampleQueues[sampleQueueIndex]; sampleQueue.rewind(); // A seek can be avoided if we're able to advance to the current playback position in the // sample queue, or if we haven't read anything from the queue since the previous seek @@ -234,7 +238,7 @@ public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStre } } - if (enabledTrackCount == 0) { + if (enabledSampleQueueCount == 0) { chunkSource.reset(); downstreamTrackFormat = null; mediaChunks.clear(); @@ -290,7 +294,7 @@ public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStre public void discardBuffer(long positionUs) { int sampleQueueCount = sampleQueues.length; for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues[i].discardTo(positionUs, false, trackGroupEnabledStates[i]); + sampleQueues[i].discardTo(positionUs, false, sampleQueuesEnabledStates[i]); } } @@ -370,8 +374,8 @@ public void onPlaylistBlacklisted(HlsUrl url, long blacklistMs) { // SampleStream implementation. - public boolean isReady(int trackGroupIndex) { - return loadingFinished || (!isPendingReset() && sampleQueues[trackGroupIndex].hasNextSample()); + public boolean isReady(int sampleQueueIndex) { + return loadingFinished || (!isPendingReset() && sampleQueues[sampleQueueIndex].hasNextSample()); } public void maybeThrowError() throws IOException { @@ -379,8 +383,8 @@ public void maybeThrowError() throws IOException { chunkSource.maybeThrowError(); } - public int readData(int trackGroupIndex, FormatHolder formatHolder, - DecoderInputBuffer buffer, boolean requireFormat) { + public int readData(int sampleQueueIndex, FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean requireFormat) { if (isPendingReset()) { return C.RESULT_NOTHING_READ; } @@ -399,12 +403,12 @@ public int readData(int trackGroupIndex, FormatHolder formatHolder, downstreamTrackFormat = trackFormat; } - return sampleQueues[trackGroupIndex].read(formatHolder, buffer, requireFormat, loadingFinished, + return sampleQueues[sampleQueueIndex].read(formatHolder, buffer, requireFormat, loadingFinished, lastSeekPositionUs); } - public int skipData(int trackGroupIndex, long positionUs) { - SampleQueue sampleQueue = sampleQueues[trackGroupIndex]; + public int skipData(int sampleQueueIndex, long positionUs) { + SampleQueue sampleQueue = sampleQueues[sampleQueueIndex]; if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { return sampleQueue.advanceToEnd(); } else { @@ -415,8 +419,9 @@ public int skipData(int trackGroupIndex, long positionUs) { private boolean finishedReadingChunk(HlsMediaChunk chunk) { int chunkUid = chunk.uid; - for (int i = 0; i < sampleQueues.length; i++) { - if (trackGroupEnabledStates[i] && sampleQueues[i].peekSourceId() == chunkUid) { + int sampleQueueCount = sampleQueues.length; + for (int i = 0; i < sampleQueueCount; i++) { + if (sampleQueuesEnabledStates[i] && sampleQueues[i].peekSourceId() == chunkUid) { return false; } } @@ -511,7 +516,7 @@ public void onLoadCanceled(Chunk loadable, long elapsedRealtimeMs, long loadDura loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded()); if (!released) { resetSampleQueues(); - if (enabledTrackCount > 0) { + if (enabledSampleQueueCount > 0) { callback.onContinueLoadingRequested(this); } } @@ -587,6 +592,11 @@ public SampleQueue track(int id, int type) { sampleQueueTrackIds[trackCount] = id; sampleQueues = Arrays.copyOf(sampleQueues, trackCount + 1); sampleQueues[trackCount] = trackOutput; + sampleQueueIsAudioVideoFlags = Arrays.copyOf(sampleQueueIsAudioVideoFlags, trackCount + 1); + sampleQueueIsAudioVideoFlags[trackCount] = type == C.TRACK_TYPE_AUDIO + || type == C.TRACK_TYPE_VIDEO; + haveAudioVideoSampleQueues |= sampleQueueIsAudioVideoFlags[trackCount]; + sampleQueuesEnabledStates = Arrays.copyOf(sampleQueuesEnabledStates, trackCount + 1); return trackOutput; } @@ -605,7 +615,9 @@ public void seekMap(SeekMap seekMap) { @Override public void onUpstreamFormatChanged(Format format) { - handler.post(maybeFinishPrepareRunnable); + if (!prepared) { + handler.post(maybeFinishPrepareRunnable); + } } // Called by the loading thread. @@ -696,17 +708,15 @@ private void buildTracks() { // Instantiate the necessary internal data-structures. primaryTrackGroupIndex = C.INDEX_UNSET; - trackGroupEnabledStates = new boolean[extractorTrackCount]; - trackGroupIsAudioVideoFlags = new boolean[extractorTrackCount]; + trackGroupToSampleQueueIndex = new int[extractorTrackCount]; + for (int i = 0; i < extractorTrackCount; i++) { + trackGroupToSampleQueueIndex[i] = i; + } // Construct the set of exposed track groups. TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount]; for (int i = 0; i < extractorTrackCount; i++) { Format sampleFormat = sampleQueues[i].getUpstreamFormat(); - String mimeType = sampleFormat.sampleMimeType; - boolean isAudioVideo = MimeTypes.isVideo(mimeType) || MimeTypes.isAudio(mimeType); - trackGroupIsAudioVideoFlags[i] = isAudioVideo; - haveAudioVideoTrackGroups |= isAudioVideo; if (i == primaryExtractorTrackIndex) { Format[] formats = new Format[chunkSourceTrackCount]; for (int j = 0; j < chunkSourceTrackCount; j++) { @@ -724,15 +734,15 @@ private void buildTracks() { } /** - * Enables or disables a specified track group. + * Enables or disables a specified sample queue. * - * @param trackGroupIndex The index of the track group. - * @param enabledState True if the group is being enabled, or false if it's being disabled. + * @param sampleQueueIndex The index of the sample queue. + * @param enabledState True if the sample queue is being enabled, or false if it's being disabled. */ - private void setTrackGroupEnabledState(int trackGroupIndex, boolean enabledState) { - Assertions.checkState(trackGroupEnabledStates[trackGroupIndex] != enabledState); - trackGroupEnabledStates[trackGroupIndex] = enabledState; - enabledTrackCount = enabledTrackCount + (enabledState ? 1 : -1); + private void setSampleQueueEnabledState(int sampleQueueIndex, boolean enabledState) { + Assertions.checkState(sampleQueuesEnabledStates[sampleQueueIndex] != enabledState); + sampleQueuesEnabledStates[sampleQueueIndex] = enabledState; + enabledSampleQueueCount = enabledSampleQueueCount + (enabledState ? 1 : -1); } /** @@ -769,8 +779,8 @@ private boolean isPendingReset() { * @return Whether the in-buffer seek was successful. */ private boolean seekInsideBufferUs(long positionUs) { - int trackCount = sampleQueues.length; - for (int i = 0; i < trackCount; i++) { + int sampleQueueCount = sampleQueues.length; + for (int i = 0; i < sampleQueueCount; i++) { SampleQueue sampleQueue = sampleQueues[i]; sampleQueue.rewind(); boolean seekInsideQueue = sampleQueue.advanceTo(positionUs, true, false) @@ -779,7 +789,7 @@ private boolean seekInsideBufferUs(long positionUs) { // is successful. We ignore whether seeks within non-AV queues are successful in this case, as // they may be sparse or poorly interleaved. If we only have non-AV tracks then a seek is // successful only if the seek into every queue succeeds. - if (!seekInsideQueue && (trackGroupIsAudioVideoFlags[i] || !haveAudioVideoTrackGroups)) { + if (!seekInsideQueue && (sampleQueueIsAudioVideoFlags[i] || !haveAudioVideoSampleQueues)) { return false; } sampleQueue.discardToRead();