private void ParseMP3Frames(byte[] buff)
        {
            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 };

            var offset = 0;
            var length = buff.Length;

            while (length >= 4)
            {
                ulong header;
                int   mpegVersion, layer, bitRate, sampleRate, padding, channelMode;
                int   frameLen;

                header = (ulong)BitConverterBE.ToUInt32(buff, offset) << 32;
                if (BitHelper.Read(ref header, 11) != 0x7FF)
                {
                    break;
                }
                mpegVersion = BitHelper.Read(ref header, 2);
                layer       = BitHelper.Read(ref header, 2);
                BitHelper.Read(ref header, 1);
                bitRate    = BitHelper.Read(ref header, 4);
                sampleRate = BitHelper.Read(ref header, 2);
                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;

                if (mpegVersion == 3)
                {
                    sampleRate = MPEG1SampleRate[sampleRate];
                }
                else if (mpegVersion == 2)
                {
                    sampleRate = MPEG20SampleRate[sampleRate];
                }
                else
                {
                    sampleRate = MPEG25SampleRate[sampleRate];
                }

                frameLen = GetFrameLength(mpegVersion, bitRate, sampleRate, padding);
                if (frameLen > length)
                {
                    break;
                }

                var isVBRHeaderFrame = false;
                if (_frameOffsets.Count == 0)
                {
                    // Check for an existing VBR header just to be safe (I haven't seen any in FLVs)
                    var o = offset + GetFrameDataOffset(mpegVersion, channelMode);
                    if (BitConverterBE.ToUInt32(buff, o) == 0x58696E67)
                    {                     // "Xing"
                        isVBRHeaderFrame = true;
                        _delayWrite      = false;
                        _hasVBRHeader    = true;
                    }
                }

                if (isVBRHeaderFrame)
                {
                }
                else if (_firstBitRate == 0)
                {
                    _firstBitRate     = bitRate;
                    _mpegVersion      = mpegVersion;
                    _sampleRate       = sampleRate;
                    _channelMode      = channelMode;
                    _firstFrameHeader = BitConverterBE.ToUInt32(buff, offset);
                }
                else if (!_isVBR && bitRate != _firstBitRate)
                {
                    _isVBR = true;
                    if (_hasVBRHeader)
                    {
                    }
                    else if (_delayWrite)
                    {
                        WriteVBRHeader(true);
                        _writeVBRHeader = true;
                        _delayWrite     = false;
                    }
                    else
                    {
                        _warnings.Add("Detected VBR too late, cannot add VBR header.");
                    }
                }

                _frameOffsets.Add(_totalFrameLength + (uint)offset);

                offset += frameLen;
                length -= frameLen;
            }

            _totalFrameLength += (uint)buff.Length;
        }
示例#2
0
        public void WriteChunk(byte[] chunk, uint timeStamp)
        {
            if (chunk.Length < 1)
            {
                return;
            }

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

                var bits = (ulong)BitConverterBE.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 == 4)                 // HE-AAC
                {
                    _aacProfile = 1;                  // Uses LC profile + SBR
                }
                if (_aacProfile < 0 || _aacProfile > 3)
                {
                    throw new Exception("Unsupported AAC profile.");
                }
                if (_sampleRateIndex > 12)
                {
                    throw new Exception("Invalid AAC sample rate index.");
                }
                if (_channelConfig > 6)
                {
                    throw new Exception("Invalid AAC channel configuration.");
                }
            }
            else
            {             // Audio data
                var   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);

                _fs.Write(BitConverterBE.GetBytes(bits), 1, 7);
                _fs.Write(chunk, 1, dataSize);
            }
        }
        public void WriteChunk(byte[] chunk, uint timeStamp)
        {
            var subModeSizes      = new[] { 0, 43, 119, 160, 220, 300, 364, 492, 79 };
            var wideBandSizes     = new[] { 0, 36, 112, 192, 352 };
            var inBandSignalSizes = new[] { 1, 1, 4, 4, 4, 4, 4, 4, 8, 8, 16, 16, 32, 32, 64, 64 };
            var frameStart        = -1;
            var frameEnd          = 0;
            var offset            = 0;
            var length            = chunk.Length * 8;
            int x;

            while (length - offset >= 5)
            {
                x = BitHelper.Read(chunk, ref offset, 1);
                if (x != 0)
                {
                    // wideband frame
                    x = BitHelper.Read(chunk, ref offset, 3);
                    if (x < 1 || x > 4)
                    {
                        goto Error;
                    }
                    offset += wideBandSizes[x] - 4;
                }
                else
                {
                    x = BitHelper.Read(chunk, ref offset, 4);
                    if (x >= 1 && x <= 8)
                    {
                        // narrowband frame
                        if (frameStart != -1)
                        {
                            WriteFramePacket(chunk, frameStart, frameEnd);
                        }
                        frameStart = frameEnd;
                        offset    += subModeSizes[x] - 5;
                    }
                    else if (x == 15)
                    {
                        // terminator
                        break;
                    }
                    else if (x == 14)
                    {
                        // in-band signal
                        if (length - offset < 4)
                        {
                            goto Error;
                        }
                        x       = BitHelper.Read(chunk, ref offset, 4);
                        offset += inBandSignalSizes[x];
                    }
                    else if (x == 13)
                    {
                        // custom in-band signal
                        if (length - offset < 5)
                        {
                            goto Error;
                        }
                        x       = BitHelper.Read(chunk, ref offset, 5);
                        offset += x * 8;
                    }
                    else
                    {
                        goto Error;
                    }
                }
                frameEnd = offset;
            }
            if (offset > length)
            {
                goto Error;
            }

            if (frameStart != -1)
            {
                WriteFramePacket(chunk, frameStart, frameEnd);
            }

            return;

Error:
            throw new Exception("Invalid Speex data.");
        }
        private void GetFrameSize(byte[] chunk)
        {
            if (_codecID == 2)
            {
                // Reference: flv_h263_decode_picture_header from libavcodec's h263.c

                if (chunk.Length < 10)
                {
                    return;
                }

                if (chunk[0] != 0 || chunk[1] != 0)
                {
                    return;
                }

                var x = BitConverterBE.ToUInt64(chunk, 2);
                int format;

                if (BitHelper.Read(ref x, 1) != 1)
                {
                    return;
                }
                BitHelper.Read(ref x, 5);
                BitHelper.Read(ref x, 8);

                format = BitHelper.Read(ref x, 3);
                switch (format)
                {
                case 0:
                    _width  = BitHelper.Read(ref x, 8);
                    _height = BitHelper.Read(ref x, 8);
                    break;

                case 1:
                    _width  = BitHelper.Read(ref x, 16);
                    _height = BitHelper.Read(ref x, 16);
                    break;

                case 2:
                    _width  = 352;
                    _height = 288;
                    break;

                case 3:
                    _width  = 176;
                    _height = 144;
                    break;

                case 4:
                    _width  = 128;
                    _height = 96;
                    break;

                case 5:
                    _width  = 320;
                    _height = 240;
                    break;

                case 6:
                    _width  = 160;
                    _height = 120;
                    break;

                default:
                    return;
                }
            }
            else if (_codecID == 4 || _codecID == 5)
            {
                // Reference: vp6_parse_header from libavcodec's vp6.c

                var skip = _codecID == 4 ? 1 : 4;
                if (chunk.Length < skip + 8)
                {
                    return;
                }
                var x = BitConverterBE.ToUInt64(chunk, skip);

                var deltaFrameFlag     = BitHelper.Read(ref x, 1);
                var quant              = BitHelper.Read(ref x, 6);
                var separatedCoeffFlag = BitHelper.Read(ref x, 1);
                var subVersion         = BitHelper.Read(ref x, 5);
                var filterHeader       = BitHelper.Read(ref x, 2);
                var interlacedFlag     = BitHelper.Read(ref x, 1);

                if (deltaFrameFlag != 0)
                {
                    return;
                }
                if (separatedCoeffFlag != 0 || filterHeader == 0)
                {
                    BitHelper.Read(ref x, 16);
                }

                _height = BitHelper.Read(ref x, 8) * 16;
                _width  = BitHelper.Read(ref x, 8) * 16;

                // chunk[0] contains the width and height (4 bits each, respectively) that should
                // be cropped off during playback, which will be non-zero if the encoder padded
                // the frames to a macroblock boundary.  But if you use this adjusted size in the
                // AVI header, DirectShow seems to ignore it, and it can cause stride or chroma
                // alignment problems with VFW if the width/height aren't multiples of 4.
                if (!_isAlphaWriter)
                {
                    var cropX = chunk[0] >> 4;
                    var cropY = chunk[0] & 0x0F;
                    if ((cropX != 0 || cropY != 0) && !_isAlphaWriter)
                    {
                        _warnings.Add(String.Format("Suggested cropping: {0} pixels from right, {1} pixels from bottom.", cropX, cropY));
                    }
                }
            }
        }