// --- ======== 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();
            }
        }