DASH: Parse Role elements to select default audio/text tracks

Issue: #2058

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144693705
This commit is contained in:
olly 2017-01-17 04:06:14 -08:00 committed by Oliver Woodman
parent 6e481178ea
commit 7f967f3057
6 changed files with 54 additions and 35 deletions

View File

@ -29,13 +29,13 @@ public class RepresentationTest extends TestCase {
String uri = "http://www.google.com"; String uri = "http://www.google.com";
SegmentBase base = new SingleSegmentBase(new RangedUri(null, 0, 1), 1, 0, 1, 1); SegmentBase base = new SingleSegmentBase(new RangedUri(null, 0, 1), 1, 0, 1, 1);
Format format = Format.createVideoContainerFormat("0", MimeTypes.APPLICATION_MP4, null, Format format = Format.createVideoContainerFormat("0", MimeTypes.APPLICATION_MP4, null,
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null); MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null, 0);
Representation representation = Representation.newInstance("test_stream_1", 3, format, uri, Representation representation = Representation.newInstance("test_stream_1", 3, format, uri,
base); base);
assertEquals("test_stream_1.0.3", representation.getCacheKey()); assertEquals("test_stream_1.0.3", representation.getCacheKey());
format = Format.createVideoContainerFormat("150", MimeTypes.APPLICATION_MP4, null, format = Format.createVideoContainerFormat("150", MimeTypes.APPLICATION_MP4, null,
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null); MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null, 0);
representation = Representation.newInstance("test_stream_1", Representation.REVISION_ID_DEFAULT, representation = Representation.newInstance("test_stream_1", Representation.REVISION_ID_DEFAULT,
format, uri, base); format, uri, base);
assertEquals("test_stream_1.150.-1", representation.getCacheKey()); assertEquals("test_stream_1.150.-1", representation.getCacheKey());

View File

@ -192,11 +192,11 @@ public final class Format implements Parcelable {
public static Format createVideoContainerFormat(String id, String containerMimeType, public static Format createVideoContainerFormat(String id, String containerMimeType,
String sampleMimeType, String codecs, int bitrate, int width, int height, String sampleMimeType, String codecs, int bitrate, int width, int height,
float frameRate, List<byte[]> initializationData) { float frameRate, List<byte[]> initializationData, @C.SelectionFlags int selectionFlags) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, width, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, width,
height, frameRate, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, height, frameRate, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, null, NO_VALUE, NO_VALUE, selectionFlags, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE,
null); initializationData, null, null);
} }
public static Format createVideoSampleFormat(String id, String sampleMimeType, String codecs, public static Format createVideoSampleFormat(String id, String sampleMimeType, String codecs,
@ -289,8 +289,8 @@ public final class Format implements Parcelable {
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs,
int bitrate, @C.SelectionFlags int selectionFlags, String language, int bitrate, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel,
int accessibilityChannel, DrmInitData drmInitData) { DrmInitData drmInitData) {
return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language,
accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE); accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE);
} }
@ -323,11 +323,13 @@ public final class Format implements Parcelable {
// Generic. // Generic.
public static Format createContainerFormat(String id, String containerMimeType, String codecs, public static Format createContainerFormat(String id, String containerMimeType,
String sampleMimeType, int bitrate) { String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags,
String language) {
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, null, null); NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, null,
null);
} }
public static Format createSampleFormat(String id, String sampleMimeType, public static Format createSampleFormat(String id, String sampleMimeType,

View File

@ -243,6 +243,7 @@ public class DashManifestParser extends DefaultHandler
List<RepresentationInfo> representationInfos = new ArrayList<>(); List<RepresentationInfo> representationInfos = new ArrayList<>();
List<InbandEventStream> adaptationSetInbandEventStreams = new ArrayList<>(); List<InbandEventStream> adaptationSetInbandEventStreams = new ArrayList<>();
List<InbandEventStream> commonRepresentationInbandEventStreams = null; List<InbandEventStream> commonRepresentationInbandEventStreams = null;
@C.SelectionFlags int selectionFlags = 0;
boolean seenFirstBaseUrl = false; boolean seenFirstBaseUrl = false;
do { do {
@ -260,10 +261,16 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentComponent")) { } else if (XmlPullParserUtil.isStartTag(xpp, "ContentComponent")) {
language = checkLanguageConsistency(language, xpp.getAttributeValue(null, "lang")); language = checkLanguageConsistency(language, xpp.getAttributeValue(null, "lang"));
contentType = checkContentTypeConsistency(contentType, parseContentType(xpp)); contentType = checkContentTypeConsistency(contentType, parseContentType(xpp));
} else if (XmlPullParserUtil.isStartTag(xpp, "Role")) {
selectionFlags |= parseRole(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
audioChannels = parseAudioChannelConfiguration(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "Accessibility")) {
accessibilityChannel = parseAccessibilityValue(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "Representation")) { } else if (XmlPullParserUtil.isStartTag(xpp, "Representation")) {
RepresentationInfo representationInfo = parseRepresentation(xpp, baseUrl, mimeType, codecs, RepresentationInfo representationInfo = parseRepresentation(xpp, baseUrl, mimeType, codecs,
width, height, frameRate, audioChannels, audioSamplingRate, language, width, height, frameRate, audioChannels, audioSamplingRate, language,
accessibilityChannel, segmentBase); accessibilityChannel, selectionFlags, segmentBase);
contentType = checkContentTypeConsistency(contentType, contentType = checkContentTypeConsistency(contentType,
getContentType(representationInfo.format)); getContentType(representationInfo.format));
representationInfos.add(representationInfo); representationInfos.add(representationInfo);
@ -283,10 +290,6 @@ public class DashManifestParser extends DefaultHandler
} }
} }
} }
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
audioChannels = parseAudioChannelConfiguration(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "Accessibility")) {
accessibilityChannel = parseAccessibilityValue(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase); segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
@ -402,6 +405,24 @@ public class DashManifestParser extends DefaultHandler
return new InbandEventStream(schemeIdUri, value); return new InbandEventStream(schemeIdUri, value);
} }
/**
* Parses a Role element.
*
* @param xpp The parser from which to read.
* @throws XmlPullParserException If an error occurs parsing the element.
* @throws IOException If an error occurs reading the element.
* @return {@link C.SelectionFlags} parsed from the element.
*/
protected int parseRole(XmlPullParser xpp) throws XmlPullParserException, IOException {
String schemeIdUri = parseString(xpp, "schemeIdUri", null);
String value = parseString(xpp, "value", null);
do {
xpp.next();
} while (!XmlPullParserUtil.isEndTag(xpp, "Role"));
return "urn:mpeg:dash:role:2011".equals(schemeIdUri) && "main".equals(value)
? C.SELECTION_FLAG_DEFAULT : 0;
}
/** /**
* Parses children of AdaptationSet elements not specifically parsed elsewhere. * Parses children of AdaptationSet elements not specifically parsed elsewhere.
* *
@ -420,8 +441,8 @@ public class DashManifestParser extends DefaultHandler
String adaptationSetMimeType, String adaptationSetCodecs, int adaptationSetWidth, String adaptationSetMimeType, String adaptationSetCodecs, int adaptationSetWidth,
int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels, int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels,
int adaptationSetAudioSamplingRate, String adaptationSetLanguage, int adaptationSetAudioSamplingRate, String adaptationSetLanguage,
int adaptationSetAccessibilityChannel, SegmentBase segmentBase) int adaptationSetAccessibilityChannel, @C.SelectionFlags int adaptationSetSelectionFlags,
throws XmlPullParserException, IOException { SegmentBase segmentBase) throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id"); String id = xpp.getAttributeValue(null, "id");
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
@ -463,7 +484,7 @@ public class DashManifestParser extends DefaultHandler
Format format = buildFormat(id, mimeType, width, height, frameRate, audioChannels, Format format = buildFormat(id, mimeType, width, height, frameRate, audioChannels,
audioSamplingRate, bandwidth, adaptationSetLanguage, adaptationSetAccessibilityChannel, audioSamplingRate, bandwidth, adaptationSetLanguage, adaptationSetAccessibilityChannel,
codecs); adaptationSetSelectionFlags, codecs);
segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase(); segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase();
return new RepresentationInfo(format, baseUrl, segmentBase, drmSchemeDatas, inbandEventStreams); return new RepresentationInfo(format, baseUrl, segmentBase, drmSchemeDatas, inbandEventStreams);
@ -471,27 +492,23 @@ public class DashManifestParser extends DefaultHandler
protected Format buildFormat(String id, String containerMimeType, int width, int height, protected Format buildFormat(String id, String containerMimeType, int width, int height,
float frameRate, int audioChannels, int audioSamplingRate, int bitrate, String language, float frameRate, int audioChannels, int audioSamplingRate, int bitrate, String language,
int accessiblityChannel, String codecs) { int accessiblityChannel, @C.SelectionFlags int selectionFlags, String codecs) {
String sampleMimeType = getSampleMimeType(containerMimeType, codecs); String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
if (sampleMimeType != null) { if (sampleMimeType != null) {
if (MimeTypes.isVideo(sampleMimeType)) { if (MimeTypes.isVideo(sampleMimeType)) {
return Format.createVideoContainerFormat(id, containerMimeType, sampleMimeType, codecs, return Format.createVideoContainerFormat(id, containerMimeType, sampleMimeType, codecs,
bitrate, width, height, frameRate, null); bitrate, width, height, frameRate, null, selectionFlags);
} else if (MimeTypes.isAudio(sampleMimeType)) { } else if (MimeTypes.isAudio(sampleMimeType)) {
return Format.createAudioContainerFormat(id, containerMimeType, sampleMimeType, codecs, return Format.createAudioContainerFormat(id, containerMimeType, sampleMimeType, codecs,
bitrate, audioChannels, audioSamplingRate, null, 0, language); bitrate, audioChannels, audioSamplingRate, null, selectionFlags, language);
} else if (mimeTypeIsRawText(sampleMimeType)) { } else if (mimeTypeIsRawText(sampleMimeType)
|| MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs, return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs,
bitrate, 0, language, accessiblityChannel); bitrate, selectionFlags, language, accessiblityChannel);
} else if (containerMimeType.equals(MimeTypes.APPLICATION_RAWCC)) {
return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs,
bitrate, 0, language, accessiblityChannel);
} else {
return Format.createContainerFormat(id, containerMimeType, codecs, sampleMimeType, bitrate);
} }
} else {
return Format.createContainerFormat(id, containerMimeType, codecs, sampleMimeType, bitrate);
} }
return Format.createContainerFormat(id, containerMimeType, sampleMimeType, codecs, bitrate,
selectionFlags, language);
} }
protected Representation buildRepresentation(RepresentationInfo representationInfo, protected Representation buildRepresentation(RepresentationInfo representationInfo,

View File

@ -40,7 +40,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
public static HlsUrl createMediaPlaylistHlsUrl(String baseUri) { public static HlsUrl createMediaPlaylistHlsUrl(String baseUri) {
Format format = Format.createContainerFormat("0", MimeTypes.APPLICATION_M3U8, null, null, Format format = Format.createContainerFormat("0", MimeTypes.APPLICATION_M3U8, null, null,
Format.NO_VALUE); Format.NO_VALUE, 0, null);
return new HlsUrl(null, baseUri, format, null, null, null); return new HlsUrl(null, baseUri, format, null, null, null);
} }

View File

@ -240,7 +240,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
line = iterator.next(); line = iterator.next();
String name = Integer.toString(variants.size()); String name = Integer.toString(variants.size());
Format format = Format.createVideoContainerFormat(name, MimeTypes.APPLICATION_M3U8, null, Format format = Format.createVideoContainerFormat(name, MimeTypes.APPLICATION_M3U8, null,
codecs, bitrate, width, height, Format.NO_VALUE, null); codecs, bitrate, width, height, Format.NO_VALUE, null, 0);
variants.add(new HlsMasterPlaylist.HlsUrl(name, line, format, null, null, null)); variants.add(new HlsMasterPlaylist.HlsUrl(name, line, format, null, null, null));
} }
} }

View File

@ -625,7 +625,7 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
List<byte[]> codecSpecificData = buildCodecSpecificData( List<byte[]> codecSpecificData = buildCodecSpecificData(
parser.getAttributeValue(null, KEY_CODEC_PRIVATE_DATA)); parser.getAttributeValue(null, KEY_CODEC_PRIVATE_DATA));
format = Format.createVideoContainerFormat(id, MimeTypes.VIDEO_MP4, sampleMimeType, null, format = Format.createVideoContainerFormat(id, MimeTypes.VIDEO_MP4, sampleMimeType, null,
bitrate, width, height, Format.NO_VALUE, codecSpecificData); bitrate, width, height, Format.NO_VALUE, codecSpecificData, 0);
} else if (type == C.TRACK_TYPE_AUDIO) { } else if (type == C.TRACK_TYPE_AUDIO) {
sampleMimeType = sampleMimeType == null ? MimeTypes.AUDIO_AAC : sampleMimeType; sampleMimeType = sampleMimeType == null ? MimeTypes.AUDIO_AAC : sampleMimeType;
int channels = parseRequiredInt(parser, KEY_CHANNELS); int channels = parseRequiredInt(parser, KEY_CHANNELS);
@ -644,8 +644,8 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
format = Format.createTextContainerFormat(id, MimeTypes.APPLICATION_MP4, sampleMimeType, format = Format.createTextContainerFormat(id, MimeTypes.APPLICATION_MP4, sampleMimeType,
null, bitrate, 0, language); null, bitrate, 0, language);
} else { } else {
format = Format.createContainerFormat(id, MimeTypes.APPLICATION_MP4, null, sampleMimeType, format = Format.createContainerFormat(id, MimeTypes.APPLICATION_MP4, sampleMimeType, null,
bitrate); bitrate, 0, null);
} }
} }