Refactor #6.HLS.1
1. Merge HlsOutput and HlsSampleSource -> HlsTrackStreamWrapper. 2. Rename HlsSource -> HlsSampleSource2. This will be renamed to HlsSampleSource in a subsequent CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=122415970
This commit is contained in:
parent
51cf8bed29
commit
770f2c2c58
@ -29,7 +29,7 @@ import com.google.android.exoplayer.demo.player.DemoPlayer;
|
|||||||
import com.google.android.exoplayer.demo.ui.TrackSelectionHelper;
|
import com.google.android.exoplayer.demo.ui.TrackSelectionHelper;
|
||||||
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
||||||
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
||||||
import com.google.android.exoplayer.hls.HlsSource;
|
import com.google.android.exoplayer.hls.HlsSampleSource2;
|
||||||
import com.google.android.exoplayer.metadata.id3.GeobFrame;
|
import com.google.android.exoplayer.metadata.id3.GeobFrame;
|
||||||
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
||||||
import com.google.android.exoplayer.metadata.id3.PrivFrame;
|
import com.google.android.exoplayer.metadata.id3.PrivFrame;
|
||||||
@ -278,7 +278,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|||||||
return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
||||||
player.getMainHandler(), player);
|
player.getMainHandler(), player);
|
||||||
case Util.TYPE_HLS:
|
case Util.TYPE_HLS:
|
||||||
return new HlsSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
return new HlsSampleSource2(uri, dataSourceFactory, player.getBandwidthMeter(),
|
||||||
player.getMainHandler(), player);
|
player.getMainHandler(), player);
|
||||||
case Util.TYPE_OTHER:
|
case Util.TYPE_OTHER:
|
||||||
Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
||||||
|
@ -461,7 +461,7 @@ public class HlsChunkSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when the {@link HlsSampleSource} has finished loading a chunk obtained from this
|
* Invoked when the {@link HlsTrackStreamWrapper} has finished loading a chunk obtained from this
|
||||||
* source.
|
* source.
|
||||||
*
|
*
|
||||||
* @param chunk The chunk whose load has been completed.
|
* @param chunk The chunk whose load has been completed.
|
||||||
@ -480,8 +480,8 @@ public class HlsChunkSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when the {@link HlsSampleSource} encounters an error loading a chunk obtained from
|
* Invoked when the {@link HlsTrackStreamWrapper} encounters an error loading a chunk obtained
|
||||||
* this source.
|
* from this source.
|
||||||
*
|
*
|
||||||
* @param chunk The chunk whose load encountered the error.
|
* @param chunk The chunk whose load encountered the error.
|
||||||
* @param cancelable Whether the load can be canceled.
|
* @param cancelable Whether the load can be canceled.
|
||||||
|
@ -59,9 +59,9 @@ import java.io.IOException;
|
|||||||
* @param discontinuitySequenceNumber The discontinuity sequence number of the chunk.
|
* @param discontinuitySequenceNumber The discontinuity sequence number of the chunk.
|
||||||
* @param extractor The extractor to parse samples from the data.
|
* @param extractor The extractor to parse samples from the data.
|
||||||
* @param extractorNeedsInit Whether the extractor needs initializing with the target
|
* @param extractorNeedsInit Whether the extractor needs initializing with the target
|
||||||
* {@link HlsOutput}.
|
* {@link HlsTrackStreamWrapper}.
|
||||||
* @param shouldSpliceIn Whether the samples parsed from this chunk should be spliced into any
|
* @param shouldSpliceIn Whether the samples parsed from this chunk should be spliced into any
|
||||||
* samples already queued to the {@link HlsOutput}.
|
* samples already queued to the {@link HlsTrackStreamWrapper}.
|
||||||
* @param encryptionKey For AES encryption chunks, the encryption key.
|
* @param encryptionKey For AES encryption chunks, the encryption key.
|
||||||
* @param encryptionIv For AES encryption chunks, the encryption initialization vector.
|
* @param encryptionIv For AES encryption chunks, the encryption initialization vector.
|
||||||
*/
|
*/
|
||||||
@ -80,12 +80,12 @@ import java.io.IOException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the chunk for loading, setting the {@link HlsOutput} that will receive samples as
|
* Initializes the chunk for loading, setting the {@link HlsTrackStreamWrapper} that will receive
|
||||||
* they are loaded.
|
* samples as they are loaded.
|
||||||
*
|
*
|
||||||
* @param output The output that will receive the loaded samples.
|
* @param output The output that will receive the loaded samples.
|
||||||
*/
|
*/
|
||||||
public void init(HlsOutput output) {
|
public void init(HlsTrackStreamWrapper output) {
|
||||||
if (shouldSpliceIn) {
|
if (shouldSpliceIn) {
|
||||||
output.splice();
|
output.splice();
|
||||||
}
|
}
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.exoplayer.hls;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
|
||||||
import com.google.android.exoplayer.extractor.ExtractorOutput;
|
|
||||||
import com.google.android.exoplayer.extractor.SeekMap;
|
|
||||||
import com.google.android.exoplayer.upstream.Allocator;
|
|
||||||
|
|
||||||
import android.util.SparseArray;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link ExtractorOutput} for HLS playbacks.
|
|
||||||
*/
|
|
||||||
/* package */ final class HlsOutput implements ExtractorOutput {
|
|
||||||
|
|
||||||
private final Allocator allocator;
|
|
||||||
private final SparseArray<DefaultTrackOutput> sampleQueues = new SparseArray<>();
|
|
||||||
|
|
||||||
private boolean prepared;
|
|
||||||
private DefaultTrackOutput[] trackOutputArray;
|
|
||||||
private volatile boolean tracksBuilt;
|
|
||||||
|
|
||||||
public HlsOutput(Allocator allocator) {
|
|
||||||
this.allocator = allocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the consuming thread.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the output, or does nothing if the output is already prepared.
|
|
||||||
*
|
|
||||||
* @return True if the output is prepared, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean prepare() {
|
|
||||||
if (prepared) {
|
|
||||||
return true;
|
|
||||||
} else if (!tracksBuilt) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (trackOutputArray == null) {
|
|
||||||
trackOutputArray = new DefaultTrackOutput[sampleQueues.size()];
|
|
||||||
for (int i = 0; i < trackOutputArray.length; i++) {
|
|
||||||
trackOutputArray[i] = sampleQueues.valueAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (DefaultTrackOutput sampleQueue : trackOutputArray) {
|
|
||||||
if (sampleQueue.getUpstreamFormat() == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prepared = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the array of track outputs, or null if the output is not yet prepared.
|
|
||||||
*/
|
|
||||||
public DefaultTrackOutput[] getTrackOutputs() {
|
|
||||||
return trackOutputArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the consuming thread, but only when there is no loading thread.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all track outputs.
|
|
||||||
*/
|
|
||||||
public void clear() {
|
|
||||||
for (int i = 0; i < sampleQueues.size(); i++) {
|
|
||||||
sampleQueues.valueAt(i).clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates to all track outputs that they should splice in subsequently queued samples.
|
|
||||||
*/
|
|
||||||
public void splice() {
|
|
||||||
for (int i = 0; i < sampleQueues.size(); i++) {
|
|
||||||
sampleQueues.valueAt(i).splice();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractorOutput implementation. Called by the loading thread.
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DefaultTrackOutput track(int id) {
|
|
||||||
if (sampleQueues.indexOfKey(id) >= 0) {
|
|
||||||
return sampleQueues.get(id);
|
|
||||||
}
|
|
||||||
DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator);
|
|
||||||
sampleQueues.put(id, trackOutput);
|
|
||||||
return trackOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void endTracks() {
|
|
||||||
tracksBuilt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekMap(SeekMap seekMap) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -46,21 +46,22 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* A {@link SampleSource} for HLS streams.
|
* A {@link SampleSource} for HLS streams.
|
||||||
*/
|
*/
|
||||||
public final class HlsSource implements SampleSource {
|
public final class HlsSampleSource2 implements SampleSource {
|
||||||
|
|
||||||
private final ManifestFetcher<HlsPlaylist> manifestFetcher;
|
private final ManifestFetcher<HlsPlaylist> manifestFetcher;
|
||||||
private final HlsSampleSource[] sources;
|
private final HlsTrackStreamWrapper[] trackStreamWrappers;
|
||||||
private final IdentityHashMap<TrackStream, HlsSampleSource> trackStreamSources;
|
private final IdentityHashMap<TrackStream, HlsTrackStreamWrapper> trackStreamSources;
|
||||||
private final int[] selectedTrackCounts;
|
private final int[] selectedTrackCounts;
|
||||||
|
|
||||||
private boolean prepared;
|
private boolean prepared;
|
||||||
private boolean seenFirstTrackSelection;
|
private boolean seenFirstTrackSelection;
|
||||||
private long durationUs;
|
private long durationUs;
|
||||||
private TrackGroupArray trackGroups;
|
private TrackGroupArray trackGroups;
|
||||||
private HlsSampleSource[] enabledSources;
|
private HlsTrackStreamWrapper[] enabledTrackStreamWrappers;
|
||||||
|
|
||||||
public HlsSource(Uri uri, DataSourceFactory dataSourceFactory, BandwidthMeter bandwidthMeter,
|
public HlsSampleSource2(Uri uri, DataSourceFactory dataSourceFactory,
|
||||||
Handler eventHandler, ChunkTrackStreamEventListener eventListener) {
|
BandwidthMeter bandwidthMeter, Handler eventHandler,
|
||||||
|
ChunkTrackStreamEventListener eventListener) {
|
||||||
HlsPlaylistParser parser = new HlsPlaylistParser();
|
HlsPlaylistParser parser = new HlsPlaylistParser();
|
||||||
DataSource manifestDataSource = dataSourceFactory.createDataSource();
|
DataSource manifestDataSource = dataSourceFactory.createDataSource();
|
||||||
manifestFetcher = new ManifestFetcher<>(uri, manifestDataSource, parser);
|
manifestFetcher = new ManifestFetcher<>(uri, manifestDataSource, parser);
|
||||||
@ -73,23 +74,25 @@ public final class HlsSource implements SampleSource {
|
|||||||
HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_DEFAULT,
|
HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_DEFAULT,
|
||||||
defaultDataSource, timestampAdjusterProvider,
|
defaultDataSource, timestampAdjusterProvider,
|
||||||
new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter));
|
new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter));
|
||||||
HlsSampleSource defaultSampleSource = new HlsSampleSource(defaultChunkSource, loadControl,
|
HlsTrackStreamWrapper defaultTrackStreamWrapper = new HlsTrackStreamWrapper(defaultChunkSource,
|
||||||
C.DEFAULT_MUXED_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_VIDEO);
|
loadControl, C.DEFAULT_MUXED_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_VIDEO);
|
||||||
|
|
||||||
DataSource audioDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
DataSource audioDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
||||||
HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_AUDIO,
|
HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_AUDIO,
|
||||||
audioDataSource, timestampAdjusterProvider, null);
|
audioDataSource, timestampAdjusterProvider, null);
|
||||||
HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl,
|
HlsTrackStreamWrapper audioTrackStreamWrapper = new HlsTrackStreamWrapper(audioChunkSource,
|
||||||
C.DEFAULT_AUDIO_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_AUDIO);
|
loadControl, C.DEFAULT_AUDIO_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_AUDIO);
|
||||||
|
|
||||||
DataSource subtitleDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
DataSource subtitleDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
||||||
HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_TEXT,
|
HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_TEXT,
|
||||||
subtitleDataSource, timestampAdjusterProvider, null);
|
subtitleDataSource, timestampAdjusterProvider, null);
|
||||||
HlsSampleSource subtitleSampleSource = new HlsSampleSource(subtitleChunkSource, loadControl,
|
HlsTrackStreamWrapper subtitleTrackStreamWrapper = new HlsTrackStreamWrapper(
|
||||||
C.DEFAULT_TEXT_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_TEXT);
|
subtitleChunkSource, loadControl, C.DEFAULT_TEXT_BUFFER_SIZE, eventHandler, eventListener,
|
||||||
|
C.TRACK_TYPE_TEXT);
|
||||||
|
|
||||||
sources = new HlsSampleSource[] {defaultSampleSource, audioSampleSource, subtitleSampleSource};
|
trackStreamWrappers = new HlsTrackStreamWrapper[] {defaultTrackStreamWrapper,
|
||||||
selectedTrackCounts = new int[sources.length];
|
audioTrackStreamWrapper, subtitleTrackStreamWrapper};
|
||||||
|
selectedTrackCounts = new int[trackStreamWrappers.length];
|
||||||
trackStreamSources = new IdentityHashMap<>();
|
trackStreamSources = new IdentityHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,29 +101,29 @@ public final class HlsSource implements SampleSource {
|
|||||||
if (prepared) {
|
if (prepared) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
boolean sourcesPrepared = true;
|
boolean trackStreamWrappersPrepared = true;
|
||||||
for (HlsSampleSource source : sources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
|
||||||
sourcesPrepared &= source.prepare(positionUs);
|
trackStreamWrappersPrepared &= trackStreamWrapper.prepare(positionUs);
|
||||||
}
|
}
|
||||||
if (!sourcesPrepared) {
|
if (!trackStreamWrappersPrepared) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
durationUs = 0;
|
durationUs = 0;
|
||||||
int totalTrackGroupCount = 0;
|
int totalTrackGroupCount = 0;
|
||||||
for (HlsSampleSource source : sources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
|
||||||
totalTrackGroupCount += source.getTrackGroups().length;
|
totalTrackGroupCount += trackStreamWrapper.getTrackGroups().length;
|
||||||
if (durationUs != C.UNSET_TIME_US) {
|
if (durationUs != C.UNSET_TIME_US) {
|
||||||
long sourceDurationUs = source.getDurationUs();
|
long wrapperDurationUs = trackStreamWrapper.getDurationUs();
|
||||||
durationUs = sourceDurationUs == C.UNSET_TIME_US
|
durationUs = wrapperDurationUs == C.UNSET_TIME_US
|
||||||
? C.UNSET_TIME_US : Math.max(durationUs, sourceDurationUs);
|
? C.UNSET_TIME_US : Math.max(durationUs, wrapperDurationUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount];
|
TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount];
|
||||||
int trackGroupIndex = 0;
|
int trackGroupIndex = 0;
|
||||||
for (HlsSampleSource source : sources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
|
||||||
int sourceTrackGroupCount = source.getTrackGroups().length;
|
int wrapperTrackGroupCount = trackStreamWrapper.getTrackGroups().length;
|
||||||
for (int j = 0; j < sourceTrackGroupCount; j++) {
|
for (int j = 0; j < wrapperTrackGroupCount; j++) {
|
||||||
trackGroupArray[trackGroupIndex++] = source.getTrackGroups().get(j);
|
trackGroupArray[trackGroupIndex++] = trackStreamWrapper.getTrackGroups().get(j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackGroups = new TrackGroupArray(trackGroupArray);
|
trackGroups = new TrackGroupArray(trackGroupArray);
|
||||||
@ -143,21 +146,21 @@ public final class HlsSource implements SampleSource {
|
|||||||
List<TrackSelection> newSelections, long positionUs) {
|
List<TrackSelection> newSelections, long positionUs) {
|
||||||
Assertions.checkState(prepared);
|
Assertions.checkState(prepared);
|
||||||
TrackStream[] newStreams = new TrackStream[newSelections.size()];
|
TrackStream[] newStreams = new TrackStream[newSelections.size()];
|
||||||
// Select tracks for each source.
|
// Select tracks for each wrapper.
|
||||||
int enabledSourceCount = 0;
|
int enabledTrackStreamWrapperCount = 0;
|
||||||
for (int i = 0; i < sources.length; i++) {
|
for (int i = 0; i < trackStreamWrappers.length; i++) {
|
||||||
selectedTrackCounts[i] += selectTracks(sources[i], oldStreams, newSelections, positionUs,
|
selectedTrackCounts[i] += selectTracks(trackStreamWrappers[i], oldStreams, newSelections,
|
||||||
newStreams);
|
positionUs, newStreams);
|
||||||
if (selectedTrackCounts[i] > 0) {
|
if (selectedTrackCounts[i] > 0) {
|
||||||
enabledSourceCount++;
|
enabledTrackStreamWrapperCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the enabled sources.
|
// Update the enabled wrappers.
|
||||||
enabledSources = new HlsSampleSource[enabledSourceCount];
|
enabledTrackStreamWrappers = new HlsTrackStreamWrapper[enabledTrackStreamWrapperCount];
|
||||||
enabledSourceCount = 0;
|
enabledTrackStreamWrapperCount = 0;
|
||||||
for (int i = 0; i < sources.length; i++) {
|
for (int i = 0; i < trackStreamWrappers.length; i++) {
|
||||||
if (selectedTrackCounts[i] > 0) {
|
if (selectedTrackCounts[i] > 0) {
|
||||||
enabledSources[enabledSourceCount++] = sources[i];
|
enabledTrackStreamWrappers[enabledTrackStreamWrapperCount++] = trackStreamWrappers[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
seenFirstTrackSelection = true;
|
seenFirstTrackSelection = true;
|
||||||
@ -166,16 +169,16 @@ public final class HlsSource implements SampleSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void continueBuffering(long positionUs) {
|
public void continueBuffering(long positionUs) {
|
||||||
for (HlsSampleSource source : enabledSources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : enabledTrackStreamWrappers) {
|
||||||
source.continueBuffering(positionUs);
|
trackStreamWrapper.continueBuffering(positionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long readReset() {
|
public long readReset() {
|
||||||
long resetPositionUs = C.UNSET_TIME_US;
|
long resetPositionUs = C.UNSET_TIME_US;
|
||||||
for (HlsSampleSource source : enabledSources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : enabledTrackStreamWrappers) {
|
||||||
long childResetPositionUs = source.readReset();
|
long childResetPositionUs = trackStreamWrapper.readReset();
|
||||||
if (resetPositionUs == C.UNSET_TIME_US) {
|
if (resetPositionUs == C.UNSET_TIME_US) {
|
||||||
resetPositionUs = childResetPositionUs;
|
resetPositionUs = childResetPositionUs;
|
||||||
} else if (childResetPositionUs != C.UNSET_TIME_US) {
|
} else if (childResetPositionUs != C.UNSET_TIME_US) {
|
||||||
@ -188,12 +191,12 @@ public final class HlsSource implements SampleSource {
|
|||||||
@Override
|
@Override
|
||||||
public long getBufferedPositionUs() {
|
public long getBufferedPositionUs() {
|
||||||
long bufferedPositionUs = durationUs != C.UNSET_TIME_US ? durationUs : Long.MAX_VALUE;
|
long bufferedPositionUs = durationUs != C.UNSET_TIME_US ? durationUs : Long.MAX_VALUE;
|
||||||
for (HlsSampleSource source : enabledSources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : enabledTrackStreamWrappers) {
|
||||||
long rendererBufferedPositionUs = source.getBufferedPositionUs();
|
long rendererBufferedPositionUs = trackStreamWrapper.getBufferedPositionUs();
|
||||||
if (rendererBufferedPositionUs == C.UNSET_TIME_US) {
|
if (rendererBufferedPositionUs == C.UNSET_TIME_US) {
|
||||||
return C.UNSET_TIME_US;
|
return C.UNSET_TIME_US;
|
||||||
} else if (rendererBufferedPositionUs == C.END_OF_SOURCE_US) {
|
} else if (rendererBufferedPositionUs == C.END_OF_SOURCE_US) {
|
||||||
// This source is fully buffered.
|
// This wrapper is fully buffered.
|
||||||
} else {
|
} else {
|
||||||
bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs);
|
bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs);
|
||||||
}
|
}
|
||||||
@ -203,39 +206,40 @@ public final class HlsSource implements SampleSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekToUs(long positionUs) {
|
public void seekToUs(long positionUs) {
|
||||||
for (HlsSampleSource source : enabledSources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : enabledTrackStreamWrappers) {
|
||||||
source.seekToUs(positionUs);
|
trackStreamWrapper.seekToUs(positionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
manifestFetcher.release();
|
manifestFetcher.release();
|
||||||
for (HlsSampleSource source : sources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
|
||||||
source.release();
|
trackStreamWrapper.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private int selectTracks(HlsSampleSource source, List<TrackStream> allOldStreams,
|
private int selectTracks(HlsTrackStreamWrapper trackStreamWrapper,
|
||||||
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
List<TrackStream> allOldStreams, List<TrackSelection> allNewSelections, long positionUs,
|
||||||
|
TrackStream[] allNewStreams) {
|
||||||
// Get the subset of the old streams for the source.
|
// Get the subset of the old streams for the source.
|
||||||
ArrayList<TrackStream> oldStreams = new ArrayList<>();
|
ArrayList<TrackStream> oldStreams = new ArrayList<>();
|
||||||
for (int i = 0; i < allOldStreams.size(); i++) {
|
for (int i = 0; i < allOldStreams.size(); i++) {
|
||||||
TrackStream stream = allOldStreams.get(i);
|
TrackStream stream = allOldStreams.get(i);
|
||||||
if (trackStreamSources.get(stream) == source) {
|
if (trackStreamSources.get(stream) == trackStreamWrapper) {
|
||||||
trackStreamSources.remove(stream);
|
trackStreamSources.remove(stream);
|
||||||
oldStreams.add(stream);
|
oldStreams.add(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get the subset of the new selections for the source.
|
// Get the subset of the new selections for the wrapper.
|
||||||
ArrayList<TrackSelection> newSelections = new ArrayList<>();
|
ArrayList<TrackSelection> newSelections = new ArrayList<>();
|
||||||
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
|
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
|
||||||
for (int i = 0; i < allNewSelections.size(); i++) {
|
for (int i = 0; i < allNewSelections.size(); i++) {
|
||||||
TrackSelection selection = allNewSelections.get(i);
|
TrackSelection selection = allNewSelections.get(i);
|
||||||
Pair<HlsSampleSource, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
|
Pair<HlsTrackStreamWrapper, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
|
||||||
if (sourceAndGroup.first == source) {
|
if (sourceAndGroup.first == trackStreamWrapper) {
|
||||||
newSelectionOriginalIndices[newSelections.size()] = i;
|
newSelectionOriginalIndices[newSelections.size()] = i;
|
||||||
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
|
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
|
||||||
}
|
}
|
||||||
@ -245,20 +249,21 @@ public final class HlsSource implements SampleSource {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Perform the selection.
|
// Perform the selection.
|
||||||
TrackStream[] newStreams = source.selectTracks(oldStreams, newSelections, positionUs);
|
TrackStream[] newStreams = trackStreamWrapper.selectTracks(oldStreams, newSelections,
|
||||||
|
positionUs);
|
||||||
for (int j = 0; j < newStreams.length; j++) {
|
for (int j = 0; j < newStreams.length; j++) {
|
||||||
allNewStreams[newSelectionOriginalIndices[j]] = newStreams[j];
|
allNewStreams[newSelectionOriginalIndices[j]] = newStreams[j];
|
||||||
trackStreamSources.put(newStreams[j], source);
|
trackStreamSources.put(newStreams[j], trackStreamWrapper);
|
||||||
}
|
}
|
||||||
return newSelections.size() - oldStreams.size();
|
return newSelections.size() - oldStreams.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<HlsSampleSource, Integer> getSourceAndGroup(int group) {
|
private Pair<HlsTrackStreamWrapper, Integer> getSourceAndGroup(int group) {
|
||||||
int totalTrackGroupCount = 0;
|
int totalTrackGroupCount = 0;
|
||||||
for (HlsSampleSource source : sources) {
|
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
|
||||||
int sourceTrackGroupCount = source.getTrackGroups().length;
|
int sourceTrackGroupCount = trackStreamWrapper.getTrackGroups().length;
|
||||||
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
||||||
return Pair.create(source, group - totalTrackGroupCount);
|
return Pair.create(trackStreamWrapper, group - totalTrackGroupCount);
|
||||||
}
|
}
|
||||||
totalTrackGroupCount += sourceTrackGroupCount;
|
totalTrackGroupCount += sourceTrackGroupCount;
|
||||||
}
|
}
|
@ -20,7 +20,6 @@ import com.google.android.exoplayer.DecoderInputBuffer;
|
|||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
import com.google.android.exoplayer.LoadControl;
|
import com.google.android.exoplayer.LoadControl;
|
||||||
import com.google.android.exoplayer.SampleSource;
|
|
||||||
import com.google.android.exoplayer.TrackGroup;
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
import com.google.android.exoplayer.TrackSelection;
|
import com.google.android.exoplayer.TrackSelection;
|
||||||
@ -30,6 +29,8 @@ import com.google.android.exoplayer.chunk.ChunkHolder;
|
|||||||
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
|
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
|
||||||
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener.EventDispatcher;
|
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
||||||
|
import com.google.android.exoplayer.extractor.ExtractorOutput;
|
||||||
|
import com.google.android.exoplayer.extractor.SeekMap;
|
||||||
import com.google.android.exoplayer.upstream.Loader;
|
import com.google.android.exoplayer.upstream.Loader;
|
||||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
@ -37,15 +38,17 @@ import com.google.android.exoplayer.util.MimeTypes;
|
|||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link SampleSource} for HLS streams.
|
* Loads {@link HlsMediaChunk}s obtained from a {@link HlsChunkSource}, and provides
|
||||||
|
* {@link TrackStream}s from which the loaded media can be consumed.
|
||||||
*/
|
*/
|
||||||
public final class HlsSampleSource implements Loader.Callback {
|
/* package */ final class HlsTrackStreamWrapper implements Loader.Callback, ExtractorOutput {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default minimum number of times to retry loading data prior to failing.
|
* The default minimum number of times to retry loading data prior to failing.
|
||||||
@ -59,18 +62,19 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
|
|
||||||
private final Loader loader;
|
private final Loader loader;
|
||||||
private final HlsChunkSource chunkSource;
|
private final HlsChunkSource chunkSource;
|
||||||
|
private final SparseArray<DefaultTrackOutput> sampleQueues;
|
||||||
private final LinkedList<HlsMediaChunk> mediaChunks;
|
private final LinkedList<HlsMediaChunk> mediaChunks;
|
||||||
private final HlsOutput output;
|
|
||||||
private final int bufferSizeContribution;
|
private final int bufferSizeContribution;
|
||||||
private final ChunkHolder nextChunkHolder;
|
private final ChunkHolder nextChunkHolder;
|
||||||
private final EventDispatcher eventDispatcher;
|
private final EventDispatcher eventDispatcher;
|
||||||
private final LoadControl loadControl;
|
private final LoadControl loadControl;
|
||||||
|
|
||||||
|
private volatile boolean sampleQueuesBuilt;
|
||||||
|
|
||||||
private boolean prepared;
|
private boolean prepared;
|
||||||
private boolean seenFirstTrackSelection;
|
private boolean seenFirstTrackSelection;
|
||||||
private boolean notifyReset;
|
private boolean notifyReset;
|
||||||
private int enabledTrackCount;
|
private int enabledTrackCount;
|
||||||
private DefaultTrackOutput[] sampleQueues;
|
|
||||||
private Format downstreamFormat;
|
private Format downstreamFormat;
|
||||||
|
|
||||||
// Tracks are complicated in HLS. See documentation of buildTracks for details.
|
// Tracks are complicated in HLS. See documentation of buildTracks for details.
|
||||||
@ -93,7 +97,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
* @param loadControl Controls when the source is permitted to load data.
|
* @param loadControl Controls when the source is permitted to load data.
|
||||||
* @param bufferSizeContribution The contribution of this source to the media buffer, in bytes.
|
* @param bufferSizeContribution The contribution of this source to the media buffer, in bytes.
|
||||||
*/
|
*/
|
||||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
public HlsTrackStreamWrapper(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution) {
|
int bufferSizeContribution) {
|
||||||
this(chunkSource, loadControl, bufferSizeContribution, null, null, 0);
|
this(chunkSource, loadControl, bufferSizeContribution, null, null, 0);
|
||||||
}
|
}
|
||||||
@ -107,7 +111,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||||
* @param eventSourceId An identifier that gets passed to {@code eventListener} methods.
|
* @param eventSourceId An identifier that gets passed to {@code eventListener} methods.
|
||||||
*/
|
*/
|
||||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
public HlsTrackStreamWrapper(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution, Handler eventHandler,
|
int bufferSizeContribution, Handler eventHandler,
|
||||||
ChunkTrackStreamEventListener eventListener, int eventSourceId) {
|
ChunkTrackStreamEventListener eventListener, int eventSourceId) {
|
||||||
this(chunkSource, loadControl, bufferSizeContribution, eventHandler, eventListener,
|
this(chunkSource, loadControl, bufferSizeContribution, eventHandler, eventListener,
|
||||||
@ -125,7 +129,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
* @param minLoadableRetryCount The minimum number of times that the source should retry a load
|
* @param minLoadableRetryCount The minimum number of times that the source should retry a load
|
||||||
* before propagating an error.
|
* before propagating an error.
|
||||||
*/
|
*/
|
||||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
public HlsTrackStreamWrapper(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution, Handler eventHandler,
|
int bufferSizeContribution, Handler eventHandler,
|
||||||
ChunkTrackStreamEventListener eventListener, int eventSourceId, int minLoadableRetryCount) {
|
ChunkTrackStreamEventListener eventListener, int eventSourceId, int minLoadableRetryCount) {
|
||||||
this.chunkSource = chunkSource;
|
this.chunkSource = chunkSource;
|
||||||
@ -134,8 +138,8 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
loader = new Loader("Loader:HLS", minLoadableRetryCount);
|
loader = new Loader("Loader:HLS", minLoadableRetryCount);
|
||||||
eventDispatcher = new EventDispatcher(eventHandler, eventListener, eventSourceId);
|
eventDispatcher = new EventDispatcher(eventHandler, eventListener, eventSourceId);
|
||||||
nextChunkHolder = new ChunkHolder();
|
nextChunkHolder = new ChunkHolder();
|
||||||
|
sampleQueues = new SparseArray<>();
|
||||||
mediaChunks = new LinkedList<>();
|
mediaChunks = new LinkedList<>();
|
||||||
output = new HlsOutput(loadControl.getAllocator());
|
|
||||||
pendingResetPositionUs = C.UNSET_TIME_US;
|
pendingResetPositionUs = C.UNSET_TIME_US;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,11 +155,20 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
prepared = true;
|
prepared = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (output.prepare()) {
|
if (sampleQueuesBuilt) {
|
||||||
sampleQueues = output.getTrackOutputs();
|
boolean canBuildTracks = true;
|
||||||
buildTracks();
|
int sampleQueueCount = sampleQueues.size();
|
||||||
prepared = true;
|
for (int i = 0; i < sampleQueueCount; i++) {
|
||||||
return true;
|
if (sampleQueues.valueAt(i).getUpstreamFormat() == null) {
|
||||||
|
canBuildTracks = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (canBuildTracks) {
|
||||||
|
buildTracks();
|
||||||
|
prepared = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// We're not prepared.
|
// We're not prepared.
|
||||||
maybeThrowError();
|
maybeThrowError();
|
||||||
@ -195,7 +208,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
int group = selection.group;
|
int group = selection.group;
|
||||||
int[] tracks = selection.getTracks();
|
int[] tracks = selection.getTracks();
|
||||||
setTrackGroupEnabledState(group, true);
|
setTrackGroupEnabledState(group, true);
|
||||||
sampleQueues[group].needDownstreamFormat();
|
sampleQueues.valueAt(group).needDownstreamFormat();
|
||||||
if (group == primaryTrackGroupIndex) {
|
if (group == primaryTrackGroupIndex) {
|
||||||
primaryTracksDeselected |= chunkSource.selectTracks(tracks);
|
primaryTracksDeselected |= chunkSource.selectTracks(tracks);
|
||||||
}
|
}
|
||||||
@ -256,9 +269,10 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
if (lastCompletedMediaChunk != null) {
|
if (lastCompletedMediaChunk != null) {
|
||||||
bufferedPositionUs = Math.max(bufferedPositionUs, lastCompletedMediaChunk.endTimeUs);
|
bufferedPositionUs = Math.max(bufferedPositionUs, lastCompletedMediaChunk.endTimeUs);
|
||||||
}
|
}
|
||||||
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
int sampleQueueCount = sampleQueues.size();
|
||||||
|
for (int i = 0; i < sampleQueueCount; i++) {
|
||||||
bufferedPositionUs = Math.max(bufferedPositionUs,
|
bufferedPositionUs = Math.max(bufferedPositionUs,
|
||||||
sampleQueue.getLargestQueuedTimestampUs());
|
sampleQueues.valueAt(i).getLargestQueuedTimestampUs());
|
||||||
}
|
}
|
||||||
return bufferedPositionUs;
|
return bufferedPositionUs;
|
||||||
}
|
}
|
||||||
@ -279,7 +293,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
// TrackStream implementation.
|
// TrackStream implementation.
|
||||||
|
|
||||||
/* package */ boolean isReady(int group) {
|
/* package */ boolean isReady(int group) {
|
||||||
return loadingFinished || (!isPendingReset() && !sampleQueues[group].isEmpty());
|
return loadingFinished || (!isPendingReset() && !sampleQueues.valueAt(group).isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void maybeThrowError() throws IOException {
|
/* package */ void maybeThrowError() throws IOException {
|
||||||
@ -303,7 +317,8 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
}
|
}
|
||||||
downstreamFormat = format;
|
downstreamFormat = format;
|
||||||
|
|
||||||
return sampleQueues[group].readData(formatHolder, buffer, loadingFinished, lastSeekPositionUs);
|
return sampleQueues.valueAt(group).readData(formatHolder, buffer, loadingFinished,
|
||||||
|
lastSeekPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loader.Callback implementation.
|
// Loader.Callback implementation.
|
||||||
@ -361,11 +376,44 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called by the consuming thread, but only when there is no loading thread.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates to all track outputs that they should splice in subsequently queued samples.
|
||||||
|
*/
|
||||||
|
public void splice() {
|
||||||
|
for (int i = 0; i < sampleQueues.size(); i++) {
|
||||||
|
sampleQueues.valueAt(i).splice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractorOutput implementation. Called by the loading thread.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DefaultTrackOutput track(int id) {
|
||||||
|
if (sampleQueues.indexOfKey(id) >= 0) {
|
||||||
|
return sampleQueues.get(id);
|
||||||
|
}
|
||||||
|
DefaultTrackOutput trackOutput = new DefaultTrackOutput(loadControl.getAllocator());
|
||||||
|
sampleQueues.put(id, trackOutput);
|
||||||
|
return trackOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endTracks() {
|
||||||
|
sampleQueuesBuilt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekMap(SeekMap seekMap) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds tracks that are exposed by this {@link HlsSampleSource} instance, as well as internal
|
* Builds tracks that are exposed by this {@link HlsTrackStreamWrapper} instance, as well as
|
||||||
* data-structures required for operation.
|
* internal data-structures required for operation.
|
||||||
* <p>
|
* <p>
|
||||||
* Tracks in HLS are complicated. A HLS master playlist contains a number of "variants". Each
|
* Tracks in HLS are complicated. A HLS master playlist contains a number of "variants". Each
|
||||||
* variant stream typically contains muxed video, audio and (possibly) additional audio, metadata
|
* variant stream typically contains muxed video, audio and (possibly) additional audio, metadata
|
||||||
@ -378,7 +426,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
* adaptive track defined to span all variants and a track for each individual variant. The
|
* adaptive track defined to span all variants and a track for each individual variant. The
|
||||||
* adaptive track is initially selected. The extractor is then prepared to discover the tracks
|
* adaptive track is initially selected. The extractor is then prepared to discover the tracks
|
||||||
* inside of each variant stream. The two sets of tracks are then combined by this method to
|
* inside of each variant stream. The two sets of tracks are then combined by this method to
|
||||||
* create a third set, which is the set exposed by this {@link HlsSampleSource}:
|
* create a third set, which is the set exposed by this {@link HlsTrackStreamWrapper}:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The extractor tracks are inspected to infer a "primary" track type. If a video track is
|
* <li>The extractor tracks are inspected to infer a "primary" track type. If a video track is
|
||||||
* present then it is always the primary type. If not, audio is the primary type if present.
|
* present then it is always the primary type. If not, audio is the primary type if present.
|
||||||
@ -397,9 +445,9 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
// of the single track of this type.
|
// of the single track of this type.
|
||||||
int primaryExtractorTrackType = PRIMARY_TYPE_NONE;
|
int primaryExtractorTrackType = PRIMARY_TYPE_NONE;
|
||||||
int primaryExtractorTrackIndex = -1;
|
int primaryExtractorTrackIndex = -1;
|
||||||
int extractorTrackCount = sampleQueues.length;
|
int extractorTrackCount = sampleQueues.size();
|
||||||
for (int i = 0; i < extractorTrackCount; i++) {
|
for (int i = 0; i < extractorTrackCount; i++) {
|
||||||
String sampleMimeType = sampleQueues[i].getUpstreamFormat().sampleMimeType;
|
String sampleMimeType = sampleQueues.valueAt(i).getUpstreamFormat().sampleMimeType;
|
||||||
int trackType;
|
int trackType;
|
||||||
if (MimeTypes.isVideo(sampleMimeType)) {
|
if (MimeTypes.isVideo(sampleMimeType)) {
|
||||||
trackType = PRIMARY_TYPE_VIDEO;
|
trackType = PRIMARY_TYPE_VIDEO;
|
||||||
@ -430,7 +478,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
// Construct the set of exposed track groups.
|
// Construct the set of exposed track groups.
|
||||||
TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
|
TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
|
||||||
for (int i = 0; i < extractorTrackCount; i++) {
|
for (int i = 0; i < extractorTrackCount; i++) {
|
||||||
Format sampleFormat = sampleQueues[i].getUpstreamFormat();
|
Format sampleFormat = sampleQueues.valueAt(i).getUpstreamFormat();
|
||||||
if (i == primaryExtractorTrackIndex) {
|
if (i == primaryExtractorTrackIndex) {
|
||||||
Format[] formats = new Format[chunkSourceTrackCount];
|
Format[] formats = new Format[chunkSourceTrackCount];
|
||||||
for (int j = 0; j < chunkSourceTrackCount; j++) {
|
for (int j = 0; j < chunkSourceTrackCount; j++) {
|
||||||
@ -498,9 +546,10 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
// before for such tracks. For ID3 we probably explicitly don't want the keyframe before, even
|
// before for such tracks. For ID3 we probably explicitly don't want the keyframe before, even
|
||||||
// if we do have it, since it might be quite a long way behind the seek position. We probably
|
// if we do have it, since it might be quite a long way behind the seek position. We probably
|
||||||
// only want to output ID3 buffers whose timestamps are greater than or equal to positionUs.
|
// only want to output ID3 buffers whose timestamps are greater than or equal to positionUs.
|
||||||
for (int i = 0; seekInsideBuffer && i < sampleQueues.length; i++) {
|
int sampleQueueCount = sampleQueues.size();
|
||||||
|
for (int i = 0; seekInsideBuffer && i < sampleQueueCount; i++) {
|
||||||
if (groupEnabledStates[i]) {
|
if (groupEnabledStates[i]) {
|
||||||
seekInsideBuffer = sampleQueues[i].skipToKeyframeBefore(positionUs);
|
seekInsideBuffer = sampleQueues.valueAt(i).skipToKeyframeBefore(positionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (seekInsideBuffer) {
|
if (seekInsideBuffer) {
|
||||||
@ -515,12 +564,12 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void discardSamplesForDisabledTracks() {
|
private void discardSamplesForDisabledTracks() {
|
||||||
if (!output.prepare()) {
|
if (!prepared) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < groupEnabledStates.length; i++) {
|
for (int i = 0; i < groupEnabledStates.length; i++) {
|
||||||
if (!groupEnabledStates[i]) {
|
if (!groupEnabledStates[i]) {
|
||||||
sampleQueues[i].skipAllSamples();
|
sampleQueues.valueAt(i).skipAllSamples();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,7 +586,9 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void clearState() {
|
private void clearState() {
|
||||||
output.clear();
|
for (int i = 0; i < sampleQueues.size(); i++) {
|
||||||
|
sampleQueues.valueAt(i).clear();
|
||||||
|
}
|
||||||
mediaChunks.clear();
|
mediaChunks.clear();
|
||||||
clearCurrentLoadable();
|
clearCurrentLoadable();
|
||||||
}
|
}
|
||||||
@ -577,7 +628,7 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
if (isMediaChunk(currentLoadable)) {
|
if (isMediaChunk(currentLoadable)) {
|
||||||
pendingResetPositionUs = C.UNSET_TIME_US;
|
pendingResetPositionUs = C.UNSET_TIME_US;
|
||||||
HlsMediaChunk mediaChunk = (HlsMediaChunk) currentLoadable;
|
HlsMediaChunk mediaChunk = (HlsMediaChunk) currentLoadable;
|
||||||
mediaChunk.init(output);
|
mediaChunk.init(this);
|
||||||
mediaChunks.addLast(mediaChunk);
|
mediaChunks.addLast(mediaChunk);
|
||||||
eventDispatcher.loadStarted(mediaChunk.dataSpec.length, mediaChunk.type, mediaChunk.trigger,
|
eventDispatcher.loadStarted(mediaChunk.dataSpec.length, mediaChunk.type, mediaChunk.trigger,
|
||||||
mediaChunk.format, mediaChunk.startTimeUs, mediaChunk.endTimeUs);
|
mediaChunk.format, mediaChunk.startTimeUs, mediaChunk.endTimeUs);
|
||||||
@ -622,17 +673,17 @@ public final class HlsSampleSource implements Loader.Callback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return HlsSampleSource.this.isReady(group);
|
return HlsTrackStreamWrapper.this.isReady(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void maybeThrowError() throws IOException {
|
public void maybeThrowError() throws IOException {
|
||||||
HlsSampleSource.this.maybeThrowError();
|
HlsTrackStreamWrapper.this.maybeThrowError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
return HlsSampleSource.this.readData(group, formatHolder, buffer);
|
return HlsTrackStreamWrapper.this.readData(group, formatHolder, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user