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:
parent
722e05b8ba
commit
48f666a0e3
@ -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 + ")");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user