Merge HlsParserUtil into HlsPlaylistParser

It's the only place that uses it.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=127927164
This commit is contained in:
olly 2016-07-20 03:01:14 -07:00 committed by Oliver Woodman
parent 722e05b8ba
commit 48f666a0e3
2 changed files with 126 additions and 191 deletions

View File

@ -1,73 +0,0 @@
/*
* Copyright (C) 2016 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.exoplayer2.source.hls.playlist;
import com.google.android.exoplayer2.ParserException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility methods for HLS manifest parsing.
*/
/* package */ final class HlsParserUtil {
private static final String BOOLEAN_TRUE_VALUE = "YES";
private static final String BOOLEAN_FALSE_VALUE = "NO";
private HlsParserUtil() {}
public static String parseStringAttr(String line, Pattern pattern, String tag)
throws ParserException {
Matcher matcher = pattern.matcher(line);
if (matcher.find() && matcher.groupCount() == 1) {
return matcher.group(1);
}
throw new ParserException("Couldn't match " + tag + " tag in " + line);
}
public static int parseIntAttr(String line, Pattern pattern, String tag)
throws ParserException {
return Integer.parseInt(parseStringAttr(line, pattern, tag));
}
public static double parseDoubleAttr(String line, Pattern pattern, String tag)
throws ParserException {
return Double.parseDouble(parseStringAttr(line, pattern, tag));
}
public static String parseOptionalStringAttr(String line, Pattern pattern) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
public static boolean parseBooleanAttribute(String line, Pattern pattern, boolean defaultValue) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
return matcher.group(1).equals(BOOLEAN_TRUE_VALUE);
}
return defaultValue;
}
public static Pattern compileBooleanAttrPattern(String attribute) {
return Pattern.compile(attribute + "=(" + BOOLEAN_FALSE_VALUE + "|" + BOOLEAN_TRUE_VALUE + ")");
}
}

View File

@ -33,6 +33,7 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
@ -40,78 +41,53 @@ import java.util.regex.Pattern;
*/ */
public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlaylist> { public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlaylist> {
private static final String VERSION_TAG = "#EXT-X-VERSION"; private static final String TAG_VERSION = "#EXT-X-VERSION";
private static final String STREAM_INF_TAG = "#EXT-X-STREAM-INF"; private static final String TAG_STREAM_INF = "#EXT-X-STREAM-INF";
private static final String MEDIA_TAG = "#EXT-X-MEDIA"; private static final String TAG_MEDIA = "#EXT-X-MEDIA";
private static final String DISCONTINUITY_TAG = "#EXT-X-DISCONTINUITY"; private static final String TAG_DISCONTINUITY = "#EXT-X-DISCONTINUITY";
private static final String DISCONTINUITY_SEQUENCE_TAG = "#EXT-X-DISCONTINUITY-SEQUENCE"; private static final String TAG_DISCONTINUITY_SEQUENCE = "#EXT-X-DISCONTINUITY-SEQUENCE";
private static final String MEDIA_DURATION_TAG = "#EXTINF"; private static final String TAG_MEDIA_DURATION = "#EXTINF";
private static final String MEDIA_SEQUENCE_TAG = "#EXT-X-MEDIA-SEQUENCE"; private static final String TAG_MEDIA_SEQUENCE = "#EXT-X-MEDIA-SEQUENCE";
private static final String TARGET_DURATION_TAG = "#EXT-X-TARGETDURATION"; private static final String TAG_TARGET_DURATION = "#EXT-X-TARGETDURATION";
private static final String ENDLIST_TAG = "#EXT-X-ENDLIST"; private static final String TAG_ENDLIST = "#EXT-X-ENDLIST";
private static final String KEY_TAG = "#EXT-X-KEY"; private static final String TAG_KEY = "#EXT-X-KEY";
private static final String BYTERANGE_TAG = "#EXT-X-BYTERANGE"; private static final String TAG_BYTERANGE = "#EXT-X-BYTERANGE";
private static final String BANDWIDTH_ATTR = "BANDWIDTH"; private static final String TYPE_AUDIO = "AUDIO";
private static final String CODECS_ATTR = "CODECS"; private static final String TYPE_VIDEO = "VIDEO";
private static final String RESOLUTION_ATTR = "RESOLUTION"; private static final String TYPE_SUBTITLES = "SUBTITLES";
private static final String LANGUAGE_ATTR = "LANGUAGE"; private static final String TYPE_CLOSED_CAPTIONS = "CLOSED-CAPTIONS";
private static final String NAME_ATTR = "NAME";
private static final String TYPE_ATTR = "TYPE";
private static final String METHOD_ATTR = "METHOD";
private static final String URI_ATTR = "URI";
private static final String IV_ATTR = "IV";
private static final String INSTREAM_ID_ATTR = "INSTREAM-ID";
private static final String AUTOSELECT_ATTR = "AUTOSELECT";
private static final String DEFAULT_ATTR = "DEFAULT";
private static final String FORCED_ATTR = "FORCED";
private static final String AUDIO_TYPE = "AUDIO";
private static final String VIDEO_TYPE = "VIDEO";
private static final String SUBTITLES_TYPE = "SUBTITLES";
private static final String CLOSED_CAPTIONS_TYPE = "CLOSED-CAPTIONS";
private static final String METHOD_NONE = "NONE"; private static final String METHOD_NONE = "NONE";
private static final String METHOD_AES128 = "AES-128"; private static final String METHOD_AES128 = "AES-128";
private static final Pattern BANDWIDTH_ATTR_REGEX = private static final String BOOLEAN_TRUE = "YES";
Pattern.compile(BANDWIDTH_ATTR + "=(\\d+)\\b"); private static final String BOOLEAN_FALSE = "NO";
private static final Pattern CODECS_ATTR_REGEX =
Pattern.compile(CODECS_ATTR + "=\"(.+?)\"");
private static final Pattern RESOLUTION_ATTR_REGEX =
Pattern.compile(RESOLUTION_ATTR + "=(\\d+x\\d+)");
private static final Pattern MEDIA_DURATION_REGEX =
Pattern.compile(MEDIA_DURATION_TAG + ":([\\d.]+)\\b");
private static final Pattern MEDIA_SEQUENCE_REGEX =
Pattern.compile(MEDIA_SEQUENCE_TAG + ":(\\d+)\\b");
private static final Pattern TARGET_DURATION_REGEX =
Pattern.compile(TARGET_DURATION_TAG + ":(\\d+)\\b");
private static final Pattern VERSION_REGEX =
Pattern.compile(VERSION_TAG + ":(\\d+)\\b");
private static final Pattern BYTERANGE_REGEX =
Pattern.compile(BYTERANGE_TAG + ":(\\d+(?:@\\d+)?)\\b");
private static final Pattern METHOD_ATTR_REGEX = private static final Pattern REGEX_BANDWIDTH = Pattern.compile("BANDWIDTH=(\\d+)\\b");
Pattern.compile(METHOD_ATTR + "=(" + METHOD_NONE + "|" + METHOD_AES128 + ")"); private static final Pattern REGEX_CODECS = Pattern.compile("CODECS=\"(.+?)\"");
private static final Pattern URI_ATTR_REGEX = private static final Pattern REGEX_RESOLUTION = Pattern.compile("RESOLUTION=(\\d+x\\d+)");
Pattern.compile(URI_ATTR + "=\"(.+?)\""); private static final Pattern REGEX_VERSION = Pattern.compile(TAG_VERSION + ":(\\d+)\\b");
private static final Pattern IV_ATTR_REGEX = private static final Pattern REGEX_TARGET_DURATION = Pattern.compile(TAG_TARGET_DURATION
Pattern.compile(IV_ATTR + "=([^,.*]+)"); + ":(\\d+)\\b");
private static final Pattern TYPE_ATTR_REGEX = private static final Pattern REGEX_MEDIA_SEQUENCE = Pattern.compile(TAG_MEDIA_SEQUENCE
Pattern.compile(TYPE_ATTR + "=(" + AUDIO_TYPE + "|" + VIDEO_TYPE + "|" + SUBTITLES_TYPE + "|" + ":(\\d+)\\b");
+ CLOSED_CAPTIONS_TYPE + ")"); private static final Pattern REGEX_MEDIA_DURATION = Pattern.compile(TAG_MEDIA_DURATION
private static final Pattern LANGUAGE_ATTR_REGEX = + ":([\\d\\.]+)\\b");
Pattern.compile(LANGUAGE_ATTR + "=\"(.+?)\""); private static final Pattern REGEX_BYTERANGE = Pattern.compile(TAG_BYTERANGE
private static final Pattern NAME_ATTR_REGEX = + ":(\\d+(?:@\\d+)?)\\b");
Pattern.compile(NAME_ATTR + "=\"(.+?)\""); private static final Pattern REGEX_METHOD = Pattern.compile("METHOD=(" + METHOD_NONE + "|"
private static final Pattern INSTREAM_ID_ATTR_REGEX = + METHOD_AES128 + ")");
Pattern.compile(INSTREAM_ID_ATTR + "=\"(.+?)\""); private static final Pattern REGEX_URI = Pattern.compile("URI=\"(.+?)\"");
private static final Pattern AUTOSELECT_ATTR_REGEX = private static final Pattern REGEX_IV = Pattern.compile("IV=([^,.*]+)");
HlsParserUtil.compileBooleanAttrPattern(AUTOSELECT_ATTR); private static final Pattern REGEX_TYPE = Pattern.compile("TYPE=(" + TYPE_AUDIO + "|" + TYPE_VIDEO
private static final Pattern DEFAULT_ATTR_REGEX = + "|" + TYPE_SUBTITLES + "|" + TYPE_CLOSED_CAPTIONS + ")");
HlsParserUtil.compileBooleanAttrPattern(DEFAULT_ATTR); private static final Pattern REGEX_LANGUAGE = Pattern.compile("LANGUAGE=\"(.+?)\"");
private static final Pattern FORCED_ATTR_REGEX = private static final Pattern REGEX_NAME = Pattern.compile("NAME=\"(.+?)\"");
HlsParserUtil.compileBooleanAttrPattern(FORCED_ATTR); private static final Pattern REGEX_INSTREAM_ID = Pattern.compile("INSTREAM-ID=\"(.+?)\"");
private static final Pattern REGEX_AUTOSELECT = compileBooleanAttrPattern("AUTOSELECT");
private static final Pattern REGEX_DEFAULT = compileBooleanAttrPattern("DEFAULT");
private static final Pattern REGEX_FORCED = compileBooleanAttrPattern("FORCED");
@Override @Override
public HlsPlaylist parse(Uri uri, InputStream inputStream) throws IOException { public HlsPlaylist parse(Uri uri, InputStream inputStream) throws IOException {
@ -123,17 +99,17 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
line = line.trim(); line = line.trim();
if (line.isEmpty()) { if (line.isEmpty()) {
// Do nothing. // Do nothing.
} else if (line.startsWith(STREAM_INF_TAG)) { } else if (line.startsWith(TAG_STREAM_INF)) {
extraLines.add(line); extraLines.add(line);
return parseMasterPlaylist(new LineIterator(extraLines, reader), uri.toString()); return parseMasterPlaylist(new LineIterator(extraLines, reader), uri.toString());
} else if (line.startsWith(TARGET_DURATION_TAG) } else if (line.startsWith(TAG_TARGET_DURATION)
|| line.startsWith(MEDIA_SEQUENCE_TAG) || line.startsWith(TAG_MEDIA_SEQUENCE)
|| line.startsWith(MEDIA_DURATION_TAG) || line.startsWith(TAG_MEDIA_DURATION)
|| line.startsWith(KEY_TAG) || line.startsWith(TAG_KEY)
|| line.startsWith(BYTERANGE_TAG) || line.startsWith(TAG_BYTERANGE)
|| line.equals(DISCONTINUITY_TAG) || line.equals(TAG_DISCONTINUITY)
|| line.equals(DISCONTINUITY_SEQUENCE_TAG) || line.equals(TAG_DISCONTINUITY_SEQUENCE)
|| line.equals(ENDLIST_TAG)) { || line.equals(TAG_ENDLIST)) {
extraLines.add(line); extraLines.add(line);
return parseMediaPlaylist(new LineIterator(extraLines, reader), uri.toString()); return parseMediaPlaylist(new LineIterator(extraLines, reader), uri.toString());
} else { } else {
@ -163,39 +139,38 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
String line; String line;
while (iterator.hasNext()) { while (iterator.hasNext()) {
line = iterator.next(); line = iterator.next();
if (line.startsWith(MEDIA_TAG)) { if (line.startsWith(TAG_MEDIA)) {
boolean isDefault = HlsParserUtil.parseBooleanAttribute(line, DEFAULT_ATTR_REGEX, false); boolean isDefault = parseBooleanAttribute(line, REGEX_DEFAULT, false);
boolean isForced = HlsParserUtil.parseBooleanAttribute(line, FORCED_ATTR_REGEX, false); boolean isForced = parseBooleanAttribute(line, REGEX_FORCED, false);
boolean isAutoselect = HlsParserUtil.parseBooleanAttribute(line, AUTOSELECT_ATTR_REGEX, boolean isAutoselect = parseBooleanAttribute(line, REGEX_AUTOSELECT,
false); false);
int selectionFlags = (isDefault ? Format.SELECTION_FLAG_DEFAULT : 0) int selectionFlags = (isDefault ? Format.SELECTION_FLAG_DEFAULT : 0)
| (isForced ? Format.SELECTION_FLAG_FORCED : 0) | (isForced ? Format.SELECTION_FLAG_FORCED : 0)
| (isAutoselect ? Format.SELECTION_FLAG_AUTOSELECT : 0); | (isAutoselect ? Format.SELECTION_FLAG_AUTOSELECT : 0);
String type = HlsParserUtil.parseStringAttr(line, TYPE_ATTR_REGEX, TYPE_ATTR); String type = parseStringAttr(line, REGEX_TYPE);
if (CLOSED_CAPTIONS_TYPE.equals(type)) { if (TYPE_CLOSED_CAPTIONS.equals(type)) {
String instreamId = HlsParserUtil.parseStringAttr(line, INSTREAM_ID_ATTR_REGEX, String instreamId = parseStringAttr(line, REGEX_INSTREAM_ID);
INSTREAM_ID_ATTR);
if ("CC1".equals(instreamId)) { if ("CC1".equals(instreamId)) {
// We assume all subtitles belong to the same group. // We assume all subtitles belong to the same group.
String captionName = HlsParserUtil.parseStringAttr(line, NAME_ATTR_REGEX, NAME_ATTR); String captionName = parseStringAttr(line, REGEX_NAME);
String language = HlsParserUtil.parseOptionalStringAttr(line, LANGUAGE_ATTR_REGEX); String language = parseOptionalStringAttr(line, REGEX_LANGUAGE);
muxedCaptionFormat = Format.createTextContainerFormat(captionName, muxedCaptionFormat = Format.createTextContainerFormat(captionName,
MimeTypes.APPLICATION_M3U8, MimeTypes.APPLICATION_EIA608, null, -1, selectionFlags, MimeTypes.APPLICATION_M3U8, MimeTypes.APPLICATION_EIA608, null, -1, selectionFlags,
language); language);
} }
} else if (SUBTITLES_TYPE.equals(type)) { } else if (TYPE_SUBTITLES.equals(type)) {
// We assume all subtitles belong to the same group. // We assume all subtitles belong to the same group.
String subtitleName = HlsParserUtil.parseStringAttr(line, NAME_ATTR_REGEX, NAME_ATTR); String subtitleName = parseStringAttr(line, REGEX_NAME);
String uri = HlsParserUtil.parseStringAttr(line, URI_ATTR_REGEX, URI_ATTR); String uri = parseStringAttr(line, REGEX_URI);
String language = HlsParserUtil.parseOptionalStringAttr(line, LANGUAGE_ATTR_REGEX); String language = parseOptionalStringAttr(line, REGEX_LANGUAGE);
Format format = Format.createTextContainerFormat(subtitleName, MimeTypes.APPLICATION_M3U8, Format format = Format.createTextContainerFormat(subtitleName, MimeTypes.APPLICATION_M3U8,
MimeTypes.TEXT_VTT, null, bitrate, selectionFlags, language); MimeTypes.TEXT_VTT, null, bitrate, selectionFlags, language);
subtitles.add(new Variant(uri, format, codecs)); subtitles.add(new Variant(uri, format, codecs));
} else if (AUDIO_TYPE.equals(type)) { } else if (TYPE_AUDIO.equals(type)) {
// We assume all audios belong to the same group. // We assume all audios belong to the same group.
String uri = HlsParserUtil.parseOptionalStringAttr(line, URI_ATTR_REGEX); String uri = parseOptionalStringAttr(line, REGEX_URI);
String language = HlsParserUtil.parseOptionalStringAttr(line, LANGUAGE_ATTR_REGEX); String language = parseOptionalStringAttr(line, REGEX_LANGUAGE);
String audioName = HlsParserUtil.parseStringAttr(line, NAME_ATTR_REGEX, NAME_ATTR); String audioName = parseStringAttr(line, REGEX_NAME);
int audioBitrate = uri != null ? bitrate : -1; int audioBitrate = uri != null ? bitrate : -1;
Format format = Format.createAudioContainerFormat(audioName, MimeTypes.APPLICATION_M3U8, Format format = Format.createAudioContainerFormat(audioName, MimeTypes.APPLICATION_M3U8,
null, null, audioBitrate, -1, -1, null, selectionFlags, language); null, null, audioBitrate, -1, -1, null, selectionFlags, language);
@ -205,12 +180,11 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
muxedAudioFormat = format; muxedAudioFormat = format;
} }
} }
} else if (line.startsWith(STREAM_INF_TAG)) { } else if (line.startsWith(TAG_STREAM_INF)) {
bitrate = HlsParserUtil.parseIntAttr(line, BANDWIDTH_ATTR_REGEX, BANDWIDTH_ATTR); bitrate = parseIntAttr(line, REGEX_BANDWIDTH);
codecs = HlsParserUtil.parseOptionalStringAttr(line, CODECS_ATTR_REGEX); codecs = parseOptionalStringAttr(line, REGEX_CODECS);
name = HlsParserUtil.parseOptionalStringAttr(line, NAME_ATTR_REGEX); name = parseOptionalStringAttr(line, REGEX_NAME);
String resolutionString = HlsParserUtil.parseOptionalStringAttr(line, String resolutionString = parseOptionalStringAttr(line, REGEX_RESOLUTION);
RESOLUTION_ATTR_REGEX);
if (resolutionString != null) { if (resolutionString != null) {
String[] widthAndHeight = resolutionString.split("x"); String[] widthAndHeight = resolutionString.split("x");
width = Integer.parseInt(widthAndHeight[0]); width = Integer.parseInt(widthAndHeight[0]);
@ -269,37 +243,35 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
String line; String line;
while (iterator.hasNext()) { while (iterator.hasNext()) {
line = iterator.next(); line = iterator.next();
if (line.startsWith(TARGET_DURATION_TAG)) { if (line.startsWith(TAG_TARGET_DURATION)) {
targetDurationSecs = HlsParserUtil.parseIntAttr(line, TARGET_DURATION_REGEX, targetDurationSecs = parseIntAttr(line, REGEX_TARGET_DURATION);
TARGET_DURATION_TAG); } else if (line.startsWith(TAG_MEDIA_SEQUENCE)) {
} else if (line.startsWith(MEDIA_SEQUENCE_TAG)) { mediaSequence = parseIntAttr(line, REGEX_MEDIA_SEQUENCE);
mediaSequence = HlsParserUtil.parseIntAttr(line, MEDIA_SEQUENCE_REGEX, MEDIA_SEQUENCE_TAG);
segmentMediaSequence = mediaSequence; segmentMediaSequence = mediaSequence;
} else if (line.startsWith(VERSION_TAG)) { } else if (line.startsWith(TAG_VERSION)) {
version = HlsParserUtil.parseIntAttr(line, VERSION_REGEX, VERSION_TAG); version = parseIntAttr(line, REGEX_VERSION);
} else if (line.startsWith(MEDIA_DURATION_TAG)) { } else if (line.startsWith(TAG_MEDIA_DURATION)) {
segmentDurationSecs = HlsParserUtil.parseDoubleAttr(line, MEDIA_DURATION_REGEX, segmentDurationSecs = parseDoubleAttr(line, REGEX_MEDIA_DURATION);
MEDIA_DURATION_TAG); } else if (line.startsWith(TAG_KEY)) {
} else if (line.startsWith(KEY_TAG)) { String method = parseStringAttr(line, REGEX_METHOD);
String method = HlsParserUtil.parseStringAttr(line, METHOD_ATTR_REGEX, METHOD_ATTR);
isEncrypted = METHOD_AES128.equals(method); isEncrypted = METHOD_AES128.equals(method);
if (isEncrypted) { if (isEncrypted) {
encryptionKeyUri = HlsParserUtil.parseStringAttr(line, URI_ATTR_REGEX, URI_ATTR); encryptionKeyUri = parseStringAttr(line, REGEX_URI);
encryptionIV = HlsParserUtil.parseOptionalStringAttr(line, IV_ATTR_REGEX); encryptionIV = parseOptionalStringAttr(line, REGEX_IV);
} else { } else {
encryptionKeyUri = null; encryptionKeyUri = null;
encryptionIV = null; encryptionIV = null;
} }
} else if (line.startsWith(BYTERANGE_TAG)) { } else if (line.startsWith(TAG_BYTERANGE)) {
String byteRange = HlsParserUtil.parseStringAttr(line, BYTERANGE_REGEX, BYTERANGE_TAG); String byteRange = parseStringAttr(line, REGEX_BYTERANGE);
String[] splitByteRange = byteRange.split("@"); String[] splitByteRange = byteRange.split("@");
segmentByterangeLength = Long.parseLong(splitByteRange[0]); segmentByterangeLength = Long.parseLong(splitByteRange[0]);
if (splitByteRange.length > 1) { if (splitByteRange.length > 1) {
segmentByterangeOffset = Long.parseLong(splitByteRange[1]); segmentByterangeOffset = Long.parseLong(splitByteRange[1]);
} }
} else if (line.startsWith(DISCONTINUITY_SEQUENCE_TAG)) { } else if (line.startsWith(TAG_DISCONTINUITY_SEQUENCE)) {
discontinuitySequenceNumber = Integer.parseInt(line.substring(line.indexOf(':') + 1)); discontinuitySequenceNumber = Integer.parseInt(line.substring(line.indexOf(':') + 1));
} else if (line.equals(DISCONTINUITY_TAG)) { } else if (line.equals(TAG_DISCONTINUITY)) {
discontinuitySequenceNumber++; discontinuitySequenceNumber++;
} else if (!line.startsWith("#")) { } else if (!line.startsWith("#")) {
String segmentEncryptionIV; String segmentEncryptionIV;
@ -323,7 +295,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
segmentByterangeOffset += segmentByterangeLength; segmentByterangeOffset += segmentByterangeLength;
} }
segmentByterangeLength = C.LENGTH_UNBOUNDED; segmentByterangeLength = C.LENGTH_UNBOUNDED;
} else if (line.equals(ENDLIST_TAG)) { } else if (line.equals(TAG_ENDLIST)) {
live = false; live = false;
} }
} }
@ -331,6 +303,42 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
Collections.unmodifiableList(segments)); Collections.unmodifiableList(segments));
} }
private static String parseStringAttr(String line, Pattern pattern) throws ParserException {
Matcher matcher = pattern.matcher(line);
if (matcher.find() && matcher.groupCount() == 1) {
return matcher.group(1);
}
throw new ParserException("Couldn't match " + pattern.pattern() + " in " + line);
}
private static int parseIntAttr(String line, Pattern pattern) throws ParserException {
return Integer.parseInt(parseStringAttr(line, pattern));
}
private static double parseDoubleAttr(String line, Pattern pattern) throws ParserException {
return Double.parseDouble(parseStringAttr(line, pattern));
}
private static String parseOptionalStringAttr(String line, Pattern pattern) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
private static boolean parseBooleanAttribute(String line, Pattern pattern, boolean defaultValue) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
return matcher.group(1).equals(BOOLEAN_TRUE);
}
return defaultValue;
}
private static Pattern compileBooleanAttrPattern(String attribute) {
return Pattern.compile(attribute + "=(" + BOOLEAN_FALSE + "|" + BOOLEAN_TRUE + ")");
}
private static class LineIterator { private static class LineIterator {
private final BufferedReader reader; private final BufferedReader reader;