流音频中的降噪和压缩

时间:2010-06-08 19:37:43

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

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

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

更新

我将位大小从8位音频更改为16位音频,并且噪音问题已修复。来自麦克风的8位音频具有太低的信噪比。声音听起来很棒,11khz,16位单声道。

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

我正在寻找ffmpeg以帮助解决(de | en)编码/ [de] muxing,我也将SharpFFmpeg视为ffmpeg的C#interop库。

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

这是一些代码,包括麦克风录音的回叫功能:

        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 { }
        }

那么我应该从哪里开始呢?

2 个答案:

答案 0 :(得分:1)

这里的目标是互相排斥的。您的11025Hz / 8bit / Mono WAV文件声音嘈杂(带有大量“嘶嘶声”)的原因是它们的低采样率和比特分辨率(44100Hz / 16bit / Stereo是CD音质的标准)。

如果您继续以该速率录制和流式传输,则音频会产生噪音。消除(或实际上只是衰减)这种噪声的唯一方法是将音频上采样到44100Hz / 16bit,然后对其执行某种降噪算法。这个上采样必须由客户端应用程序执行,因为在流式传输之前在服务器上执行此操作意味着您将流式传输比原始音频大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:抱歉,我的流媒体知识水平相当低。如果我正在做你正在做的事情,我会首先从音频和静止图像(通过PInvoke使用avifil32.dll方法)创建一个(未压缩的)AVI文件,然后将其压缩为MPEG(或任何格式)是标准的 - YouTube有一个页面,他们可以在这里讨论他们的首选格式,并且使用其中一种可能很好。)

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

http://csharpmagics.blogspot.com/

使用这个免费的播放器:

http://www.videolan.org/

可能有用。

答案 1 :(得分:0)

如果您只想压缩数据以限制带宽使用,可以尝试使用GZipStream。