From 58d746ecaa811d29f9bb52b1e4e232b3bc92ed07 Mon Sep 17 00:00:00 2001 From: Arnold Szabo Date: Sun, 3 Mar 2019 20:26:31 +0200 Subject: [PATCH] Add IntDef for role and accessibility descriptor's value, parse these also for video / audio tracks --- .../java/com/google/android/exoplayer2/C.java | 48 ++++++++ .../com/google/android/exoplayer2/Format.java | 109 +++++++++-------- .../dash/manifest/DashManifestParser.java | 114 ++++++++++++------ .../exoplayer2/source/hls/HlsMediaPeriod.java | 8 +- .../hls/playlist/HlsPlaylistParser.java | 12 +- .../manifest/SsManifestParser.java | 8 +- 6 files changed, 206 insertions(+), 93 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index 2eed9f03a9..19545fe0c3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -976,6 +976,54 @@ public final class C { */ public static final int NETWORK_TYPE_OTHER = 8; + /** + * Adaptation set's role descriptor value (ISO 23009-1) + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ROLE_UNSET, + ROLE_MAIN, + ROLE_ALTERNATE, + ROLE_SUPPLEMENTARY, + ROLE_COMMENTARY, + ROLE_DUB, + ROLE_EMERGENCY, + ROLE_CAPTION, + ROLE_SIGN + }) + public @interface Role {} + + public static final int ROLE_UNSET = -1; + public static final int ROLE_MAIN = 0; + public static final int ROLE_ALTERNATE = 1; + public static final int ROLE_SUPPLEMENTARY = 2; + public static final int ROLE_COMMENTARY = 3; + public static final int ROLE_DUB = 4; + public static final int ROLE_EMERGENCY = 5; + public static final int ROLE_CAPTION = 6; + public static final int ROLE_SIGN = 7; + + /** + * Adaptation set's accessibility descriptor value (ISO 23009-1) + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ACCESSIBILITY_UNSET, + ACCESSIBILITY_ENHANCED_AUDIO_INTELLIGIBILITY, + ACCESSIBILITY_DESCRIPTION, + ACCESSIBILITY_CAPTION, + ACCESSIBILITY_SIGN + }) + public @interface Accessibility {} + + public static final int ACCESSIBILITY_UNSET = -1; + public static final int ACCESSIBILITY_ENHANCED_AUDIO_INTELLIGIBILITY = 1; + public static final int ACCESSIBILITY_DESCRIPTION = 2; + public static final int ACCESSIBILITY_CAPTION = 3; + public static final int ACCESSIBILITY_SIGN = 4; + /** * Converts a time in microseconds to the corresponding time in milliseconds, preserving * {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Format.java b/library/core/src/main/java/com/google/android/exoplayer2/Format.java index 3ed5a99f23..43ca19e444 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Format.java @@ -48,7 +48,18 @@ public final class Format implements Parcelable { public final @Nullable String id; /** The human readable label, or null if unknown or not applicable. */ public final @Nullable String label; - + /** Track selection flags. **/ + @C.SelectionFlags + public final int selectionFlags; + /** Track role descriptor value, or {@link C#ROLE_UNSET} if unknown or not applicable. **/ + @C.Role + public final int role; + /** + * Track accessibility descriptor value, or {@link C#ACCESSIBILITY_UNSET} if unknown + * or not applicable. + */ + @C.Accessibility + public final int accessibility; /** * The average bandwidth in bits per second, or {@link #NO_VALUE} if unknown or not applicable. */ @@ -153,12 +164,6 @@ public final class Format implements Parcelable { // Audio and text specific. - /** - * Track selection flags. - */ - @C.SelectionFlags - public final int selectionFlags; - /** The language as ISO 639-2/T three-letter code, or null if unknown or not applicable. */ public final @Nullable String language; @@ -167,16 +172,6 @@ public final class Format implements Parcelable { */ public final int accessibilityChannel; - /** - * The Role descriptor value. - */ - public final String role; - - /** - * The Accessibility descriptor value. - */ - public final String accessibility; - // Lazily initialized hashcode. private int hashCode; @@ -193,7 +188,9 @@ public final class Format implements Parcelable { int height, float frameRate, @Nullable List initializationData, - @C.SelectionFlags int selectionFlags) { + @C.SelectionFlags int selectionFlags, + @C.Role int role, + @C.Accessibility int accessibility) { return createVideoContainerFormat( id, /* label= */ null, @@ -205,7 +202,9 @@ public final class Format implements Parcelable { height, frameRate, initializationData, - selectionFlags); + selectionFlags, + role, + accessibility); } public static Format createVideoContainerFormat( @@ -219,7 +218,9 @@ public final class Format implements Parcelable { int height, float frameRate, @Nullable List initializationData, - @C.SelectionFlags int selectionFlags) { + @C.SelectionFlags int selectionFlags, + @C.Role int role, + @C.Accessibility int accessibility) { return new Format( id, label, @@ -244,8 +245,8 @@ public final class Format implements Parcelable { selectionFlags, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + role, + accessibility, OFFSET_SAMPLE_RELATIVE, initializationData, /* drmInitData= */ null, @@ -349,8 +350,8 @@ public final class Format implements Parcelable { /* selectionFlags= */ 0, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, @@ -370,7 +371,9 @@ public final class Format implements Parcelable { int sampleRate, @Nullable List initializationData, @C.SelectionFlags int selectionFlags, - @Nullable String language) { + @Nullable String language, + @C.Role int role, + @C.Accessibility int accessibility) { return createAudioContainerFormat( id, /* label= */ null, @@ -382,7 +385,9 @@ public final class Format implements Parcelable { sampleRate, initializationData, selectionFlags, - language); + language, + role, + accessibility); } public static Format createAudioContainerFormat( @@ -396,7 +401,9 @@ public final class Format implements Parcelable { int sampleRate, @Nullable List initializationData, @C.SelectionFlags int selectionFlags, - @Nullable String language) { + @Nullable String language, + @C.Role int role, + @C.Accessibility int accessibility) { return new Format( id, label, @@ -421,8 +428,8 @@ public final class Format implements Parcelable { selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + role, + accessibility, OFFSET_SAMPLE_RELATIVE, initializationData, /* drmInitData= */ null, @@ -527,8 +534,8 @@ public final class Format implements Parcelable { selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, @@ -576,8 +583,8 @@ public final class Format implements Parcelable { selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null); + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET); } public static Format createTextContainerFormat( @@ -590,8 +597,8 @@ public final class Format implements Parcelable { @C.SelectionFlags int selectionFlags, @Nullable String language, int accessibilityChannel, - @Nullable String role, - @Nullable String accessibility) { + @C.Role int role, + @C.Accessibility int accessibility) { return new Format( id, label, @@ -730,8 +737,8 @@ public final class Format implements Parcelable { selectionFlags, language, accessibilityChannel, - /* role= */ null, - /* accessibility= */ null, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET, subsampleOffsetUs, initializationData, drmInitData, @@ -773,8 +780,8 @@ public final class Format implements Parcelable { selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, @@ -836,8 +843,8 @@ public final class Format implements Parcelable { selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET, OFFSET_SAMPLE_RELATIVE, /* initializationData= */ null, /* drmInitData= */ null, @@ -870,8 +877,8 @@ public final class Format implements Parcelable { /* selectionFlags= */ 0, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET, subsampleOffsetUs, /* initializationData= */ null, /* drmInitData= */ null, @@ -908,8 +915,8 @@ public final class Format implements Parcelable { /* selectionFlags= */ 0, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, - /* role= */ null, - /* accessibility= */ null, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET, OFFSET_SAMPLE_RELATIVE, /* initializationData= */ null, drmInitData, @@ -940,8 +947,8 @@ public final class Format implements Parcelable { @C.SelectionFlags int selectionFlags, @Nullable String language, int accessibilityChannel, - @Nullable String role, - @Nullable String accessibility, + @C.Role int role, + @C.Accessibility int accessibility, long subsampleOffsetUs, @Nullable List initializationData, @Nullable DrmInitData drmInitData, @@ -1005,8 +1012,8 @@ public final class Format implements Parcelable { selectionFlags = in.readInt(); language = in.readString(); accessibilityChannel = in.readInt(); - role = in.readString(); - accessibility = in.readString(); + role = in.readInt(); + accessibility = in.readInt(); subsampleOffsetUs = in.readLong(); int initializationDataSize = in.readInt(); initializationData = new ArrayList<>(initializationDataSize); @@ -1602,8 +1609,8 @@ public final class Format implements Parcelable { dest.writeInt(selectionFlags); dest.writeString(language); dest.writeInt(accessibilityChannel); - dest.writeString(role); - dest.writeString(accessibility); + dest.writeInt(role); + dest.writeInt(accessibility); dest.writeLong(subsampleOffsetUs); int initializationDataSize = initializationData.size(); dest.writeInt(initializationDataSize); diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index d7f02926cd..462ebc6300 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -302,8 +302,7 @@ public class DashManifestParser extends DefaultHandler contentType = checkContentTypeConsistency(contentType, parseContentType(xpp)); } else if (XmlPullParserUtil.isStartTag(xpp, "Role")) { Descriptor descriptor = parseDescriptor(xpp, "Role"); - selectionFlags |= "urn:mpeg:dash:role:2011".equals(descriptor.schemeIdUri) - && "main".equals(descriptor.value) ? C.SELECTION_FLAG_DEFAULT : 0; + selectionFlags |= parseSelectionFlags(descriptor); roleDescriptors.add(descriptor); } else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) { audioChannels = parseAudioChannelConfiguration(xpp); @@ -589,6 +588,8 @@ public class DashManifestParser extends DefaultHandler List supplementalProperties) { String sampleMimeType = getSampleMimeType(containerMimeType, codecs); if (sampleMimeType != null) { + int role = parseRole(roleDescriptors); + int accessibility = parseAccessibility(accessibilityDescriptors); if (MimeTypes.AUDIO_E_AC3.equals(sampleMimeType)) { sampleMimeType = parseEac3SupplementalProperties(supplementalProperties); } @@ -604,7 +605,9 @@ public class DashManifestParser extends DefaultHandler height, frameRate, /* initializationData= */ null, - selectionFlags); + selectionFlags, + role, + accessibility); } else if (MimeTypes.isAudio(sampleMimeType)) { return Format.createAudioContainerFormat( id, @@ -617,7 +620,9 @@ public class DashManifestParser extends DefaultHandler audioSamplingRate, /* initializationData= */ null, selectionFlags, - language); + language, + role, + accessibility); } else if (mimeTypeIsRawText(sampleMimeType)) { int accessibilityChannel; if (MimeTypes.APPLICATION_CEA608.equals(sampleMimeType)) { @@ -627,10 +632,6 @@ public class DashManifestParser extends DefaultHandler } else { accessibilityChannel = Format.NO_VALUE; } - - String role = parseRole(roleDescriptors); - String accessibility = parseAccessibility(accessibilityDescriptors); - return Format.createTextContainerFormat( id, label, @@ -1060,6 +1061,77 @@ public class DashManifestParser extends DefaultHandler return audioChannels; } + // Selection flag parsing. + + protected int parseSelectionFlags(Descriptor roleDescriptor) { + return "urn:mpeg:dash:role:2011".equals(roleDescriptor.schemeIdUri) + && "main".equals(roleDescriptor.value) ? C.SELECTION_FLAG_DEFAULT : 0; + } + + // Role and Accessibility parsing. + + protected @C.Role int parseRole(List roleDescriptors) { + for (int i = 0; i < roleDescriptors.size(); i++) { + Descriptor descriptor = roleDescriptors.get(i); + if ("urn:mpeg:dash:role:2011".equalsIgnoreCase(descriptor.schemeIdUri) && descriptor.value != null) { + switch (descriptor.value) { + case "main": + return C.ROLE_MAIN; + case "alternate": + return C.ROLE_ALTERNATE; + case "supplementary": + return C.ROLE_SUPPLEMENTARY; + case "commentary": + return C.ROLE_COMMENTARY; + case "dub": + return C.ROLE_DUB; + case "emergency": + return C.ROLE_EMERGENCY; + case "caption": + return C.ROLE_CAPTION; + case "sign": + return C.ROLE_SIGN; + default: + return C.ROLE_UNSET; + } + } + } + return C.ROLE_UNSET; + } + + protected @C.Accessibility int parseAccessibility(List accessibilityDescriptors) { + for (int i = 0; i < accessibilityDescriptors.size(); i++) { + Descriptor descriptor = accessibilityDescriptors.get(i); + if ("urn:mpeg:dash:role:2011".equalsIgnoreCase(descriptor.schemeIdUri) && descriptor.value != null) { + switch (descriptor.value){ + case "description": + return C.ACCESSIBILITY_DESCRIPTION; + case "enhanced-audio-intelligibility": + return C.ACCESSIBILITY_ENHANCED_AUDIO_INTELLIGIBILITY; + case "caption": + return C.ACCESSIBILITY_CAPTION; + case "sign": + return C.ACCESSIBILITY_SIGN; + default: + return C.ACCESSIBILITY_UNSET; + } + } + + if ("urn:tva:metadata:cs:AudioPurposeCS:2007".equalsIgnoreCase(descriptor.schemeIdUri) && + descriptor.value != null) { + switch (descriptor.value){ + case "1": + return C.ACCESSIBILITY_ENHANCED_AUDIO_INTELLIGIBILITY; + case "2": + return C.ACCESSIBILITY_CAPTION; + default: + return C.ACCESSIBILITY_UNSET; + } + } + } + return C.ACCESSIBILITY_UNSET; + } + // Utility methods. /** @@ -1262,32 +1334,6 @@ public class DashManifestParser extends DefaultHandler return MimeTypes.AUDIO_E_AC3; } - protected static String parseRole(List roleDescriptors) { - for (int i = 0; i < roleDescriptors.size(); i++) { - Descriptor descriptor = roleDescriptors.get(i); - if ("urn:mpeg:dash:role:2011".equals(descriptor.schemeIdUri) && descriptor.value != null) { - return descriptor.value; - } - } - return null; - } - - protected static String parseAccessibility(List accessibilityDescriptors) { - for (int i = 0; i < accessibilityDescriptors.size(); i++) { - Descriptor descriptor = accessibilityDescriptors.get(i); - if ("urn:mpeg:dash:role:2011".equals(descriptor.schemeIdUri) && descriptor.value != null) { - return descriptor.value; - } - - if ("urn:tva:metadata:cs:AudioPurposeCS:2007".equals(descriptor.schemeIdUri)) { - if ("1".equals(descriptor.value) || "2".equals(descriptor.value)) { - return descriptor.value; - } - } - } - return null; - } - protected static float parseFrameRate(XmlPullParser xpp, float defaultValue) { float frameRate = defaultValue; String frameRateAttribute = xpp.getAttributeValue(null, "frameRate"); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 1c3e2f141d..61244f9a45 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -702,7 +702,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper variantFormat.height, variantFormat.frameRate, /* initializationData= */ null, - variantFormat.selectionFlags); + variantFormat.selectionFlags, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET); } private static Format deriveAudioFormat( @@ -740,7 +742,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper /* sampleRate= */ Format.NO_VALUE, /* initializationData= */ null, selectionFlags, - language); + language, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index e9fd1fb803..7e273fbd3f 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -329,7 +329,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser { height, /* frameRate= */ Format.NO_VALUE, codecSpecificData, - /* selectionFlags= */ 0); + /* selectionFlags= */ 0, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET); } else if (type == C.TRACK_TYPE_AUDIO) { sampleMimeType = sampleMimeType == null ? MimeTypes.AUDIO_AAC : sampleMimeType; int channels = parseRequiredInt(parser, KEY_CHANNELS); @@ -705,7 +707,9 @@ public class SsManifestParser implements ParsingLoadable.Parser { samplingRate, codecSpecificData, /* selectionFlags= */ 0, - language); + language, + /* role= */ C.ROLE_UNSET, + /* accessibility= */ C.ACCESSIBILITY_UNSET); } else if (type == C.TRACK_TYPE_TEXT) { String language = (String) getNormalizedAttribute(KEY_LANGUAGE); format =