Commit f9151dfe by Steve Mayhew

Update to include iframe Variants in same TrackGroup

This was a change suggested by @ojw28 to allow adpative track selection to work with IFrame only `Variant` as any other adaptive seleted `Track` in the `TrackGroup`.  This actually works quite well with the exceptions that:

1. IFrame only tracks do not contain the same Rendition Group references as other non-iframe only varaints (so track selection should disable these tracks even in other non-video renderers.
2. Adapting to iFrame tracks only based on bandwidth might not be so good (as often larger spacial resolution iFrame track might have higher bitrate then lower spacial resolution non-iframe only track).

This change includes one proposed workaround in the AdaptiveTrackSelection class (only use iFrame for higher playback speeds).
parent f076a5eb
...@@ -1065,6 +1065,10 @@ public final class C { ...@@ -1065,6 +1065,10 @@ public final class C {
/** Indicates the track contains a text that has been edited for ease of reading. */ /** Indicates the track contains a text that has been edited for ease of reading. */
public static final int ROLE_FLAG_EASY_TO_READ = 1 << 13; public static final int ROLE_FLAG_EASY_TO_READ = 1 << 13;
// TODO - not a 'role' in the sense it is parsed from the CHARACTERISTICS attribute... forced if iFrame only
/** Indicates the track is an IDR (IFrame) only track for trick play */
public static final int ROLE_FLAG_TRICK_PLAY = 1 << 14;
/** /**
* Converts a time in microseconds to the corresponding time in milliseconds, preserving * Converts a time in microseconds to the corresponding time in milliseconds, preserving
* {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values. * {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values.
......
...@@ -540,7 +540,17 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { ...@@ -540,7 +540,17 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
@SuppressWarnings("unused") @SuppressWarnings("unused")
protected boolean canSelectFormat( protected boolean canSelectFormat(
Format format, int trackBitrate, float playbackSpeed, long effectiveBitrate) { Format format, int trackBitrate, float playbackSpeed, long effectiveBitrate) {
return Math.round(trackBitrate * playbackSpeed) <= effectiveBitrate;
boolean isIframeOnly = (format.roleFlags & C.ROLE_FLAG_TRICK_PLAY) != 0;
boolean canSelect = Math.round(trackBitrate * playbackSpeed) <= effectiveBitrate;
if (Math.abs(playbackSpeed) > 6.0f) {
canSelect = isIframeOnly; // TODO factor in playback speed...
} else {
canSelect = ! isIframeOnly && canSelect;
}
return canSelect;
} }
/** /**
......
...@@ -35,7 +35,6 @@ import com.google.android.exoplayer2.source.SequenceableLoader; ...@@ -35,7 +35,6 @@ import com.google.android.exoplayer2.source.SequenceableLoader;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.IFrameVariant;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Rendition; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Rendition;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Variant; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Variant;
import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker;
...@@ -479,22 +478,17 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper ...@@ -479,22 +478,17 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
ArrayList<HlsSampleStreamWrapper> sampleStreamWrappers = new ArrayList<>(); ArrayList<HlsSampleStreamWrapper> sampleStreamWrappers = new ArrayList<>();
ArrayList<int[]> manifestUrlIndicesPerWrapper = new ArrayList<>(); ArrayList<int[]> manifestUrlIndicesPerWrapper = new ArrayList<>();
if (hasVariants) { ArrayList<Variant> allVariants = new ArrayList<>();
allVariants.addAll(masterPlaylist.variants);
allVariants.addAll(masterPlaylist.iFrameVariants);
if (hasVariants){
buildAndPrepareMainSampleStreamWrapper( buildAndPrepareMainSampleStreamWrapper(
masterPlaylist, masterPlaylist,
positionUs, positionUs,
sampleStreamWrappers, sampleStreamWrappers,
manifestUrlIndicesPerWrapper, manifestUrlIndicesPerWrapper,
overridingDrmInitData); overridingDrmInitData,
} allVariants);
if (hasIFrameVariants) {
buildAndPrepareIFrameSampleStreamWrappers(
masterPlaylist,
positionUs,
sampleStreamWrappers,
overridingDrmInitData
);
} }
// TODO: Build video stream wrappers here. // TODO: Build video stream wrappers here.
...@@ -570,12 +564,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper ...@@ -570,12 +564,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
long positionUs, long positionUs,
List<HlsSampleStreamWrapper> sampleStreamWrappers, List<HlsSampleStreamWrapper> sampleStreamWrappers,
List<int[]> manifestUrlIndicesPerWrapper, List<int[]> manifestUrlIndicesPerWrapper,
Map<String, DrmInitData> overridingDrmInitData) { Map<String, DrmInitData> overridingDrmInitData, List<Variant> variants) {
int[] variantTypes = new int[masterPlaylist.variants.size()]; int[] variantTypes = new int[variants.size()];
int videoVariantCount = 0; int videoVariantCount = 0;
int audioVariantCount = 0; int audioVariantCount = 0;
for (int i = 0; i < masterPlaylist.variants.size(); i++) { for (int i = 0; i < variants.size(); i++) {
Variant variant = masterPlaylist.variants.get(i); Variant variant = variants.get(i);
Format format = variant.format; Format format = variant.format;
if (format.height > 0 || Util.getCodecsOfType(format.codecs, C.TRACK_TYPE_VIDEO) != null) { if (format.height > 0 || Util.getCodecsOfType(format.codecs, C.TRACK_TYPE_VIDEO) != null) {
variantTypes[i] = C.TRACK_TYPE_VIDEO; variantTypes[i] = C.TRACK_TYPE_VIDEO;
...@@ -606,10 +600,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper ...@@ -606,10 +600,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
Format[] selectedPlaylistFormats = new Format[selectedVariantsCount]; Format[] selectedPlaylistFormats = new Format[selectedVariantsCount];
int[] selectedVariantIndices = new int[selectedVariantsCount]; int[] selectedVariantIndices = new int[selectedVariantsCount];
int outIndex = 0; int outIndex = 0;
for (int i = 0; i < masterPlaylist.variants.size(); i++) { for (int i = 0; i < variants.size(); i++) {
if ((!useVideoVariantsOnly || variantTypes[i] == C.TRACK_TYPE_VIDEO) if ((!useVideoVariantsOnly || variantTypes[i] == C.TRACK_TYPE_VIDEO)
&& (!useNonAudioVariantsOnly || variantTypes[i] != C.TRACK_TYPE_AUDIO)) { && (!useNonAudioVariantsOnly || variantTypes[i] != C.TRACK_TYPE_AUDIO)) {
Variant variant = masterPlaylist.variants.get(i); Variant variant =variants.get(i);
selectedPlaylistUrls[outIndex] = variant.url; selectedPlaylistUrls[outIndex] = variant.url;
selectedPlaylistFormats[outIndex] = variant.format; selectedPlaylistFormats[outIndex] = variant.format;
selectedVariantIndices[outIndex++] = i; selectedVariantIndices[outIndex++] = i;
...@@ -633,8 +627,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper ...@@ -633,8 +627,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
List<TrackGroup> muxedTrackGroups = new ArrayList<>(); List<TrackGroup> muxedTrackGroups = new ArrayList<>();
if (variantsContainVideoCodecs) { if (variantsContainVideoCodecs) {
Format[] videoFormats = new Format[selectedVariantsCount]; Format[] videoFormats = new Format[selectedVariantsCount];
for (int i = 0; i < videoFormats.length; i++) { for (int i1 = 0; i1 < videoFormats.length; i1++) {
videoFormats[i] = deriveVideoFormat(selectedPlaylistFormats[i]); videoFormats[i1] = deriveVideoFormat(selectedPlaylistFormats[i1]);
} }
muxedTrackGroups.add(new TrackGroup(videoFormats)); muxedTrackGroups.add(new TrackGroup(videoFormats));
...@@ -684,45 +678,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper ...@@ -684,45 +678,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
} }
} }
/**
* Build a set of SampleStream wrappers around the IFrame (IDR) only variants found
* for the MediaPeriod at positionUS.
*
* @param masterPlaylist - master playlist with the IFrame variants
* @param positionUs - position to begin loading samples from
* @param sampleStreamWrappers - [output] list is filled.
*/
private void buildAndPrepareIFrameSampleStreamWrappers(
HlsMasterPlaylist masterPlaylist,
long positionUs,
List<HlsSampleStreamWrapper> sampleStreamWrappers,
Map<String, DrmInitData> overridingDrmInitData) {
int selectedVariantsCount = masterPlaylist.iFrameVariants.size();
Uri[] selectedPlaylistUrls = new Uri[selectedVariantsCount];
Format[] selectedPlaylistFormats = new Format[selectedVariantsCount];
int[] selectedVariantIndices = new int[selectedVariantsCount];
int outIndex = 0;
for (IFrameVariant iFrameVariant : masterPlaylist.iFrameVariants) {
selectedPlaylistUrls[outIndex] = iFrameVariant.url;
selectedPlaylistFormats[outIndex] = iFrameVariant.format;
selectedVariantIndices[outIndex] = outIndex++;
}
HlsSampleStreamWrapper sampleStreamWrapper =
buildSampleStreamWrapper(
C.TRACK_TYPE_VIDEO,
selectedPlaylistUrls,
selectedPlaylistFormats,
/* muxedAudioFormat= */ null,
/* muxedCaptionFormats= */ Collections.emptyList(),
overridingDrmInitData,
positionUs);
sampleStreamWrappers.add(sampleStreamWrapper);
}
private void buildAndPrepareAudioSampleStreamWrappers( private void buildAndPrepareAudioSampleStreamWrappers(
long positionUs, long positionUs,
List<Rendition> audioRenditions, List<Rendition> audioRenditions,
......
...@@ -35,6 +35,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -35,6 +35,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
/* baseUri= */ "", /* baseUri= */ "",
/* tags= */ Collections.emptyList(), /* tags= */ Collections.emptyList(),
/* variants= */ Collections.emptyList(), /* variants= */ Collections.emptyList(),
/* iframes= */ Collections.emptyList(),
/* videos= */ Collections.emptyList(), /* videos= */ Collections.emptyList(),
/* audios= */ Collections.emptyList(), /* audios= */ Collections.emptyList(),
/* subtitles= */ Collections.emptyList(), /* subtitles= */ Collections.emptyList(),
...@@ -95,6 +96,28 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -95,6 +96,28 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
} }
/** /**
* Construct a Variant with only an (optional) video Rendition (for example, EXT-X-I-FRAME-STREAM-INF
* only allows alternate VIDEO Renditions, these are suggested if the non-Iframe Variant includes
* alternate video Rendition but not required)
*
* @param url See {@link #url}.
* @param format See {@link #format}.
* @param videoGroupId See {@link #videoGroupId}.
*/
public Variant(
Uri url,
Format format,
@Nullable String videoGroupId) {
this(
url,
format,
videoGroupId,
/* audioGroupId */null,
/* subtitleGroupId */null,
/* captionGroupId */null);
}
/**
* Creates a variant for a given media playlist url. * Creates a variant for a given media playlist url.
* *
* @param url The media playlist url. * @param url The media playlist url.
...@@ -152,6 +175,8 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -152,6 +175,8 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
public final List<Uri> mediaPlaylistUrls; public final List<Uri> mediaPlaylistUrls;
/** The variants declared by the playlist. */ /** The variants declared by the playlist. */
public final List<Variant> variants; public final List<Variant> variants;
/** The IFrame only playlist declared by the playlist, if any. */
public final List<Variant> iFrameVariants;
/** The video renditions declared by the playlist. */ /** The video renditions declared by the playlist. */
public final List<Rendition> videos; public final List<Rendition> videos;
/** The audio renditions declared by the playlist. */ /** The audio renditions declared by the playlist. */
...@@ -181,6 +206,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -181,6 +206,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
* @param baseUri See {@link #baseUri}. * @param baseUri See {@link #baseUri}.
* @param tags See {@link #tags}. * @param tags See {@link #tags}.
* @param variants See {@link #variants}. * @param variants See {@link #variants}.
* @param iFrameVariants
* @param videos See {@link #videos}. * @param videos See {@link #videos}.
* @param audios See {@link #audios}. * @param audios See {@link #audios}.
* @param subtitles See {@link #subtitles}. * @param subtitles See {@link #subtitles}.
...@@ -195,6 +221,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -195,6 +221,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
String baseUri, String baseUri,
List<String> tags, List<String> tags,
List<Variant> variants, List<Variant> variants,
List<Variant> iFrameVariants,
List<Rendition> videos, List<Rendition> videos,
List<Rendition> audios, List<Rendition> audios,
List<Rendition> subtitles, List<Rendition> subtitles,
...@@ -209,6 +236,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -209,6 +236,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
Collections.unmodifiableList( Collections.unmodifiableList(
getMediaPlaylistUrls(variants, iFrameVariants, videos, audios, subtitles, closedCaptions)); getMediaPlaylistUrls(variants, iFrameVariants, videos, audios, subtitles, closedCaptions));
this.variants = Collections.unmodifiableList(variants); this.variants = Collections.unmodifiableList(variants);
this.iFrameVariants = Collections.unmodifiableList(iFrameVariants);
this.videos = Collections.unmodifiableList(videos); this.videos = Collections.unmodifiableList(videos);
this.audios = Collections.unmodifiableList(audios); this.audios = Collections.unmodifiableList(audios);
this.subtitles = Collections.unmodifiableList(subtitles); this.subtitles = Collections.unmodifiableList(subtitles);
...@@ -226,6 +254,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -226,6 +254,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
baseUri, baseUri,
tags, tags,
copyStreams(variants, GROUP_INDEX_VARIANT, streamKeys), copyStreams(variants, GROUP_INDEX_VARIANT, streamKeys),
/* iframes */ Collections.emptyList(),
// TODO: Allow stream keys to specify video renditions to be retained. // TODO: Allow stream keys to specify video renditions to be retained.
/* videos= */ Collections.emptyList(), /* videos= */ Collections.emptyList(),
copyStreams(audios, GROUP_INDEX_AUDIO, streamKeys), copyStreams(audios, GROUP_INDEX_AUDIO, streamKeys),
...@@ -252,6 +281,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -252,6 +281,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
/* baseUri= */ "", /* baseUri= */ "",
/* tags= */ Collections.emptyList(), /* tags= */ Collections.emptyList(),
variant, variant,
/* iframes= */ Collections.emptyList(),
/* videos= */ Collections.emptyList(), /* videos= */ Collections.emptyList(),
/* audios= */ Collections.emptyList(), /* audios= */ Collections.emptyList(),
/* subtitles= */ Collections.emptyList(), /* subtitles= */ Collections.emptyList(),
...@@ -265,7 +295,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -265,7 +295,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
private static List<Uri> getMediaPlaylistUrls( private static List<Uri> getMediaPlaylistUrls(
List<Variant> variants, List<Variant> variants,
List<IFrameVariant> iFrameVariants, List<Variant> iFrameVariants,
List<Rendition> videos, List<Rendition> videos,
List<Rendition> audios, List<Rendition> audios,
List<Rendition> subtitles, List<Rendition> subtitles,
...@@ -277,7 +307,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { ...@@ -277,7 +307,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
mediaPlaylistUrls.add(uri); mediaPlaylistUrls.add(uri);
} }
} }
for (IFrameVariant iFrameVariant : iFrameVariants) { for (Variant iFrameVariant : iFrameVariants) {
mediaPlaylistUrls.add(iFrameVariant.url); mediaPlaylistUrls.add(iFrameVariant.url);
} }
addMediaPlaylistUrls(videos, mediaPlaylistUrls); addMediaPlaylistUrls(videos, mediaPlaylistUrls);
......
...@@ -69,6 +69,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli ...@@ -69,6 +69,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
private static final String TAG_PLAYLIST_TYPE = "#EXT-X-PLAYLIST-TYPE"; private static final String TAG_PLAYLIST_TYPE = "#EXT-X-PLAYLIST-TYPE";
private static final String TAG_DEFINE = "#EXT-X-DEFINE"; private static final String TAG_DEFINE = "#EXT-X-DEFINE";
private static final String TAG_STREAM_INF = "#EXT-X-STREAM-INF"; private static final String TAG_STREAM_INF = "#EXT-X-STREAM-INF";
private static final String TAG_STREAM_IFRAME = "#EXT-X-I-FRAME-STREAM-INF";
private static final String TAG_MEDIA = "#EXT-X-MEDIA"; private static final String TAG_MEDIA = "#EXT-X-MEDIA";
private static final String TAG_TARGET_DURATION = "#EXT-X-TARGETDURATION"; private static final String TAG_TARGET_DURATION = "#EXT-X-TARGETDURATION";
private static final String TAG_DISCONTINUITY = "#EXT-X-DISCONTINUITY"; private static final String TAG_DISCONTINUITY = "#EXT-X-DISCONTINUITY";
...@@ -261,6 +262,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli ...@@ -261,6 +262,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
HashMap<Uri, ArrayList<VariantInfo>> urlToVariantInfos = new HashMap<>(); HashMap<Uri, ArrayList<VariantInfo>> urlToVariantInfos = new HashMap<>();
HashMap<String, String> variableDefinitions = new HashMap<>(); HashMap<String, String> variableDefinitions = new HashMap<>();
ArrayList<Variant> variants = new ArrayList<>(); ArrayList<Variant> variants = new ArrayList<>();
ArrayList<Variant> iFrameVariants = new ArrayList<>();
ArrayList<Rendition> videos = new ArrayList<>(); ArrayList<Rendition> videos = new ArrayList<>();
ArrayList<Rendition> audios = new ArrayList<>(); ArrayList<Rendition> audios = new ArrayList<>();
ArrayList<Rendition> subtitles = new ArrayList<>(); ArrayList<Rendition> subtitles = new ArrayList<>();
...@@ -302,33 +304,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli ...@@ -302,33 +304,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
sessionKeyDrmInitData.add(new DrmInitData(scheme, schemeData)); sessionKeyDrmInitData.add(new DrmInitData(scheme, schemeData));
} }
} else if (line.startsWith(TAG_STREAM_INF)) { } else if (line.startsWith(TAG_STREAM_INF)) {
String formatId = Integer.toString(variants.size());
noClosedCaptions |= line.contains(ATTR_CLOSED_CAPTIONS_NONE); noClosedCaptions |= line.contains(ATTR_CLOSED_CAPTIONS_NONE);
int peakBitrate = parseIntAttr(line, REGEX_BANDWIDTH); int peakBitrate = parseIntAttr(line, REGEX_BANDWIDTH);
int averageBitrate = parseOptionalIntAttr(line, REGEX_AVERAGE_BANDWIDTH, -1); int averageBitrate = parseOptionalIntAttr(line, REGEX_AVERAGE_BANDWIDTH, -1);
String codecs = parseOptionalStringAttr(line, REGEX_CODECS, variableDefinitions); Format format = parseVideoContainerFormat(variableDefinitions, line, formatId, peakBitrate, averageBitrate, 0);
String resolutionString =
parseOptionalStringAttr(line, REGEX_RESOLUTION, variableDefinitions);
int width;
int height;
if (resolutionString != null) {
String[] widthAndHeight = resolutionString.split("x");
width = Integer.parseInt(widthAndHeight[0]);
height = Integer.parseInt(widthAndHeight[1]);
if (width <= 0 || height <= 0) {
// Resolution string is invalid.
width = Format.NO_VALUE;
height = Format.NO_VALUE;
}
} else {
width = Format.NO_VALUE;
height = Format.NO_VALUE;
}
float frameRate = Format.NO_VALUE;
String frameRateString =
parseOptionalStringAttr(line, REGEX_FRAME_RATE, variableDefinitions);
if (frameRateString != null) {
frameRate = Float.parseFloat(frameRateString);
}
String videoGroupId = parseOptionalStringAttr(line, REGEX_VIDEO, variableDefinitions); String videoGroupId = parseOptionalStringAttr(line, REGEX_VIDEO, variableDefinitions);
String audioGroupId = parseOptionalStringAttr(line, REGEX_AUDIO, variableDefinitions); String audioGroupId = parseOptionalStringAttr(line, REGEX_AUDIO, variableDefinitions);
String subtitlesGroupId = String subtitlesGroupId =
...@@ -342,17 +323,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli ...@@ -342,17 +323,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
replaceVariableReferences( replaceVariableReferences(
iterator.next(), variableDefinitions); // #EXT-X-STREAM-INF's URI. iterator.next(), variableDefinitions); // #EXT-X-STREAM-INF's URI.
Uri uri = UriUtil.resolveToUri(baseUri, line); Uri uri = UriUtil.resolveToUri(baseUri, line);
Format format =
new Format.Builder()
.setId(variants.size())
.setContainerMimeType(MimeTypes.APPLICATION_M3U8)
.setCodecs(codecs)
.setAverageBitrate(averageBitrate)
.setPeakBitrate(peakBitrate)
.setWidth(width)
.setHeight(height)
.setFrameRate(frameRate)
.build();
Variant variant = Variant variant =
new Variant( new Variant(
uri, format, videoGroupId, audioGroupId, subtitlesGroupId, closedCaptionsGroupId); uri, format, videoGroupId, audioGroupId, subtitlesGroupId, closedCaptionsGroupId);
...@@ -370,6 +341,17 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli ...@@ -370,6 +341,17 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
audioGroupId, audioGroupId,
subtitlesGroupId, subtitlesGroupId,
closedCaptionsGroupId)); closedCaptionsGroupId));
} else if (line.startsWith(TAG_STREAM_IFRAME)) {
String formatId = "iFrame-" + iFrameVariants.size();
int peakBitrate = parseIntAttr(line, REGEX_BANDWIDTH);
int averageBitrate = parseOptionalIntAttr(line, REGEX_AVERAGE_BANDWIDTH, -1);
Format format = parseVideoContainerFormat(variableDefinitions, line, formatId, peakBitrate, averageBitrate,
C.ROLE_FLAG_ALTERNATE | C.ROLE_FLAG_TRICK_PLAY);
String iframeUri = parseStringAttr(line, REGEX_URI, variableDefinitions);
Uri uri = UriUtil.resolveToUri(baseUri, iframeUri);
iFrameVariants.add(new Variant(uri, format, null));
} }
} }
...@@ -494,6 +476,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli ...@@ -494,6 +476,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
baseUri, baseUri,
tags, tags,
deduplicatedVariants, deduplicatedVariants,
iFrameVariants,
videos, videos,
audios, audios,
subtitles, subtitles,
...@@ -505,6 +488,47 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli ...@@ -505,6 +488,47 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
sessionKeyDrmInitData); sessionKeyDrmInitData);
} }
private static Format parseVideoContainerFormat(HashMap<String, String> variableDefinitions,
String line, String formatId, int peakBitrate, int averageBitrate, int roleFlags) {
String codecs = parseOptionalStringAttr(line, REGEX_CODECS, variableDefinitions);
String resolutionString =
parseOptionalStringAttr(line, REGEX_RESOLUTION, variableDefinitions);
int width;
int height;
if (resolutionString != null) {
String[] widthAndHeight = resolutionString.split("x");
width = Integer.parseInt(widthAndHeight[0]);
height = Integer.parseInt(widthAndHeight[1]);
if (width <= 0 || height <= 0) {
// Resolution string is invalid.
width = Format.NO_VALUE;
height = Format.NO_VALUE;
}
} else {
width = Format.NO_VALUE;
height = Format.NO_VALUE;
}
float frameRate = Format.NO_VALUE;
String frameRateString =
parseOptionalStringAttr(line, REGEX_FRAME_RATE, variableDefinitions);
if (frameRateString != null) {
frameRate = Float.parseFloat(frameRateString);
}
Format format =
new Format.Builder()
.setId(formatId)
.setContainerMimeType(MimeTypes.APPLICATION_M3U8)
.setCodecs(codecs)
.setAverageBitrate(averageBitrate)
.setPeakBitrate(peakBitrate)
.setWidth(width)
.setHeight(height)
.setFrameRate(frameRate)
.setRoleFlags(roleFlags)
.build();
return format;
}
@Nullable @Nullable
private static Variant getVariantWithAudioGroup(ArrayList<Variant> variants, String groupId) { private static Variant getVariantWithAudioGroup(ArrayList<Variant> variants, String groupId) {
for (int i = 0; i < variants.size(); i++) { for (int i = 0; i < variants.size(); i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment