public void WriteChunk(byte[] chunk, uint timeStamp)
        {
            if (chunk.Length < 1)
            {
                return;
            }

            if (chunk[0] == 0)
            {
                // Header
                if (chunk.Length < 3)
                {
                    return;
                }

                ulong bits = (ulong)BigEndianBitConverter.ToUInt16(chunk, 1) << 48;

                aacProfile      = BitHelper.Read(ref bits, 5) - 1;
                sampleRateIndex = BitHelper.Read(ref bits, 4);
                channelConfig   = BitHelper.Read(ref bits, 4);

                if (aacProfile < 0 || aacProfile > 3)
                {
                    throw new AudioExtractionException("Unsupported AAC profile.");
                }
                if (sampleRateIndex > 12)
                {
                    throw new AudioExtractionException("Invalid AAC sample rate index.");
                }
                if (channelConfig > 6)
                {
                    throw new AudioExtractionException("Invalid AAC channel configuration.");
                }
            }

            else
            {
                // Audio data
                int   dataSize = chunk.Length - 1;
                ulong bits     = 0;

                // Reference: WriteADTSHeader from FAAC's bitstream.c

                BitHelper.Write(ref bits, 12, 0xFFF);
                BitHelper.Write(ref bits, 1, 0);
                BitHelper.Write(ref bits, 2, 0);
                BitHelper.Write(ref bits, 1, 1);
                BitHelper.Write(ref bits, 2, aacProfile);
                BitHelper.Write(ref bits, 4, sampleRateIndex);
                BitHelper.Write(ref bits, 1, 0);
                BitHelper.Write(ref bits, 3, channelConfig);
                BitHelper.Write(ref bits, 1, 0);
                BitHelper.Write(ref bits, 1, 0);
                BitHelper.Write(ref bits, 1, 0);
                BitHelper.Write(ref bits, 1, 0);
                BitHelper.Write(ref bits, 13, 7 + dataSize);
                BitHelper.Write(ref bits, 11, 0x7FF);
                BitHelper.Write(ref bits, 2, 0);

                fileStream.Write(BigEndianBitConverter.GetBytes(bits), 1, 7);
                fileStream.Write(chunk, 1, dataSize);
            }
        }
Exemple #2
0
        private void ParseMp3Frames(byte[] buffer)
        {
            var mpeg1BitRate     = new[] { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 };
            var mpeg2XBitRate    = new[] { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 };
            var mpeg1SampleRate  = new[] { 44100, 48000, 32000, 0 };
            var mpeg20SampleRate = new[] { 22050, 24000, 16000, 0 };
            var mpeg25SampleRate = new[] { 11025, 12000, 8000, 0 };

            int offset = 0;
            int length = buffer.Length;

            while (length >= 4)
            {
                int mpegVersion, sampleRate, channelMode;

                ulong header = (ulong)BigEndianBitConverter.ToUInt32(buffer, offset) << 32;

                if (BitHelper.Read(ref header, 11) != 0x7FF)
                {
                    break;
                }

                mpegVersion = BitHelper.Read(ref header, 2);
                int layer = BitHelper.Read(ref header, 2);
                BitHelper.Read(ref header, 1);
                int bitRate = BitHelper.Read(ref header, 4);
                sampleRate = BitHelper.Read(ref header, 2);
                int padding = BitHelper.Read(ref header, 1);
                BitHelper.Read(ref header, 1);
                channelMode = BitHelper.Read(ref header, 2);

                if (mpegVersion == 1 || layer != 1 || bitRate == 0 || bitRate == 15 || sampleRate == 3)
                {
                    break;
                }

                bitRate = (mpegVersion == 3 ? mpeg1BitRate[bitRate] : mpeg2XBitRate[bitRate]) * 1000;

                switch (mpegVersion)
                {
                case 2:
                    sampleRate = mpeg20SampleRate[sampleRate];
                    break;

                case 3:
                    sampleRate = mpeg1SampleRate[sampleRate];
                    break;

                default:
                    sampleRate = mpeg25SampleRate[sampleRate];
                    break;
                }

                int frameLenght = GetFrameLength(mpegVersion, bitRate, sampleRate, padding);

                if (frameLenght > length)
                {
                    break;
                }

                bool isVbrHeaderFrame = false;

                if (frameOffsets.Count == 0)
                {
                    // Check for an existing VBR header just to be safe (I haven't seen any in FLVs)
                    int o = offset + GetFrameDataOffset(mpegVersion, channelMode);

                    if (BigEndianBitConverter.ToUInt32(buffer, o) == 0x58696E67)
                    {
                        // "Xing"
                        isVbrHeaderFrame  = true;
                        this.delayWrite   = false;
                        this.hasVbrHeader = true;
                    }
                }

                if (!isVbrHeaderFrame)
                {
                    if (this.firstBitRate == 0)
                    {
                        this.firstBitRate     = bitRate;
                        this.mpegVersion      = mpegVersion;
                        this.sampleRate       = sampleRate;
                        this.channelMode      = channelMode;
                        this.firstFrameHeader = BigEndianBitConverter.ToUInt32(buffer, offset);
                    }

                    else if (!this.isVbr && bitRate != this.firstBitRate)
                    {
                        this.isVbr = true;

                        if (!this.hasVbrHeader)
                        {
                            if (this.delayWrite)
                            {
                                this.WriteVbrHeader(true);
                                this.writeVbrHeader = true;
                                this.delayWrite     = false;
                            }

                            else
                            {
                                this.warnings.Add("Detected VBR too late, cannot add VBR header.");
                            }
                        }
                    }
                }

                this.frameOffsets.Add(this.totalFrameLength + (uint)offset);

                offset += frameLenght;
                length -= frameLenght;
            }

            this.totalFrameLength += (uint)buffer.Length;
        }