c# - 流式音频中的降噪和压缩

标签 c# compression wav audio-streaming noise-reduction

希望能帮到你。我正在用麦克风录制音频并通过网络直播。采样质量为 11025hz,8 位,单声道。虽然有一点延迟(1 秒),但效果很好。我需要帮助的是我现在正在尝试实现降噪和压缩,以使音频更安静并使用更少的带宽。音频样本存储在字节 [] 的 C# 数组中,我使用 Socket 发送/接收它。

谁能建议如何在 C# 中实现压缩和降噪?我不介意使用第三方库,只要它是免费的(LGPL 许可证等)并且可以从 C# 中使用。但是,我更喜欢实际工作的源代码示例。提前感谢您的任何建议。

更新:

我将比特大小从 8 位音频更改为 16 位音频,噪音问题得到解决。显然来自麦克风的 8 位音频信噪比太低。 11khz、16 位单声道的声音听起来很棒。

然而,自从我发布这篇文章以来,这个项目的要求发生了变化。我们现在也在尝试添加视频。我有一个回调设置,每 100 毫秒从网络摄像头接收实时图像。我需要对音频和视频进行编码,复用它们,将它们通过我的套接字传输到服务器,服务器将流重新传输到另一个客户端,该客户端接收流,解复用流并解码音频和视频,显示图片框中的视频并将音频输出到扬声器。

我正在查看 ffmpeg 以帮助解决 (de|en) 编码/[de] 多路复用,我也在查看 SharpFFmpeg 作为 ffmpeg 的 C# 互操作库。

我找不到任何这样做的好例子。我整个星期都在网上搜索,没有真正的运气。非常感谢您提供的任何帮助!

这是一些代码,包括我的麦克风录音回调函数:

        private const int AUDIO_FREQ = 11025;
        private const int CHANNELS = 1;
        private const int BITS = 16;
        private const int BYTES_PER_SEC = AUDIO_FREQ * CHANNELS * (BITS / 8);
        private const int BLOCKS_PER_SEC = 40;
        private const int BUFFER_SECS = 1;
        private const int BUF_SIZE = ((int)(BYTES_PER_SEC / BLOCKS_PER_SEC * BUFFER_SECS / 2)) * 2; // rounded to nearest EVEN number

        private WaveLib.WaveOutPlayer m_Player;
        private WaveLib.WaveInRecorder m_Recorder;
        private WaveLib.FifoStream m_Fifo;

        WebCam MyWebCam;

        public void OnPickupHeadset()
        {
            stopRingTone();
            m_Fifo = new WaveLib.FifoStream();

            WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(AUDIO_FREQ, BITS, CHANNELS);
            m_Player = new WaveLib.WaveOutPlayer(-1, fmt, BUF_SIZE, BLOCKS_PER_SEC,
                            new WaveLib.BufferFillEventHandler(PlayerCB));
            m_Recorder = new WaveLib.WaveInRecorder(-1, fmt, BUF_SIZE, BLOCKS_PER_SEC,
                            new WaveLib.BufferDoneEventHandler(RecorderCB));

            MyWebCam = null;
            try
            {
                MyWebCam = new WebCam();                
                MyWebCam.InitializeWebCam(ref pbMyPhoto, pbPhoto.Width, pbPhoto.Height);
                MyWebCam.Start();
            }
            catch { }

        }

        private byte[] m_PlayBuffer;
        private void PlayerCB(IntPtr data, int size)
        {
            try
            {
                if (m_PlayBuffer == null || m_PlayBuffer.Length != size)
                    m_PlayBuffer = new byte[size];

                if (m_Fifo.Length >= size)
                {
                    m_Fifo.Read(m_PlayBuffer, 0, size);
                }
                else
                {
                    // Read what we can 
                    int fifoLength = (int)m_Fifo.Length;
                    m_Fifo.Read(m_PlayBuffer, 0, fifoLength);

                    // Zero out rest of buffer
                    for (int i = fifoLength; i < m_PlayBuffer.Length; i++)
                        m_PlayBuffer[i] = 0;                        
                }

                // Return the play buffer
                Marshal.Copy(m_PlayBuffer, 0, data, size);
            }
            catch { }
        }


        private byte[] m_RecBuffer;
        private void RecorderCB(IntPtr data, int size)
        {
            try
            {
                if (m_RecBuffer == null || m_RecBuffer.Length != size)
                    m_RecBuffer = new byte[size];
                Marshal.Copy(data, m_RecBuffer, 0, size);

                // HERE'S WHERE I WOULD ENCODE THE AUDIO IF I KNEW HOW

                // Send data to server
                if (theForm.CallClient != null)
                {
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                    args.SetBuffer(m_RecBuffer, 0, m_RecBuffer.Length);
                    theForm.CallClient.SendAsync(args);
                }
            }
            catch { }
        }

        //Called from network stack when data received from server (other client)
        public void PlayBuffer(byte[] buffer, int length)
        {
            try
            {
                //HERE'S WHERE I WOULD DECODE THE AUDIO IF I KNEW HOW

                m_Fifo.Write(buffer, 0, length); 
            }
            catch { }
        }

那么我应该从这里去哪里呢?

最佳答案

你们的目标有点相互排斥。您的 11025Hz/8 位/单声道 WAV 文件听起来嘈杂(带有大量“嘶嘶声”)的原因是它们的采样率和位分辨率较低(44100Hz/16 位/立体声是 CD 质量音频的标准)。

如果您继续以该速率录制和流式传输,您将会听到嘈杂的音频。消除(或实际上只是减弱)这种噪音的唯一方法是将音频上采样到 44100Hz/16 位,然后对其执行某种降噪算法。这种上采样必须由客户端应用程序执行,因为在流式传输之前在服务器上执行它意味着你将流式传输比原始音频大 8 倍的音频(在服务器上执行它也完全没有意义,因为你会最好一开始就以更密集的格式录制)。

您要做的是以 CD 质量格式录制原始音频,然后将其压缩为标准格式,如 MP3 或 Ogg Vorbis。请参阅之前的问题:

What's the best audio compression library for .NET?

更新:我没用过这个,但是:

http://www.ohloh.net/p/OggVorbisDecoder

我认为您需要一个编码器,但我找不到用于 Ogg Vorbis 的编码器。我认为您也可以尝试编码为 WMV 格式:

http://www.discussweb.com/c-programming/1728-encoding-wmv-file-c-net.html

更新 2: 抱歉,我的流媒体知识水平很低。如果我正在做你正在做的事情,我会先从音频和静止图像创建一个(未压缩的)AVI 文件(通过 PInvoke 使用 avifil32.dll 方法),然后将其压缩到MPEG(或任何标准格式 - YouTube 有一个页面,他们在其中讨论他们的首选格式,使用其中一种格式可能会很好)。

我不确定这是否会满足您的需要,但是这个链接:

http://csharpmagics.blogspot.com/

使用这个免费播放器:

http://www.videolan.org/

可能有用。

关于c# - 流式音频中的降噪和压缩,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3000642/

相关文章:

压缩字符数据

wav - 显示 WAV 文件音高

java - 无法创建 AudioData 对象?

c# - dotNet 4.0 剪贴板错误?

algorithm - 实际压缩和 Kolmogorov 复杂性的界限

c# - Winforms应用程序崩溃

c++ - 如何使用 jpg 库从 jpg 中获取 DC 系数?

javascript - 从 wav 文件中读取样本

c# - 检查 List<T> 元素是否包含具有特定属性值的项目

c# - 来自计时器触发器的 Azure 函数输出服务总线绑定(bind)