// --- ======== static builder ========= --- /// <summary> /// Parses the input arrays as a DecoderSpecificInfo, as used in MP4 containers. /// </summary> /// <param name="data"></param> /// <returns>a DecoderConfig</returns> public static DecoderConfig parseMP4DecoderSpecificInfo(byte[] data) { var inStream = new BitStream(data); var config = new DecoderConfig(); try { config.profile = readProfile(inStream); int sf = inStream.readBits(4); config.sampleFrequency = sf == 0xf ? SampleFrequency.forFrequency(inStream.readBits(24)) : SampleFrequency.forInt(sf); config.channelConfiguration = (ChannelConfiguration)inStream.readBits(4); switch (config.profile.type) { case Profile.ProfileType.AAC_SBR: { config.extProfile = config.profile; config.sbrPresent = true; sf = inStream.readBits(4); // TODO: 24 bits already read; read again? //if(sf==0xF) config.sampleFrequency = SampleFrequency.forFrequency(inStream.readBits(24)); // if sample frequencies are the same: downsample SBR config.downSampledSBR = config.sampleFrequency.getIndex() == sf; config.sampleFrequency = SampleFrequency.forInt(sf); config.profile = readProfile(inStream); } break; case Profile.ProfileType.AAC_MAIN: case Profile.ProfileType.AAC_LC: case Profile.ProfileType.AAC_SSR: case Profile.ProfileType.AAC_LTP: case Profile.ProfileType.ER_AAC_LC: case Profile.ProfileType.ER_AAC_LTP: case Profile.ProfileType.ER_AAC_LD: { // ga-specific info: config.frameLengthFlag = inStream.readBool(); if (config.frameLengthFlag) { throw new AACException("config uses 960-sample frames, not yet supported"); //TODO: are 960-frames working yet? } config.dependsOnCoreCoder = inStream.readBool(); config.coreCoderDelay = config.dependsOnCoreCoder ? inStream.readBits(14) : 0; config.extensionFlag = inStream.readBool(); if (config.extensionFlag) { if (config.profile.isErrorResilientProfile()) { config.sectionDataResilience = inStream.readBool(); config.scalefactorResilience = inStream.readBool(); config.spectralDataResilience = inStream.readBool(); } // extensionFlag3 inStream.skipBit(); } if (config.channelConfiguration == ChannelConfiguration.CHANNEL_CONFIG_NONE || !config.channelConfiguration.ToString().StartsWith("CHANNEL_", StringComparison.Ordinal)) { // TODO: is this working correct? -> ISO 14496-3 part 1: 1.A.4.3 inStream.skipBits(3); //PCE throw new NotImplementedException(); //PCE pce = new PCE(); //pce.decode(inStream); //config.profile = pce.getProfile(); //config.sampleFrequency = pce.getSampleFrequency(); //config.channelConfiguration = ChannelConfiguration.forInt(pce.getChannelCount()); } if (inStream.getBitsLeft() > 10) { readSyncExtension(inStream, config); } } break; default: throw new AACException("profile not supported: " + config.profile.type); } return(config); } finally { inStream.destroy(); } }