Подавление шума и сжатие в потоковом аудио

надеюсь, ты сможешь помочь. Я записываю звук с микрофона и транслирую его в прямом эфире по сети. Качество семплов - 11025 Гц, 8 бит, моно. Хотя есть небольшая задержка (1 секунда), работает отлично. Мне нужна помощь, так это то, что я пытаюсь реализовать шумоподавление и сжатие, чтобы сделать звук тише и использовать меньшую полосу пропускания. Аудиосэмплы хранятся в массиве байтов [] C #, который я отправляю / получаю с помощью Socket.

Может ли кто-нибудь подсказать, как в C # реализовать сжатие и шумоподавление? Я не против использования сторонней библиотеки, если она бесплатна (лицензия LGPL и т. Д.) И может быть использована из C #. Однако я бы предпочел реально работающие примеры исходного кода. Заранее благодарим за любые предложения.

ОБНОВЛЕНИЕ:

Я изменил размер бит с 8-битного звука на 16-битный звук, и проблема с шумом решена. Примерно 8-битный звук с микрофона имел слишком низкое отношение сигнал / шум. Голос звучит отлично на 11 кГц, 16 бит моно.

Однако с тех пор, как я опубликовал это, требования этого проекта изменились. Сейчас мы также пытаемся добавить видео. У меня есть настройка обратного вызова, которая получает живые изображения каждые 100 мс с веб-камеры. Мне нужно кодировать аудио и видео, мультиплексировать их, передавать через мой сокет на сервер, сервер повторно передает поток другому клиенту, который получает поток, демультиплексирует поток и декодирует аудио и видео, отображает видео в окне изображения и выводит звук на динамик.

Я смотрю на ffmpeg, чтобы помочь с (de | en) кодированием / [de] мультиплексированием, и я также смотрю на SharpFFmpeg как на библиотеку взаимодействия C # с ffmpeg.

Я не могу найти хороших примеров этого. Всю неделю я рыскал по Интернету, но без особого успеха. Любая помощь, которую вы можете оказать, очень ценится!

Вот код, включая мою функцию обратного вызова для записи с микрофона:

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

Так что же мне делать дальше?


person Rodney Burton    schedule 08.06.2010    source источник
comment
Какой тип сжатия вы имеете в виду: en.wikipedia.org/wiki/Audio_compression   -  person JW.    schedule 11.06.2010
comment
Пожалуйста, посмотрите мое обновление. Необходимо сжать аудио и видео в прямой эфир. Я не знаю, какой метод мне нужно использовать. Я передаю голос вместе с видео размером 80x80 (маленькое). Он должен хорошо работать в Интернете.   -  person Rodney Burton    schedule 11.06.2010
comment
Следуя вашей ссылке, это будет сжатие звука (данных), а не сжатие динамического диапазона. Требуется сжатие для передачи через Интернет (все соединения будут иметь высокоскоростной Интернет), но мы должны иметь возможность поддерживать большое количество соединений через наш потоковый сервер, поэтому пропускная способность важна.   -  person Rodney Burton    schedule 11.06.2010
comment
Привет, @RodneyBurton, я пытаюсь сделать что-то очень похожее на ваше, но на Android. Мне удалось получить голосовой вызов через wifi, но у меня тоже Лаг. Эта задержка в основном увеличивается / уменьшается на величину буфера. Я не могу уменьшить буфер слишком сильно, потому что телефон не может обрабатывать его так быстро. Ok. Еще я думал о сжатии звука. Я пробовал безуспешно (трудно сделать на Android). Но я тоже думал, стоит ли? Для уменьшения лага? Я имею в виду, что мы будем пытаться сжать действительно небольшой фрагмент разговора, будет ли он сжат? Что вы думаете?   -  person Daniel    schedule 12.02.2014


Ответы (2)


Ваши цели здесь как бы взаимоисключающие. Причина, по которой ваши файлы WAV 11025 Гц / 8 бит / моно звучат шумно (с огромным количеством «шипения»), заключается в их низкой частоте дискретизации и разрешении в битах (44100 Гц / 16 бит / стерео является стандартом для звука CD-качества).

Если вы продолжите запись и потоковую передачу с такой скоростью, у вас будет шумный звук. Единственный способ устранить (или фактически просто ослабить) этот шум - это повысить дискретизацию звука до 44100 Гц / 16 бит, а затем выполнить какой-либо алгоритм шумоподавления на нем. Это повышение частоты дискретизации должно быть выполнено клиентским приложением, поскольку выполнение его на сервере перед потоковой передачей означает, что вы будете передавать аудио в 8 раз больше, чем исходное (выполнение этого на сервере также будет совершенно бессмысленным, поскольку вы будете лучше просто записать в более плотном формате в первую очередь).

Что вы хотите сделать, так это записать исходный звук в формате CD-качества, а затем сжать его до стандартного формата, такого как MP3 или Ogg Vorbis. См. Предыдущий вопрос:

Какая библиотека сжатия звука лучшая для .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 из аудио и неподвижных изображений (используя методы avifil32.dll через PInvoke), а затем сжал бы его в MPEG (или любой другой стандартный формат - YouTube есть страница, на которой они рассказывают о своих предпочтительных форматах, и, вероятно, будет полезно использовать один из них).

Я не уверен, что это сделает то, что вам нужно, но эта ссылка:

http://csharpmagics.blogspot.com/

с помощью этого бесплатного плеера:

http://www.videolan.org/

может работать.

person MusiGenesis    schedule 08.06.2010
comment
Спасибо за Ваш ответ. Имеет смысл сэмплировать с более высоким качеством, а затем выполнить сжатие. Я загрузил исходный код для libogg и libvorbis и скомпилировал их, так что у меня есть DLL. Но я не знаю, как использовать их в моем приложении на C #. Не могли бы вы указать мне пример использования [DllImport] из C # для кодирования / декодирования моего буфера аудиопотока в реальном времени? - person Rodney Burton; 09.06.2010
comment
Я тоже не смог найти кодировщика C # Ogg. Если я пойду по пути Ogg, мне понадобится решение на C #, которое может кодировать И декодировать Ogg Vorbis и Theora, потому что сейчас я делаю аудио + видео. Тяжелый порядок, а? - person Rodney Burton; 11.06.2010
comment
Если вы делаете аудио и видео, я бы посоветовал не беспокоиться об аудио как об отдельной вещи. Используйте что-то, что кодирует / декодирует как аудио, так и видео (что почти все, включая MPEG, WMV и т. Д.). - person MusiGenesis; 11.06.2010
comment
Некоторые вопросы, с которыми мне нужна помощь: Какой аудиокодек вы бы использовали? Какой видеокодек? Какой формат файла? Какие сторонние библиотеки вы бы использовали? Какие оболочки C # к этим библиотекам? Какие функции в этих библиотеках вы бы назвали для потоковой передачи в реальном времени? - person Rodney Burton; 11.06.2010
comment
Я получил сжатие звука, работающее с G729, и я также пробую кодек Speex (потому что он свободен от патентов). По-прежнему не выбран ни кодек для видео, ни формат файла. Я даже думал об отправке аудио и видео по отдельным портам и не беспокоился о оболочке, но это могло привести к проблеме синхронизации. В потоке будут живые разговоры (веб-камера), так что, возможно, это не будет проблемой. Я не пытаюсь транслировать сохраненные видеофайлы. Я выложу дополнительную информацию, когда она у меня будет. Спасибо за вашу помощь. - person Rodney Burton; 14.06.2010
comment
Чтобы закрыть эту проблему, вот что я в итоге сделал. Мы сказали, что пока забудьте о видео. Мы добавим это позже (два пресс-релиза все равно лучше, чем один!). Мы использовали NAudio для захвата звука, потому что обнаружили, что он более стабилен, чем использовал waveIn / waveOut. У этого были проблемы с освобождением неуправляемых буферов в Vista и периодические сбои. NAudio не разбился! Что касается исходной проблемы, изменение размера бит с 8 бит на 16 бит устранило шум b / g. Мы все еще рассматриваем возможность внедрения кодека Speex (потому что он бесплатный, без патентных ограничений). Спасибо всем за помощь! - person Rodney Burton; 02.07.2010

Если вы хотите только сжать данные, чтобы ограничить использование полосы пропускания, вы можете попробовать использовать GZipStream.

person Jonas Van der Aa    schedule 10.06.2010
comment
Поскольку мы собираемся также делать видео (сейчас), я бы предпочел использовать что-то, разработанное только для AV, вместо общей техники сжатия. Кроме того, мне нужен способ мультиплексирования / демультиплексирования аудио и видео в 1 поток для отправки через 1 сетевой сокет. - person Rodney Burton; 11.06.2010
comment
Боюсь, что андроид плохо приспособлен для мультимедиа :) - person Jonas Van der Aa; 12.06.2010