⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 codecs.cs

📁 著名的开源动态库speex的动态库C++二次封装
💻 CS
字号:
using System.Collections;
using System.Data;
using System.Text;
using System.Runtime.InteropServices;
using System;

namespace RtpAudio
{

    #region//编解码动态库引用
    public static class Codec
    {
        /// <summary>
        /// 语音编码初始化操作
        /// </summary>
        /// <param name="quality"></param>
        [DllImport("speexCodec.dll", EntryPoint = "encoder_init")]
        public extern static void encoder_init(int quality);

        /// <summary>
        ///语音编码的释放
        /// </summary>
        [DllImport("speexCodec.dll", EntryPoint = "encoder_dispose")]
        public extern static void encoder_dispose();

        /// <summary>
        ///语音编码的执行过程
        /// </summary>
        /// <param name="data">要进行编码的数据</param>
        /// <param name="output">编码之后的数据</param>
        /// <returns></returns>
        [DllImport("speexCodec.dll", EntryPoint = "encoder_encode")]
        public extern static int encoder_encode(short[] data, byte[] output);

        /// <summary>
        ///解码初始化
        /// </summary>
        [DllImport("speexCodec.dll", EntryPoint = "decoder_init")]
        public extern static void decoder_init();

        /// <summary>
        ///语音解码释放 
        /// </summary>
        [DllImport("speexCodec.dll", EntryPoint = "decoder_dispose")]
        public extern static void decoder_dispose();

        /// <summary>
        ///语音解码
        /// </summary>
        /// <param name="nbBytes">解码的字节数</param>
        /// <param name="data">要进行解码的语音数据</param>
        /// <param name="output">解码后输出的语音数据</param>
        [DllImport("speexCodec.dll", EntryPoint = "decoder_decode")]
        public extern static void decoder_decode(int nbBytes, byte[] data, short[] output);
    }
    #endregion

    #region// 编码
    public class SpeexEncoder : IDisposable
    {
        const int FrameSize = 160;

        private bool _init = false;

        public void Dispose()
        {
            Codec.encoder_dispose();
            _init = false;
        }

        /// <summary>
        /// 初始化结构保存数据,quality的值可以取 8表示 15kbps
        /// </summary>
        /// <param name="quality"></param>
        public void SetQuality(int quality)
        {
            if (_init)
                Codec.encoder_dispose();
            Codec.encoder_init(quality);
            _init = true;
        }

        //在开始捕获后,每隔 1 秒(缓冲区设置为可以保存最长 10 秒的音频,超过的话最早的内容会被覆盖)读出当前的音频流,
        //然后送给 SpeexEncoder 编码
        /// <summary>
        ///数据编码
        /// </summary>
        /// <param name="data">要进行编码的数据</param>
        /// <returns></returns>
        public byte[] Encode(byte[] data)
        {
            if (!_init)
                throw new NotSupportedException("尚未设置编码器比特率。");
            //data的长度必须为 160 *2 的整数倍
            if (data.Length % (FrameSize * 2) != 0)  //将要进行 语音编码的数据 切分为多个 320字节的单元
                throw new ArgumentException("数据无效。", "data");
            int nbBytes;
            short[] input = new short[FrameSize]; //一会要进行语音编码数据
            byte[] buffer = new byte[200];
            byte[] output = new byte[0];

            for (int i = 0; i < data.Length / (FrameSize * 2); i++) //将 data数组 划分为 多个 320 单元
            {
                for (int j = 0; j < input.Length; j++)
                    input[j] = (short)(data[i * FrameSize * 2 + j * 2] + data[i * FrameSize * 2 + j * 2 + 1] * 0x100);

                nbBytes = Codec.encoder_encode(input, buffer); //针对 每 320 字节即编码, 编码之后的数据长度

                Array.Resize<byte>(ref output, output.Length + nbBytes + sizeof(int));
                Array.Copy(buffer, 0, output, output.Length - nbBytes, nbBytes);
                for (int j = 0; j < sizeof(int); j++)
                {
                    output[output.Length - nbBytes - sizeof(int) + j] = (byte)(nbBytes % 0x100);
                    nbBytes /= 0x100;
                }
            }
            return output;
        }
    }
    #endregion

    #region//解码
    public class SpeexDecoder : IDisposable
    {
        public const int FrameSize = 160;

        private bool _init = false;

        /// <summary>
        ///解码释放
        /// </summary>
        public void Dispose()
        {
            if (_init)
                Codec.decoder_dispose();
        }

       
        
        /// <summary>
        ///解码语音数据
        /// </summary>
        /// <param name="data">要解码的语音数据</param>
        /// <returns>解码之后的语音数组</returns>
        public byte[] Decode(byte[] data)
        {
            if (!_init)
                Codec.decoder_init(); //解码初始化
            int nbBytes, index = 0;

            byte[] input; // input数组为一暂存数组
            short[] buffer = new short[FrameSize];
            byte[] output = new byte[0];

            while (index < data.Length)
            {
                nbBytes = 0;
                //每段的前四字节存储的是 该段数据的长度值
                index += sizeof(int);
                for (int i = 1; i <= sizeof(int); i++)
                    nbBytes = nbBytes * 0x100 + data[index - i]; 

                input = new byte[nbBytes]; //读出对应的解码段的长度

                Array.Copy(data, index, input, 0, input.Length);// 将接收的编码语音数据拷贝到  input数组中去

                index += input.Length;

                //解码之后的数据在 buffer中
                Codec.decoder_decode(nbBytes, input, buffer); //对数据进行解码,解码后语音数据即还原了

                Array.Resize<byte>(ref output, output.Length + FrameSize * 2);

                for (int i = 0; i < FrameSize; i++)
                {
                    output[output.Length - FrameSize * 2 + i * 2] = (byte)(buffer[i] % 0x100);
                    output[output.Length - FrameSize * 2 + i * 2 + 1] = (byte)(buffer[i] / 0x100);
                }
            }
            return output;
        }
    }
    #endregion

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -