From 7f967f305718bc2c9ee679fdd7d014eccef0356b Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 17 Jan 2017 04:06:14 -0800 Subject: [PATCH] DASH: Parse Role elements to select default audio/text tracks Issue: #2058 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=144693705 --- .../dash/manifest/RepresentationTest.java | 4 +- .../com/google/android/exoplayer2/Format.java | 18 +++--- .../dash/manifest/DashManifestParser.java | 57 ++++++++++++------- .../hls/playlist/HlsMasterPlaylist.java | 2 +- .../hls/playlist/HlsPlaylistParser.java | 2 +- .../manifest/SsManifestParser.java | 6 +- 6 files changed, 54 insertions(+), 35 deletions(-) diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/RepresentationTest.java b/library/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/RepresentationTest.java index 008cd0e556..5d10aba1ae 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/RepresentationTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/RepresentationTest.java @@ -29,13 +29,13 @@ public class RepresentationTest extends TestCase { String uri = "http://www.google.com"; SegmentBase base = new SingleSegmentBase(new RangedUri(null, 0, 1), 1, 0, 1, 1); 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, base); assertEquals("test_stream_1.0.3", representation.getCacheKey()); 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, format, uri, base); assertEquals("test_stream_1.150.-1", representation.getCacheKey()); diff --git a/library/src/main/java/com/google/android/exoplayer2/Format.java b/library/src/main/java/com/google/android/exoplayer2/Format.java index 6b8fb1d41e..f3b058621a 100644 --- a/library/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/src/main/java/com/google/android/exoplayer2/Format.java @@ -192,11 +192,11 @@ public final class Format implements Parcelable { public static Format createVideoContainerFormat(String id, String containerMimeType, String sampleMimeType, String codecs, int bitrate, int width, int height, - float frameRate, List initializationData) { + float frameRate, List initializationData, @C.SelectionFlags int selectionFlags) { 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, - NO_VALUE, NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, null, - null); + NO_VALUE, NO_VALUE, selectionFlags, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, + initializationData, null, null); } 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, - int bitrate, @C.SelectionFlags int selectionFlags, String language, - int accessibilityChannel, DrmInitData drmInitData) { + int bitrate, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel, + DrmInitData drmInitData) { return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE); } @@ -323,11 +323,13 @@ public final class Format implements Parcelable { // Generic. - public static Format createContainerFormat(String id, String containerMimeType, String codecs, - String sampleMimeType, int bitrate) { + public static Format createContainerFormat(String id, String containerMimeType, + String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags, + String language) { 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, 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, diff --git a/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index 51a7531b10..688d68e893 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -243,6 +243,7 @@ public class DashManifestParser extends DefaultHandler List representationInfos = new ArrayList<>(); List adaptationSetInbandEventStreams = new ArrayList<>(); List commonRepresentationInbandEventStreams = null; + @C.SelectionFlags int selectionFlags = 0; boolean seenFirstBaseUrl = false; do { @@ -260,10 +261,16 @@ public class DashManifestParser extends DefaultHandler } else if (XmlPullParserUtil.isStartTag(xpp, "ContentComponent")) { language = checkLanguageConsistency(language, xpp.getAttributeValue(null, "lang")); 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")) { RepresentationInfo representationInfo = parseRepresentation(xpp, baseUrl, mimeType, codecs, width, height, frameRate, audioChannels, audioSamplingRate, language, - accessibilityChannel, segmentBase); + accessibilityChannel, selectionFlags, segmentBase); contentType = checkContentTypeConsistency(contentType, getContentType(representationInfo.format)); 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")) { segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase); } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) { @@ -402,6 +405,24 @@ public class DashManifestParser extends DefaultHandler 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. * @@ -420,8 +441,8 @@ public class DashManifestParser extends DefaultHandler String adaptationSetMimeType, String adaptationSetCodecs, int adaptationSetWidth, int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels, int adaptationSetAudioSamplingRate, String adaptationSetLanguage, - int adaptationSetAccessibilityChannel, SegmentBase segmentBase) - throws XmlPullParserException, IOException { + int adaptationSetAccessibilityChannel, @C.SelectionFlags int adaptationSetSelectionFlags, + SegmentBase segmentBase) throws XmlPullParserException, IOException { String id = xpp.getAttributeValue(null, "id"); 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, audioSamplingRate, bandwidth, adaptationSetLanguage, adaptationSetAccessibilityChannel, - codecs); + adaptationSetSelectionFlags, codecs); segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase(); 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, 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); if (sampleMimeType != null) { if (MimeTypes.isVideo(sampleMimeType)) { return Format.createVideoContainerFormat(id, containerMimeType, sampleMimeType, codecs, - bitrate, width, height, frameRate, null); + bitrate, width, height, frameRate, null, selectionFlags); } else if (MimeTypes.isAudio(sampleMimeType)) { return Format.createAudioContainerFormat(id, containerMimeType, sampleMimeType, codecs, - bitrate, audioChannels, audioSamplingRate, null, 0, language); - } else if (mimeTypeIsRawText(sampleMimeType)) { + bitrate, audioChannels, audioSamplingRate, null, selectionFlags, language); + } else if (mimeTypeIsRawText(sampleMimeType) + || MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) { return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs, - bitrate, 0, 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); + bitrate, selectionFlags, language, accessiblityChannel); } - } else { - return Format.createContainerFormat(id, containerMimeType, codecs, sampleMimeType, bitrate); } + return Format.createContainerFormat(id, containerMimeType, sampleMimeType, codecs, bitrate, + selectionFlags, language); } protected Representation buildRepresentation(RepresentationInfo representationInfo, diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java index 4aaec59f7d..b7426fd03d 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java @@ -40,7 +40,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { public static HlsUrl createMediaPlaylistHlsUrl(String baseUri) { 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); } diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 7a52c4d0b5..c349bbee05 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -240,7 +240,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser { List codecSpecificData = buildCodecSpecificData( parser.getAttributeValue(null, KEY_CODEC_PRIVATE_DATA)); 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) { sampleMimeType = sampleMimeType == null ? MimeTypes.AUDIO_AAC : sampleMimeType; int channels = parseRequiredInt(parser, KEY_CHANNELS); @@ -644,8 +644,8 @@ public class SsManifestParser implements ParsingLoadable.Parser { format = Format.createTextContainerFormat(id, MimeTypes.APPLICATION_MP4, sampleMimeType, null, bitrate, 0, language); } else { - format = Format.createContainerFormat(id, MimeTypes.APPLICATION_MP4, null, sampleMimeType, - bitrate); + format = Format.createContainerFormat(id, MimeTypes.APPLICATION_MP4, sampleMimeType, null, + bitrate, 0, null); } }