Skip to content

Commit

Permalink
Refactor #6.HLS.3
Browse files Browse the repository at this point in the history
- Pull loading of the initial manifest up to HlsSampleSource.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=123305312
  • Loading branch information
ojw28 committed Jun 15, 2016
1 parent e74fc80 commit 1ea149a
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.HttpDataSource.InvalidResponseCodeException;
import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.UriUtil;
import com.google.android.exoplayer.util.Util;
Expand All @@ -51,7 +50,6 @@
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
Expand All @@ -72,7 +70,6 @@ public class HlsChunkSource {
private static final String VTT_FILE_EXTENSION = ".vtt";
private static final String WEBVTT_FILE_EXTENSION = ".webvtt";

private final ManifestFetcher<HlsPlaylist> manifestFetcher;
private final int type;
private final DataSource dataSource;
private final FormatEvaluator adaptiveFormatEvaluator;
Expand All @@ -84,8 +81,9 @@ public class HlsChunkSource {
private boolean live;
private long durationUs;
private IOException fatalError;
private HlsMasterPlaylist masterPlaylist;
private String baseUri;
private Format muxedAudioFormat;
private Format muxedCaptionFormat;

private Uri encryptionKeyUri;
private byte[] encryptionKey;
Expand All @@ -103,7 +101,6 @@ public class HlsChunkSource {
private boolean[] enabledVariantBlacklistFlags;

/**
* @param manifestFetcher A fetcher for the playlist.
* @param type The type of chunk provided by the source. One of {@link C#TRACK_TYPE_DEFAULT},
* {@link C#TRACK_TYPE_AUDIO} and {@link C#TRACK_TYPE_TEXT}.
* @param dataSource A {@link DataSource} suitable for loading the media data.
Expand All @@ -112,10 +109,9 @@ public class HlsChunkSource {
* same provider.
* @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats.
*/
public HlsChunkSource(ManifestFetcher<HlsPlaylist> manifestFetcher, int type,
DataSource dataSource, PtsTimestampAdjusterProvider timestampAdjusterProvider,
public HlsChunkSource(int type, DataSource dataSource,
PtsTimestampAdjusterProvider timestampAdjusterProvider,
FormatEvaluator adaptiveFormatEvaluator) {
this.manifestFetcher = manifestFetcher;
this.type = type;
this.dataSource = dataSource;
this.adaptiveFormatEvaluator = adaptiveFormatEvaluator;
Expand Down Expand Up @@ -148,38 +144,14 @@ public boolean isAdaptive() {
/**
* Prepares the source.
*
* @return True if the source was prepared, false otherwise.
* @param playlist A {@link HlsPlaylist}.
*/
public boolean prepare() throws IOException {
if (masterPlaylist == null) {
HlsPlaylist playlist = manifestFetcher.getManifest();
if (playlist == null) {
manifestFetcher.maybeThrowError();
manifestFetcher.requestRefresh();
return false;
} else {
baseUri = playlist.baseUri;
if (playlist.type == HlsPlaylist.TYPE_MASTER) {
masterPlaylist = (HlsMasterPlaylist) playlist;
} else {
Format format = Format.createContainerFormat("0", MimeTypes.APPLICATION_M3U8, null,
Format.NO_VALUE);
List<Variant> variants = new ArrayList<>();
variants.add(new Variant(baseUri, format, null));
masterPlaylist = new HlsMasterPlaylist(baseUri, variants,
Collections.<Variant>emptyList(), Collections.<Variant>emptyList(), null, null);
}
processMasterPlaylist(masterPlaylist);
if (variants.length > 0) {
if (playlist.type == HlsPlaylist.TYPE_MEDIA) {
setMediaPlaylist(0, (HlsMediaPlaylist) playlist);
}
// Select the first variant listed in the master playlist.
selectTracks(new int[] {0});
}
}
public void prepare(HlsPlaylist playlist) {
processPlaylist(playlist);
if (variants.length > 0) {
// Select the first variant listed in the master playlist.
selectTracks(new int[] {0});
}
return true;
}

/**
Expand Down Expand Up @@ -235,7 +207,7 @@ public Format getTrackFormat(int index) {
* @return The format of the audio muxed into variants, or null if unknown.
*/
public Format getMuxedAudioFormat() {
return masterPlaylist.muxedAudioFormat;
return muxedAudioFormat;
}

/**
Expand All @@ -246,7 +218,7 @@ public Format getMuxedAudioFormat() {
* @return The format of the captions muxed into variants, or null if unknown.
*/
public Format getMuxedCaptionFormat() {
return masterPlaylist.muxedCaptionFormat;
return muxedCaptionFormat;
}

/**
Expand Down Expand Up @@ -521,9 +493,33 @@ public boolean onChunkLoadError(Chunk chunk, boolean cancelable, IOException e)

// Private methods.

private void processMasterPlaylist(HlsMasterPlaylist playlist) {
private void processPlaylist(HlsPlaylist playlist) {
baseUri = playlist.baseUri;

if (playlist instanceof HlsMediaPlaylist) {
if (type == C.TRACK_TYPE_TEXT || type == C.TRACK_TYPE_AUDIO) {
variants = new Variant[0];
variantPlaylists = new HlsMediaPlaylist[variants.length];
variantLastPlaylistLoadTimesMs = new long[variants.length];
return;
}

// type == C.TRACK_TYPE_DEFAULT
Format format = Format.createContainerFormat("0", MimeTypes.APPLICATION_M3U8, null,
Format.NO_VALUE);
variants = new Variant[] {new Variant(baseUri, format, null)};
variantPlaylists = new HlsMediaPlaylist[variants.length];
variantLastPlaylistLoadTimesMs = new long[variants.length];
setMediaPlaylist(0, (HlsMediaPlaylist) playlist);
return;
}

HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist;
muxedAudioFormat = masterPlaylist.muxedAudioFormat;
muxedCaptionFormat = masterPlaylist.muxedCaptionFormat;
if (type == C.TRACK_TYPE_TEXT || type == C.TRACK_TYPE_AUDIO) {
List<Variant> variantList = type == C.TRACK_TYPE_AUDIO ? playlist.audios : playlist.subtitles;
List<Variant> variantList = type == C.TRACK_TYPE_AUDIO ? masterPlaylist.audios
: masterPlaylist.subtitles;
if (variantList != null && !variantList.isEmpty()) {
variants = new Variant[variantList.size()];
variantList.toArray(variants);
Expand All @@ -535,8 +531,8 @@ private void processMasterPlaylist(HlsMasterPlaylist playlist) {
return;
}

// Type is TYPE_DEFAULT.
List<Variant> enabledVariantList = new ArrayList<>(playlist.variants);
// type == C.TRACK_TYPE_DEFAULT
List<Variant> enabledVariantList = new ArrayList<>(masterPlaylist.variants);
ArrayList<Variant> definiteVideoVariants = new ArrayList<>();
ArrayList<Variant> definiteAudioOnlyVariants = new ArrayList<>();
for (int i = 0; i < enabledVariantList.size(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,22 @@
*/
public final class HlsSampleSource implements SampleSource {

/**
* The minimum number of times to retry loading data prior to failing.
*/
// TODO: Use this for playlist loads as well.
private static final int MIN_LOADABLE_RETRY_COUNT = 3;

private final ManifestFetcher<HlsPlaylist> manifestFetcher;
private final HlsChunkSource[] chunkSources;
private final HlsTrackStreamWrapper[] trackStreamWrappers;
private final IdentityHashMap<TrackStream, HlsTrackStreamWrapper> trackStreamSources;
private final int[] selectedTrackCounts;

private boolean prepared;
private boolean seenFirstTrackSelection;
private long durationUs;
private HlsPlaylist playlist;
private TrackGroupArray trackGroups;
private HlsTrackStreamWrapper[] enabledTrackStreamWrappers;

Expand All @@ -71,27 +79,30 @@ public HlsSampleSource(Uri uri, DataSourceFactory dataSourceFactory,
PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();

DataSource defaultDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_DEFAULT,
HlsChunkSource defaultChunkSource = new HlsChunkSource(C.TRACK_TYPE_DEFAULT,
defaultDataSource, timestampAdjusterProvider,
new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter));
HlsTrackStreamWrapper defaultTrackStreamWrapper = new HlsTrackStreamWrapper(defaultChunkSource,
loadControl, C.DEFAULT_MUXED_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_VIDEO);
loadControl, C.DEFAULT_MUXED_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_VIDEO,
MIN_LOADABLE_RETRY_COUNT);

DataSource audioDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_AUDIO,
HlsChunkSource audioChunkSource = new HlsChunkSource(C.TRACK_TYPE_AUDIO,
audioDataSource, timestampAdjusterProvider, null);
HlsTrackStreamWrapper audioTrackStreamWrapper = new HlsTrackStreamWrapper(audioChunkSource,
loadControl, C.DEFAULT_AUDIO_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_AUDIO);
loadControl, C.DEFAULT_AUDIO_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_AUDIO,
MIN_LOADABLE_RETRY_COUNT);

DataSource subtitleDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_TEXT,
subtitleDataSource, timestampAdjusterProvider, null);
HlsTrackStreamWrapper subtitleTrackStreamWrapper = new HlsTrackStreamWrapper(
subtitleChunkSource, loadControl, C.DEFAULT_TEXT_BUFFER_SIZE, eventHandler, eventListener,
C.TRACK_TYPE_TEXT);
DataSource textDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
HlsChunkSource textChunkSource = new HlsChunkSource(C.TRACK_TYPE_TEXT, textDataSource,
timestampAdjusterProvider, null);
HlsTrackStreamWrapper textTrackStreamWrapper = new HlsTrackStreamWrapper(
textChunkSource, loadControl, C.DEFAULT_TEXT_BUFFER_SIZE, eventHandler, eventListener,
C.TRACK_TYPE_TEXT, MIN_LOADABLE_RETRY_COUNT);

chunkSources = new HlsChunkSource[] {defaultChunkSource, audioChunkSource, textChunkSource};
trackStreamWrappers = new HlsTrackStreamWrapper[] {defaultTrackStreamWrapper,
audioTrackStreamWrapper, subtitleTrackStreamWrapper};
audioTrackStreamWrapper, textTrackStreamWrapper};
selectedTrackCounts = new int[trackStreamWrappers.length];
trackStreamSources = new IdentityHashMap<>();
}
Expand All @@ -101,13 +112,27 @@ public boolean prepare(long positionUs) throws IOException {
if (prepared) {
return true;
}

if (playlist == null) {
playlist = manifestFetcher.getManifest();
if (playlist == null) {
manifestFetcher.maybeThrowError();
manifestFetcher.requestRefresh();
return false;
}
for (HlsChunkSource chunkSource : chunkSources) {
chunkSource.prepare(playlist);
}
}

boolean trackStreamWrappersPrepared = true;
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
trackStreamWrappersPrepared &= trackStreamWrapper.prepare(positionUs);
}
if (!trackStreamWrappersPrepared) {
return false;
}

durationUs = 0;
int totalTrackGroupCount = 0;
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@
*/
/* package */ final class HlsTrackStreamWrapper implements Loader.Callback<Chunk>, ExtractorOutput {

/**
* The default minimum number of times to retry loading data prior to failing.
*/
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;

private static final int PRIMARY_TYPE_NONE = 0;
private static final int PRIMARY_TYPE_TEXT = 1;
private static final int PRIMARY_TYPE_AUDIO = 2;
Expand Down Expand Up @@ -89,32 +84,6 @@

private boolean loadingFinished;

/**
* @param chunkSource A {@link HlsChunkSource} from which chunks to load are obtained.
* @param loadControl Controls when the source is permitted to load data.
* @param bufferSizeContribution The contribution of this source to the media buffer, in bytes.
*/
public HlsTrackStreamWrapper(HlsChunkSource chunkSource, LoadControl loadControl,
int bufferSizeContribution) {
this(chunkSource, loadControl, bufferSizeContribution, null, null, 0);
}

/**
* @param chunkSource A {@link HlsChunkSource} from which chunks to load are obtained.
* @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 eventHandler A handler to use when delivering events to {@code eventListener}. 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.
*/
public HlsTrackStreamWrapper(HlsChunkSource chunkSource, LoadControl loadControl,
int bufferSizeContribution, Handler eventHandler,
ChunkTrackStreamEventListener eventListener, int eventSourceId) {
this(chunkSource, loadControl, bufferSizeContribution, eventHandler, eventListener,
eventSourceId, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
}

/**
* @param chunkSource A {@link HlsChunkSource} from which chunks to load are obtained.
* @param loadControl Controls when the source is permitted to load data.
Expand Down Expand Up @@ -144,9 +113,6 @@ public boolean prepare(long positionUs) throws IOException {
if (prepared) {
return true;
}
if (!chunkSource.prepare()) {
return false;
}
if (chunkSource.getTrackCount() == 0) {
trackGroups = new TrackGroupArray();
prepared = true;
Expand Down

0 comments on commit 1ea149a

Please sign in to comment.