Parse CHANNELS attribute from EXT-X-MEDIA

PiperOrigin-RevId: 230743198
This commit is contained in:
aquilescanta 2019-01-24 18:12:27 +00:00 committed by Oliver Woodman
parent 9d19a7a4b6
commit 6dde1e67d3
3 changed files with 35 additions and 2 deletions

View File

@ -2,7 +2,8 @@
### dev-v2 (not yet released) ### ### dev-v2 (not yet released) ###
* Increase `minSdkVersion` to 16 (Jellybean). * HLS:
* Parse CHANNELS attribute from EXT-X-MEDIA.
* Support for playing spherical videos on Daydream. * Support for playing spherical videos on Daydream.
* Improve decoder re-use between playbacks. TODO: Write and link a blog post * Improve decoder re-use between playbacks. TODO: Write and link a blog post
here ([#2826](https://github.com/google/ExoPlayer/issues/2826)). here ([#2826](https://github.com/google/ExoPlayer/issues/2826)).

View File

@ -101,6 +101,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
Pattern.compile("AVERAGE-BANDWIDTH=(\\d+)\\b"); Pattern.compile("AVERAGE-BANDWIDTH=(\\d+)\\b");
private static final Pattern REGEX_AUDIO = Pattern.compile("AUDIO=\"(.+?)\""); private static final Pattern REGEX_AUDIO = Pattern.compile("AUDIO=\"(.+?)\"");
private static final Pattern REGEX_BANDWIDTH = Pattern.compile("[^-]BANDWIDTH=(\\d+)\\b"); private static final Pattern REGEX_BANDWIDTH = Pattern.compile("[^-]BANDWIDTH=(\\d+)\\b");
private static final Pattern REGEX_CHANNELS = Pattern.compile("CHANNELS=\"(.+?)\"");
private static final Pattern REGEX_CODECS = Pattern.compile("CODECS=\"(.+?)\""); private static final Pattern REGEX_CODECS = Pattern.compile("CODECS=\"(.+?)\"");
private static final Pattern REGEX_RESOLUTION = Pattern.compile("RESOLUTION=(\\d+x\\d+)"); private static final Pattern REGEX_RESOLUTION = Pattern.compile("RESOLUTION=(\\d+x\\d+)");
private static final Pattern REGEX_FRAME_RATE = Pattern.compile("FRAME-RATE=([\\d\\.]+)\\b"); private static final Pattern REGEX_FRAME_RATE = Pattern.compile("FRAME-RATE=([\\d\\.]+)\\b");
@ -346,6 +347,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
switch (parseStringAttr(line, REGEX_TYPE, variableDefinitions)) { switch (parseStringAttr(line, REGEX_TYPE, variableDefinitions)) {
case TYPE_AUDIO: case TYPE_AUDIO:
String codecs = audioGroupIdToCodecs.get(groupId); String codecs = audioGroupIdToCodecs.get(groupId);
int channelCount = parseChannelsAttribute(line, variableDefinitions);
String sampleMimeType = codecs != null ? MimeTypes.getMediaMimeType(codecs) : null; String sampleMimeType = codecs != null ? MimeTypes.getMediaMimeType(codecs) : null;
format = format =
Format.createAudioContainerFormat( Format.createAudioContainerFormat(
@ -355,7 +357,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
sampleMimeType, sampleMimeType,
codecs, codecs,
/* bitrate= */ Format.NO_VALUE, /* bitrate= */ Format.NO_VALUE,
/* channelCount= */ Format.NO_VALUE, channelCount,
/* sampleRate= */ Format.NO_VALUE, /* sampleRate= */ Format.NO_VALUE,
/* initializationData= */ null, /* initializationData= */ null,
selectionFlags, selectionFlags,
@ -661,6 +663,13 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
return flags; return flags;
} }
private static int parseChannelsAttribute(String line, Map<String, String> variableDefinitions) {
String channelsString = parseOptionalStringAttr(line, REGEX_CHANNELS, variableDefinitions);
return channelsString != null
? Integer.parseInt(Util.splitAtFirst(channelsString, "/")[0])
: Format.NO_VALUE;
}
private static @Nullable SchemeData parsePlayReadySchemeData( private static @Nullable SchemeData parsePlayReadySchemeData(
String line, Map<String, String> variableDefinitions) throws ParserException { String line, Map<String, String> variableDefinitions) throws ParserException {
String keyFormatVersions = String keyFormatVersions =

View File

@ -81,6 +81,18 @@ public class HlsMasterPlaylistParserTest {
+ "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
+ "http://example.com/low.m3u8\n"; + "http://example.com/low.m3u8\n";
private static final String PLAYLIST_WITH_CHANNELS_ATTRIBUTE =
" #EXTM3U \n"
+ "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"audio\",CHANNELS=\"6\",NAME=\"Eng6\","
+ "URI=\"something.m3u8\"\n"
+ "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"audio\",CHANNELS=\"2/6\",NAME=\"Eng26\","
+ "URI=\"something2.m3u8\"\n"
+ "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"audio\",NAME=\"Eng\","
+ "URI=\"something3.m3u8\"\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,"
+ "CODECS=\"mp4a.40.2,avc1.66.30\",AUDIO=\"audio\",RESOLUTION=304x128\n"
+ "http://example.com/low.m3u8\n";
private static final String PLAYLIST_WITHOUT_CC = private static final String PLAYLIST_WITHOUT_CC =
" #EXTM3U \n" " #EXTM3U \n"
+ "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS," + "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,"
@ -216,6 +228,17 @@ public class HlsMasterPlaylistParserTest {
assertThat(closedCaptionFormat.language).isEqualTo("es"); assertThat(closedCaptionFormat.language).isEqualTo("es");
} }
@Test
public void testPlaylistWithChannelsAttribute() throws IOException {
HlsMasterPlaylist playlist =
parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CHANNELS_ATTRIBUTE);
List<HlsMasterPlaylist.HlsUrl> audios = playlist.audios;
assertThat(audios).hasSize(3);
assertThat(audios.get(0).format.channelCount).isEqualTo(6);
assertThat(audios.get(1).format.channelCount).isEqualTo(2);
assertThat(audios.get(2).format.channelCount).isEqualTo(Format.NO_VALUE);
}
@Test @Test
public void testPlaylistWithoutClosedCaptions() throws IOException { public void testPlaylistWithoutClosedCaptions() throws IOException {
HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITHOUT_CC); HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITHOUT_CC);