mirror of
https://github.com/androidx/media.git
synced 2025-05-10 09:12:16 +08:00
Parse EXT-X-MEDIA tags with SUBTITLES type.
Not yet used by anything. Issue: #151
This commit is contained in:
parent
be103106cb
commit
1ebaaaebd5
@ -23,10 +23,12 @@ import java.util.List;
|
||||
public final class HlsMasterPlaylist extends HlsPlaylist {
|
||||
|
||||
public final List<Variant> variants;
|
||||
public final List<Subtitle> subtitles;
|
||||
|
||||
public HlsMasterPlaylist(String baseUri, List<Variant> variants) {
|
||||
public HlsMasterPlaylist(String baseUri, List<Variant> variants, List<Subtitle> subtitles) {
|
||||
super(baseUri, HlsPlaylist.TYPE_MASTER);
|
||||
this.variants = variants;
|
||||
this.subtitles = subtitles;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
/* package */ class HlsParserUtil {
|
||||
|
||||
private static final String BOOLEAN_YES = "YES";
|
||||
|
||||
private HlsParserUtil() {}
|
||||
|
||||
public static String parseStringAttr(String line, Pattern pattern, String tag)
|
||||
@ -36,14 +38,6 @@ import java.util.regex.Pattern;
|
||||
throw new ParserException(String.format("Couldn't match %s tag in %s", tag, line));
|
||||
}
|
||||
|
||||
public static String parseOptionalStringAttr(String line, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.find() && matcher.groupCount() == 1) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int parseIntAttr(String line, Pattern pattern, String tag)
|
||||
throws ParserException {
|
||||
return Integer.parseInt(parseStringAttr(line, pattern, tag));
|
||||
@ -54,4 +48,20 @@ import java.util.regex.Pattern;
|
||||
return Double.parseDouble(parseStringAttr(line, pattern, tag));
|
||||
}
|
||||
|
||||
public static String parseOptionalStringAttr(String line, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.find() && matcher.groupCount() == 1) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean parseOptionalBoolAttr(String line, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.find() && matcher.groupCount() == 1) {
|
||||
return BOOLEAN_YES.equals(matcher.group(1));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,12 +37,8 @@ import java.util.regex.Pattern;
|
||||
public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlaylist> {
|
||||
|
||||
private static final String VERSION_TAG = "#EXT-X-VERSION";
|
||||
|
||||
private static final String STREAM_INF_TAG = "#EXT-X-STREAM-INF";
|
||||
private static final String BANDWIDTH_ATTR = "BANDWIDTH";
|
||||
private static final String CODECS_ATTR = "CODECS";
|
||||
private static final String RESOLUTION_ATTR = "RESOLUTION";
|
||||
|
||||
private static final String MEDIA_TAG = "#EXT-X-MEDIA";
|
||||
private static final String DISCONTINUITY_TAG = "#EXT-X-DISCONTINUITY";
|
||||
private static final String MEDIA_DURATION_TAG = "#EXTINF";
|
||||
private static final String MEDIA_SEQUENCE_TAG = "#EXT-X-MEDIA-SEQUENCE";
|
||||
@ -51,17 +47,29 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
|
||||
private static final String KEY_TAG = "#EXT-X-KEY";
|
||||
private static final String BYTERANGE_TAG = "#EXT-X-BYTERANGE";
|
||||
|
||||
private static final String BANDWIDTH_ATTR = "BANDWIDTH";
|
||||
private static final String CODECS_ATTR = "CODECS";
|
||||
private static final String RESOLUTION_ATTR = "RESOLUTION";
|
||||
private static final String LANGUAGE_ATTR = "LANGUAGE";
|
||||
private static final String NAME_ATTR = "NAME";
|
||||
private static final String AUTOSELECT_ATTR = "AUTOSELECT";
|
||||
private static final String DEFAULT_ATTR = "DEFAULT";
|
||||
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 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 Pattern BANDWIDTH_ATTR_REGEX =
|
||||
Pattern.compile(BANDWIDTH_ATTR + "=(\\d+)\\b");
|
||||
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.]+),");
|
||||
private static final Pattern MEDIA_SEQUENCE_REGEX =
|
||||
@ -72,13 +80,23 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
|
||||
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 =
|
||||
Pattern.compile(METHOD_ATTR + "=([^,.*]+)");
|
||||
private static final Pattern URI_ATTR_REGEX =
|
||||
Pattern.compile(URI_ATTR + "=\"(.+)\"");
|
||||
private static final Pattern IV_ATTR_REGEX =
|
||||
Pattern.compile(IV_ATTR + "=([^,.*]+)");
|
||||
private static final Pattern TYPE_ATTR_REGEX =
|
||||
Pattern.compile(TYPE_ATTR + "=(" + AUDIO_TYPE + "|" + VIDEO_TYPE + "|" + SUBTITLES_TYPE + "|"
|
||||
+ CLOSED_CAPTIONS_TYPE + ")");
|
||||
private static final Pattern LANGUAGE_ATTR_REGEX =
|
||||
Pattern.compile(LANGUAGE_ATTR + "=\"(.+?)\"");
|
||||
private static final Pattern NAME_ATTR_REGEX =
|
||||
Pattern.compile(NAME_ATTR + "=\"(.+?)\"");
|
||||
private static final Pattern AUTOSELECT_ATTR_REGEX =
|
||||
Pattern.compile(AUTOSELECT_ATTR + "=\"(.+?)\"");
|
||||
private static final Pattern DEFAULT_ATTR_REGEX =
|
||||
Pattern.compile(DEFAULT_ATTR + "=\"(.+?)\"");
|
||||
|
||||
@Override
|
||||
public HlsPlaylist parse(String connectionUrl, InputStream inputStream)
|
||||
@ -103,10 +121,8 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
|
||||
|| line.equals(ENDLIST_TAG)) {
|
||||
extraLines.add(line);
|
||||
return parseMediaPlaylist(new LineIterator(extraLines, reader), connectionUrl);
|
||||
} else if (line.startsWith(VERSION_TAG)) {
|
||||
} else {
|
||||
extraLines.add(line);
|
||||
} else if (!line.startsWith("#")) {
|
||||
throw new ParserException("Missing a tag before URL.");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@ -117,17 +133,32 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
|
||||
|
||||
private static HlsMasterPlaylist parseMasterPlaylist(LineIterator iterator, String baseUri)
|
||||
throws IOException {
|
||||
List<Variant> variants = new ArrayList<Variant>();
|
||||
ArrayList<Variant> variants = new ArrayList<Variant>();
|
||||
ArrayList<Subtitle> subtitles = new ArrayList<Subtitle>();
|
||||
int bandwidth = 0;
|
||||
String[] codecs = null;
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
int variantIndex = 0;
|
||||
|
||||
boolean expectingStreamInfUrl = false;
|
||||
String line;
|
||||
while (iterator.hasNext()) {
|
||||
line = iterator.next();
|
||||
if (line.startsWith(STREAM_INF_TAG)) {
|
||||
if (line.startsWith(MEDIA_TAG)) {
|
||||
String type = HlsParserUtil.parseStringAttr(line, TYPE_ATTR_REGEX, TYPE_ATTR);
|
||||
if (SUBTITLES_TYPE.equals(type)) {
|
||||
// We assume all subtitles belong to the same group.
|
||||
String name = HlsParserUtil.parseStringAttr(line, NAME_ATTR_REGEX, NAME_ATTR);
|
||||
String uri = HlsParserUtil.parseStringAttr(line, URI_ATTR_REGEX, URI_ATTR);
|
||||
String language = HlsParserUtil.parseOptionalStringAttr(line, LANGUAGE_ATTR_REGEX);
|
||||
boolean isDefault = HlsParserUtil.parseOptionalBoolAttr(line, DEFAULT_ATTR_REGEX);
|
||||
boolean autoSelect = HlsParserUtil.parseOptionalBoolAttr(line, AUTOSELECT_ATTR_REGEX);
|
||||
subtitles.add(new Subtitle(name, uri, language, isDefault, autoSelect));
|
||||
} else {
|
||||
// TODO: Support other types of media tag.
|
||||
}
|
||||
} else if (line.startsWith(STREAM_INF_TAG)) {
|
||||
bandwidth = HlsParserUtil.parseIntAttr(line, BANDWIDTH_ATTR_REGEX, BANDWIDTH_ATTR);
|
||||
String codecsString = HlsParserUtil.parseOptionalStringAttr(line, CODECS_ATTR_REGEX);
|
||||
if (codecsString != null) {
|
||||
@ -145,15 +176,18 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
|
||||
width = -1;
|
||||
height = -1;
|
||||
}
|
||||
} else if (!line.startsWith("#")) {
|
||||
expectingStreamInfUrl = true;
|
||||
} else if (!line.startsWith("#") && expectingStreamInfUrl) {
|
||||
variants.add(new Variant(variantIndex++, line, bandwidth, codecs, width, height));
|
||||
bandwidth = 0;
|
||||
codecs = null;
|
||||
width = -1;
|
||||
height = -1;
|
||||
expectingStreamInfUrl = false;
|
||||
}
|
||||
}
|
||||
return new HlsMasterPlaylist(baseUri, Collections.unmodifiableList(variants));
|
||||
return new HlsMasterPlaylist(baseUri, Collections.unmodifiableList(variants),
|
||||
Collections.unmodifiableList(subtitles));
|
||||
}
|
||||
|
||||
private static HlsMediaPlaylist parseMediaPlaylist(LineIterator iterator, String baseUri)
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.exoplayer.hls;
|
||||
|
||||
/**
|
||||
* Subtitle media tag.
|
||||
*/
|
||||
public final class Subtitle {
|
||||
|
||||
public final String name;
|
||||
public final String uri;
|
||||
public final String language;
|
||||
public final boolean isDefault;
|
||||
public final boolean autoSelect;
|
||||
|
||||
public Subtitle(String name, String uri, String language, boolean isDefault, boolean autoSelect) {
|
||||
this.name = name;
|
||||
this.uri = uri;
|
||||
this.language = language;
|
||||
this.autoSelect = autoSelect;
|
||||
this.isDefault = isDefault;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user