mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Merge pull request #3161 from DolbyLaboratories/dev-v2-eac3-7.1
Support 7.1 EAC3 in MP4, DASH and HLS formats
This commit is contained in:
commit
2e950633c7
2 changed files with 66 additions and 7 deletions
|
|
@ -38,6 +38,10 @@ public final class Ac3Util {
|
||||||
* {@link MimeTypes#AUDIO_E_AC3}.
|
* {@link MimeTypes#AUDIO_E_AC3}.
|
||||||
*/
|
*/
|
||||||
public final String mimeType;
|
public final String mimeType;
|
||||||
|
/**
|
||||||
|
* The type of the bitstream, only for AUDIO_E_AC3
|
||||||
|
*/
|
||||||
|
public final int streamType;
|
||||||
/**
|
/**
|
||||||
* The audio sampling rate in Hz.
|
* The audio sampling rate in Hz.
|
||||||
*/
|
*/
|
||||||
|
|
@ -55,9 +59,10 @@ public final class Ac3Util {
|
||||||
*/
|
*/
|
||||||
public final int sampleCount;
|
public final int sampleCount;
|
||||||
|
|
||||||
private Ac3SyncFrameInfo(String mimeType, int channelCount, int sampleRate, int frameSize,
|
private Ac3SyncFrameInfo(String mimeType, int streamType, int channelCount, int sampleRate,
|
||||||
int sampleCount) {
|
int frameSize, int sampleCount) {
|
||||||
this.mimeType = mimeType;
|
this.mimeType = mimeType;
|
||||||
|
this.streamType = streamType;
|
||||||
this.channelCount = channelCount;
|
this.channelCount = channelCount;
|
||||||
this.sampleRate = sampleRate;
|
this.sampleRate = sampleRate;
|
||||||
this.frameSize = frameSize;
|
this.frameSize = frameSize;
|
||||||
|
|
@ -101,6 +106,13 @@ public final class Ac3Util {
|
||||||
private static final int[] SYNCFRAME_SIZE_WORDS_BY_HALF_FRMSIZECOD_44_1 = new int[] {69, 87, 104,
|
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};
|
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
|
* 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.
|
* ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified.
|
||||||
|
|
@ -138,8 +150,8 @@ public final class Ac3Util {
|
||||||
String language, DrmInitData drmInitData) {
|
String language, DrmInitData drmInitData) {
|
||||||
data.skipBytes(2); // data_rate, num_ind_sub
|
data.skipBytes(2); // data_rate, num_ind_sub
|
||||||
|
|
||||||
// Read only the first substream.
|
// Read only the first independent substream.
|
||||||
// TODO: Read later substreams?
|
// TODO: Read later independent substreams?
|
||||||
int fscod = (data.readUnsignedByte() & 0xC0) >> 6;
|
int fscod = (data.readUnsignedByte() & 0xC0) >> 6;
|
||||||
int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod];
|
int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod];
|
||||||
int nextByte = data.readUnsignedByte();
|
int nextByte = data.readUnsignedByte();
|
||||||
|
|
@ -147,6 +159,19 @@ public final class Ac3Util {
|
||||||
if ((nextByte & 0x01) != 0) { // lfeon
|
if ((nextByte & 0x01) != 0) { // lfeon
|
||||||
channelCount++;
|
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,
|
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, null, Format.NO_VALUE,
|
||||||
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language);
|
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language);
|
||||||
}
|
}
|
||||||
|
|
@ -164,13 +189,16 @@ public final class Ac3Util {
|
||||||
boolean isEac3 = data.readBits(5) == 16;
|
boolean isEac3 = data.readBits(5) == 16;
|
||||||
data.setPosition(initialPosition);
|
data.setPosition(initialPosition);
|
||||||
String mimeType;
|
String mimeType;
|
||||||
|
int streamType;
|
||||||
int sampleRate;
|
int sampleRate;
|
||||||
int acmod;
|
int acmod;
|
||||||
int frameSize;
|
int frameSize;
|
||||||
int sampleCount;
|
int sampleCount;
|
||||||
if (isEac3) {
|
if (isEac3) {
|
||||||
mimeType = MimeTypes.AUDIO_E_AC3;
|
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;
|
frameSize = (data.readBits(11) + 1) * 2;
|
||||||
int fscod = data.readBits(2);
|
int fscod = data.readBits(2);
|
||||||
int audioBlocks;
|
int audioBlocks;
|
||||||
|
|
@ -187,6 +215,7 @@ public final class Ac3Util {
|
||||||
} else /* is AC-3 */ {
|
} else /* is AC-3 */ {
|
||||||
mimeType = MimeTypes.AUDIO_AC3;
|
mimeType = MimeTypes.AUDIO_AC3;
|
||||||
data.skipBits(16 + 16); // syncword, crc1
|
data.skipBits(16 + 16); // syncword, crc1
|
||||||
|
streamType = STREAM_TYPE_UNDEFINED; // AC-3 stream hasn't streamType
|
||||||
int fscod = data.readBits(2);
|
int fscod = data.readBits(2);
|
||||||
int frmsizecod = data.readBits(6);
|
int frmsizecod = data.readBits(6);
|
||||||
frameSize = getAc3SyncframeSize(fscod, frmsizecod);
|
frameSize = getAc3SyncframeSize(fscod, frmsizecod);
|
||||||
|
|
@ -206,7 +235,8 @@ public final class Ac3Util {
|
||||||
}
|
}
|
||||||
boolean lfeon = data.readBit();
|
boolean lfeon = data.readBit();
|
||||||
int channelCount = CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -690,7 +690,9 @@ public class DashManifestParser extends DefaultHandler
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
String schemeIdUri = parseString(xpp, "schemeIdUri", null);
|
String schemeIdUri = parseString(xpp, "schemeIdUri", null);
|
||||||
int audioChannels = "urn:mpeg:dash:23003:3:audio_channel_configuration:2011".equals(schemeIdUri)
|
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 {
|
do {
|
||||||
xpp.next();
|
xpp.next();
|
||||||
} while (!XmlPullParserUtil.isEndTag(xpp, "AudioChannelConfiguration"));
|
} while (!XmlPullParserUtil.isEndTag(xpp, "AudioChannelConfiguration"));
|
||||||
|
|
@ -901,6 +903,33 @@ public class DashManifestParser extends DefaultHandler
|
||||||
return value == null ? defaultValue : value;
|
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 {
|
private static final class RepresentationInfo {
|
||||||
|
|
||||||
public final Format format;
|
public final Format format;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue