Skip to content

Commit

Permalink
Refactor #6.HLS.4
Browse files Browse the repository at this point in the history
Pull more logic up to HlsSampleSource. Somewhat regretfully,
this also backs out the optimization work done toward the
ref'd issue. I think that's one for another time perhaps...

Issue: #551
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=123417413
  • Loading branch information
ojw28 committed Jun 15, 2016
1 parent 6d62962 commit 8744e8d
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 253 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
import com.google.android.exoplayer.extractor.ts.AdtsExtractor;
import com.google.android.exoplayer.extractor.ts.PtsTimestampAdjuster;
import com.google.android.exoplayer.extractor.ts.TsExtractor;
import com.google.android.exoplayer.hls.playlist.HlsMasterPlaylist;
import com.google.android.exoplayer.hls.playlist.HlsMediaPlaylist;
import com.google.android.exoplayer.hls.playlist.HlsPlaylist;
import com.google.android.exoplayer.hls.playlist.HlsPlaylistParser;
import com.google.android.exoplayer.hls.playlist.Variant;
import com.google.android.exoplayer.upstream.DataSource;
Expand All @@ -48,10 +46,8 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;

/**
Expand All @@ -70,54 +66,53 @@ public class HlsChunkSource {
private static final String VTT_FILE_EXTENSION = ".vtt";
private static final String WEBVTT_FILE_EXTENSION = ".webvtt";

private final int type;
private final String baseUri;
private final DataSource dataSource;
private final FormatEvaluator adaptiveFormatEvaluator;
private final Evaluation evaluation;
private final HlsPlaylistParser playlistParser;
private final PtsTimestampAdjusterProvider timestampAdjusterProvider;
private final Variant[] variants;
private final HlsMediaPlaylist[] variantPlaylists;
private final long[] variantLastPlaylistLoadTimesMs;

private byte[] scratchSpace;
private boolean live;
private long durationUs;
private IOException fatalError;
private String baseUri;
private Format muxedAudioFormat;
private Format muxedCaptionFormat;

private Uri encryptionKeyUri;
private byte[] encryptionKey;
private String encryptionIvString;
private byte[] encryptionIv;

// Properties of exposed tracks.
private Variant[] variants;
private HlsMediaPlaylist[] variantPlaylists;
private long[] variantLastPlaylistLoadTimesMs;

// Properties of enabled variants.
private Variant[] enabledVariants;
private long[] enabledVariantBlacklistTimes;
private boolean[] enabledVariantBlacklistFlags;

/**
* @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 baseUri The playlist's base uri.
* @param variants The available variants.
* @param dataSource A {@link DataSource} suitable for loading the media data.
* @param timestampAdjusterProvider A provider of {@link PtsTimestampAdjuster} instances. If
* multiple {@link HlsChunkSource}s are used for a single playback, they should all share the
* same provider.
* @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats.
*/
public HlsChunkSource(int type, DataSource dataSource,
public HlsChunkSource(String baseUri, Variant[] variants, DataSource dataSource,
PtsTimestampAdjusterProvider timestampAdjusterProvider,
FormatEvaluator adaptiveFormatEvaluator) {
this.type = type;
this.baseUri = baseUri;
this.variants = variants;
this.dataSource = dataSource;
this.adaptiveFormatEvaluator = adaptiveFormatEvaluator;
this.timestampAdjusterProvider = timestampAdjusterProvider;
playlistParser = new HlsPlaylistParser();
evaluation = new Evaluation();
variantPlaylists = new HlsMediaPlaylist[variants.length];
variantLastPlaylistLoadTimesMs = new long[variants.length];
selectTracks(new int[] {0});
}

/**
Expand All @@ -141,19 +136,6 @@ public boolean isAdaptive() {
return adaptiveFormatEvaluator != null;
}

/**
* Prepares the source.
*
* @param playlist A {@link HlsPlaylist}.
*/
public void prepare(HlsPlaylist playlist) {
processPlaylist(playlist);
if (variants.length > 0) {
// Select the first variant listed in the master playlist.
selectTracks(new int[] {0});
}
}

/**
* Returns whether this is a live playback.
* <p>
Expand Down Expand Up @@ -199,28 +181,6 @@ public Format getTrackFormat(int index) {
return variants[index].format;
}

/**
* Returns the format of the audio muxed into variants, or null if unknown.
* <p>
* This method should only be called after the source has been prepared.
*
* @return The format of the audio muxed into variants, or null if unknown.
*/
public Format getMuxedAudioFormat() {
return muxedAudioFormat;
}

/**
* Returns the format of the captions muxed into variants, or null if unknown.
* <p>
* This method should only be called after the source has been prepared.
*
* @return The format of the captions muxed into variants, or null if unknown.
*/
public Format getMuxedCaptionFormat() {
return muxedCaptionFormat;
}

/**
* Selects tracks for use.
* <p>
Expand Down Expand Up @@ -269,17 +229,6 @@ public int compare(Variant first, Variant second) {
return false;
}

/**
* Notifies the source that a seek has occurred.
* <p>
* This method should only be called after the source has been prepared.
*/
public void seek() {
if (type == C.TRACK_TYPE_DEFAULT) {
timestampAdjusterProvider.reset();
}
}

/**
* Resets the source.
* <p>
Expand Down Expand Up @@ -493,90 +442,6 @@ public boolean onChunkLoadError(Chunk chunk, boolean cancelable, IOException e)

// Private methods.

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 ? masterPlaylist.audios
: masterPlaylist.subtitles;
if (variantList != null && !variantList.isEmpty()) {
variants = new Variant[variantList.size()];
variantList.toArray(variants);
} else {
variants = new Variant[0];
}
variantPlaylists = new HlsMediaPlaylist[variants.length];
variantLastPlaylistLoadTimesMs = new long[variants.length];
return;
}

// 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++) {
Variant variant = enabledVariantList.get(i);
if (variant.format.height > 0 || variantHasExplicitCodecWithPrefix(variant, "avc")) {
definiteVideoVariants.add(variant);
} else if (variantHasExplicitCodecWithPrefix(variant, "mp4a")) {
definiteAudioOnlyVariants.add(variant);
}
}

if (!definiteVideoVariants.isEmpty()) {
// We've identified some variants as definitely containing video. Assume variants within the
// master playlist are marked consistently, and hence that we have the full set. Filter out
// any other variants, which are likely to be audio only.
enabledVariantList = definiteVideoVariants;
} else if (definiteAudioOnlyVariants.size() < enabledVariantList.size()) {
// We've identified some variants, but not all, as being audio only. Filter them out to leave
// the remaining variants, which are likely to contain video.
enabledVariantList.removeAll(definiteAudioOnlyVariants);
} else {
// Leave the enabled variants unchanged. They're likely either all video or all audio.
}

variants = new Variant[enabledVariantList.size()];
enabledVariantList.toArray(variants);
variantPlaylists = new HlsMediaPlaylist[variants.length];
variantLastPlaylistLoadTimesMs = new long[variants.length];
}

private static boolean variantHasExplicitCodecWithPrefix(Variant variant, String prefix) {
String codecs = variant.codecs;
if (TextUtils.isEmpty(codecs)) {
return false;
}
String[] codecArray = codecs.split("(\\s*,\\s*)|(\\s*$)");
for (String codec : codecArray) {
if (codec.startsWith(prefix)) {
return true;
}
}
return false;
}

private int getNextVariantIndex(HlsMediaChunk previous, long playbackPositionUs) {
clearStaleBlacklistedVariants();
if (enabledVariants.length > 1) {
Expand Down
Loading

0 comments on commit 8744e8d

Please sign in to comment.