diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/Ac3Util.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/Ac3Util.java index 4b64ffb030d..bc46a4f10a8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/Ac3Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/Ac3Util.java @@ -38,6 +38,10 @@ public static final class Ac3SyncFrameInfo { * {@link MimeTypes#AUDIO_E_AC3}. */ public final String mimeType; + /** + * The type of the bitstream, only for AUDIO_E_AC3 + */ + public final int streamType; /** * The audio sampling rate in Hz. */ @@ -55,9 +59,10 @@ public static final class Ac3SyncFrameInfo { */ public final int sampleCount; - private Ac3SyncFrameInfo(String mimeType, int channelCount, int sampleRate, int frameSize, - int sampleCount) { + private Ac3SyncFrameInfo(String mimeType, int streamType, int channelCount, int sampleRate, + int frameSize, int sampleCount) { this.mimeType = mimeType; + this.streamType = streamType; this.channelCount = channelCount; this.sampleRate = sampleRate; this.frameSize = frameSize; @@ -101,6 +106,13 @@ private Ac3SyncFrameInfo(String mimeType, int channelCount, int sampleRate, int private static final int[] SYNCFRAME_SIZE_WORDS_BY_HALF_FRMSIZECOD_44_1 = new int[] {69, 87, 104, 121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114, 1253, 1393}; + /** + * Stream type. See ETSI TS 102 366 E.1.3.1.1. + */ + public static final int STREAM_TYPE_UNDEFINED = -1; + public static final int STREAM_TYPE_TYPE0 = 0; + public static final int STREAM_TYPE_TYPE1 = 1; + /** * Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to * ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified. @@ -138,8 +150,8 @@ public static Format parseEAc3AnnexFFormat(ParsableByteArray data, String trackI String language, DrmInitData drmInitData) { data.skipBytes(2); // data_rate, num_ind_sub - // Read only the first substream. - // TODO: Read later substreams? + // Read only the first independent substream. + // TODO: Read later independent substreams? int fscod = (data.readUnsignedByte() & 0xC0) >> 6; int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod]; int nextByte = data.readUnsignedByte(); @@ -147,6 +159,19 @@ public static Format parseEAc3AnnexFFormat(ParsableByteArray data, String trackI if ((nextByte & 0x01) != 0) { // lfeon channelCount++; } + + // Read only the first dependent substream. + // TODO: Read later dependent substreams? + nextByte = data.readUnsignedByte(); + int numDepSub = ((nextByte & 0x1E) >> 1); + if (numDepSub > 0) { + int lowByteChanLoc = data.readUnsignedByte(); + // Read Lrs/Rrs pair + // TODO: Read other channel configuration + if ((lowByteChanLoc & 0x02) != 0) { + channelCount += 2; + } + } return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, null, Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language); } @@ -164,13 +189,16 @@ public static Ac3SyncFrameInfo parseAc3SyncframeInfo(ParsableBitArray data) { boolean isEac3 = data.readBits(5) == 16; data.setPosition(initialPosition); String mimeType; + int streamType; int sampleRate; int acmod; int frameSize; int sampleCount; if (isEac3) { mimeType = MimeTypes.AUDIO_E_AC3; - data.skipBits(16 + 2 + 3); // syncword, strmtype, substreamid + data.skipBits(16); // syncword + streamType = data.readBits(2); + data.skipBits(3); // substreamid frameSize = (data.readBits(11) + 1) * 2; int fscod = data.readBits(2); int audioBlocks; @@ -187,6 +215,7 @@ public static Ac3SyncFrameInfo parseAc3SyncframeInfo(ParsableBitArray data) { } else /* is AC-3 */ { mimeType = MimeTypes.AUDIO_AC3; data.skipBits(16 + 16); // syncword, crc1 + streamType = STREAM_TYPE_UNDEFINED; // AC-3 stream hasn't streamType int fscod = data.readBits(2); int frmsizecod = data.readBits(6); frameSize = getAc3SyncframeSize(fscod, frmsizecod); @@ -206,7 +235,8 @@ public static Ac3SyncFrameInfo parseAc3SyncframeInfo(ParsableBitArray data) { } boolean lfeon = data.readBit(); int channelCount = CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0); - return new Ac3SyncFrameInfo(mimeType, channelCount, sampleRate, frameSize, sampleCount); + return new Ac3SyncFrameInfo(mimeType, streamType, channelCount, sampleRate, + frameSize, sampleCount); } /** 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 53115a7a0ed..a34d248006d 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 @@ -690,7 +690,9 @@ protected int parseAudioChannelConfiguration(XmlPullParser xpp) throws XmlPullParserException, IOException { String schemeIdUri = parseString(xpp, "schemeIdUri", null); int audioChannels = "urn:mpeg:dash:23003:3:audio_channel_configuration:2011".equals(schemeIdUri) - ? parseInt(xpp, "value", Format.NO_VALUE) : Format.NO_VALUE; + ? parseInt(xpp, "value", Format.NO_VALUE) : + ("tag:dolby.com,2014:dash:audio_channel_configuration:2011".equals(schemeIdUri) + ? parseDolbyChannelConfiguration(xpp, "value", Format.NO_VALUE) : Format.NO_VALUE); do { xpp.next(); } while (!XmlPullParserUtil.isEndTag(xpp, "AudioChannelConfiguration")); @@ -901,6 +903,33 @@ protected static String parseString(XmlPullParser xpp, String name, String defau return value == null ? defaultValue : value; } + protected static int parseDolbyChannelConfiguration(XmlPullParser xpp, String name, + int defaultValue) { + String value = Util.toLowerInvariant(xpp.getAttributeValue(null, name)); + if (value == null) { + return defaultValue; + } + int channels; + // TODO: Parse other channel configurations + switch (value) { + case "4000": + channels = 1; + break; + case "a000": + channels = 2; + break; + case "f801": + channels = 6; + break; + case "fa01": + channels = 8; + break; + default: + channels = defaultValue; + } + return channels; + } + private static final class RepresentationInfo { public final Format format;