WAV格式音频转G.711A

        有个项目,要求从微信录音,远程传输到终端设备广播。终端只支持G.711A格式,而从微信获取的音频文件是AMR格式(具体获取见微信开发文档),所以就需要音频转码。以前没有做过音频开发,对各种格式不了解,花了几天学习AMR、WAV、G.711等格式编解码,定下技术方案:把AMR转码成WAV,然后提取PCM数据,再压缩成G.711A。在AMR转WAV时,没弄明白AMR格式中每帧数据去掉帧头后那段数据该怎么编解码,不得已只好用ffmpeg转成WAV临时解决。


WAV格式:

                //wav文件格式:
                //0-3字节:RIFF标识
                //4-7字节:文件长度
                //8-11字节:WAVE标识
                //12-15字节:fmt 标识,最后有个空格符
                //16-19字节:文件内部格式信息块大小
                //20-21字节:音频编码方式,1表示PCM格式
                //22-23字节:声道数,单声道1,双声道2
                //24-27字节:采样率,比如44100
                //20-31字节:音频传输速率,单位字节
                //32-33字节:每次采样的字节数,例如,双声道16位,就是4字节
                //34-35字节:采样值的精度,8bit 16bit 24bit
                //[附加数据 2字节]
                //[可选块 12字节]
                //36-39字节:data标识
                //40-43字节:音频数据长度

//...................:PCM音频数据


获取音频数据部分代码:

                int channel = (data[23] << 8) + data[22];


                //获取每次采用的字节数
                int bytesPerSample = (data[33] << 8) + data[32];

                //查找data标记
                int index = 36;
                for (; index < data.Length; index++)
                {
                    if (data[index] == 0x64 && data[index + 1] == 0x61 && data[index + 2] == 0x74 && data[index + 3] == 0x61)
                    {
                        break;
                    }
                }
                index += 4;


                //音频数据长度
                int audioLength = (data[index + 3] << 24) + (data[index + 2] << 16) + (data[index + 1] << 8) + data[index];
                index += 4;


                //音频数据
                fs = File.Create("20170306104559.g711");


                if (bytesPerSample == 1)  //8位单声道
                {
                    for (int i = 0; i < audioLength; i++)
                    {
                        fs.WriteByte(PcmCompressToG711a(data[index + i]));
                    }
                }
                else if (bytesPerSample == 2 && channel == 1)  //16位单声道
                {
                    for (int i = 0; i < audioLength;)
                    {
                        int pcm= ((data[index + i + 1] << 8) + data[index + i]);
                        fs.WriteByte(PcmCompressToG711a((short)pcm));
                        i = i + 2;
                    }
                }
                else if (bytesPerSample == 2 && channel == 2)  //8位双声道
                {
                    for (int i = 0; i < audioLength;)
                    {
                        fs.WriteByte(PcmCompressToG711a((data[index + i])));
                        i = i + 2;
                    }
                }
                else if (bytesPerSample == 4)  //16位双声道
                {
                    for (int i = 0; i < audioLength;)
                    {
                        int pcm = (data[index + i + 1] << 8) + data[index + i];
                        fs.WriteByte(PcmCompressToG711a((short)pcm));
                        i = i + 4;
                    }
                }



PCM转G711A:

            //原理:
            //1.取符号位并取反得到s
            //2.获取强度位eee
            //3.获取高位样本位wxyz
            //4.组合为seeewxyz,将seeewxyz逢偶数为取补数,编码完毕


            /**************eee获取方法*****************/
            /****   Linear Input Code  ------->  Compressed Code   ****/
            /*    s000 0000 wxyz abcd  ------->  s000wxyz    */
            /*    s000 0001 wxyz abcd  ------->  s001wxyz    */
            /*    s000 001w xyza bcde  ------->  s010wxyz    */
            /*    s000 01wx yzab cdef  ------->  s011wxyz    */
            /*    s000 1wxy zabc defg  ------->  s100wxyz    */
            /*    s001 wxyz abcd efgh  ------->  s101wxyz    */
            /*    s01w xyza bcde fghi  ------->  s110wxyz    */
            /*    s1wx yzab cdef ghij  ------->  s111wxyz    */


        ///


        /// 8KHZ 16bit PCM格式编码成 8bit G.711a
        ///

        /// 采样值
        ///
        private byte PcmCompressToG711a(short pcm)
        {

            string s = "";    //符号位
            string eee = "";  //强度位
            string wxyz = ""; //样本位


            s = "1";
            if (pcm < 0)
            {
                pcm = (short)-pcm;
                s = "0";
            }


            string vstr = Convert.ToString(pcm, 2);
            for (int i = vstr.Length; i < 16; i++)
            {
                vstr = "0" + vstr;
            }

            String sub = vstr.Substring(1, 7);
            int index = sub.IndexOf("1");
            wxyz = vstr.Substring(1 + index + 1, 4);


            switch (index)
            {
                case 6:
                    eee = "001";
                    break;
                case 5:
                    eee = "010";
                    break;
                case 4:
                    eee = "011";
                    break;
                case 3:
                    eee = "100";
                    break;
                case 2:
                    eee = "101";
                    break;
                case 1:
                    eee = "110";
                    break;
                case 0:
                    eee = "111";
                    break;
                default:
                    eee = "000";
                    wxyz = vstr.Substring(8, 4);
                    break;
            }

            string temp = s + eee + wxyz;
            string result = "";
            for (int i = 0; i < temp.Length; i++)
            {
                string bit = temp.Substring(i, 1);
                if ((i + 1) % 2 == 0)
                {
                    if (bit.Equals("0"))
                    {
                        result += "1";
                    }
                    else
                    {
                        result += "0";
                    }
                    continue;
                }
                result += bit;
            }

            return Convert.ToByte(result, 2);
        }


从WAV提取PCM转G.711A又遇到噪音很大的问题,后来感觉应该是上面方法中pcm取值的问题

就添加了下面这句,解决了噪音问题

            if (pcm < 0)
            {
                pcm = (short)-pcm;    //pcm为负值时,应该转换成正数
                s = "0";
            }

你可能感兴趣的:(流媒体)