4

あなたが助けてくれることを願っています。マイクから音声を録音し、ネットワーク経由でライブ ストリーミングしています。サンプルの品質は 11025hz、8 ビット、モノラルです。わずかな遅延 (1 秒) がありますが、うまく機能します。私が助けを必要としているのは、ノイズリダクションと圧縮を実装して、オーディオをより静かにし、使用する帯域幅を少なくしようとしていることです。オーディオ サンプルは、Bytes[] の C# 配列に格納されており、Socket を使用して送受信しています。

C# で圧縮とノイズ削減を実装する方法を提案できる人はいますか? 無料(LGPL ライセンスなど)で C# から利用できるものであれば、サードパーティのライブラリを使用してもかまいません。ただし、実際に動作するソース コードの例の方が望ましいと思います。ご提案いただきありがとうございます。

アップデート:

ビット サイズを 8 ビット オーディオから 16 ビット オーディオに変更したところ、ノイズの問題が修正されました。明らかに、マイクからの 8 ビット オーディオの S/N 比が低すぎました。音声は 11khz、16 ビット モノで素晴らしく聞こえます。

ただし、これを投稿してから、このプロジェクトの要件が変更されました。現在、動画の追加も検討中です。ウェブカメラから 100 ミリ秒ごとにライブ画像を受信するコールバック設定があります。オーディオとビデオをエンコードし、それらを多重化し、ソケットでサーバーに送信する必要があります。サーバーはストリームを他のクライアントに再送信し、ストリームを受信し、ストリームを分離し、オーディオとビデオをデコードし、ビデオをピクチャボックスに出力し、オーディオをスピーカーに出力します。

(de|en)coding/[de]muxing を支援するために ffmpeg を検討しています。また、ffmpeg への C# 相互運用ライブラリとして SharpFFmpeg も検討しています。

これを行う良い例は見つかりません。私は 1 週間ずっとインターネットを探し回りましたが、まったく運がありませんでした。あなたが提供できるどんな助けも大歓迎です!

マイク録音用のコールバック関数を含むいくつかのコードを次に示します。

        プライベート const int AUDIO_FREQ = 11025;
        プライベート const int CHANNELS = 1;
        プライベート const int BITS = 16;
        private const int BYTES_PER_SEC = AUDIO_FREQ * CHANNELS * (BITS / 8);
        プライベート const int BLOCKS_PER_SEC = 40;
        プライベート const int BUFFER_SECS = 1;
        private const int BUF_SIZE = ((int)(BYTES_PER_SEC / BLOCKS_PER_SEC * BUFFER_SECS / 2)) * 2; // 最も近い偶数に四捨五入

        プライベート WaveLib.WaveOutPlayer m_Player;
        プライベート WaveLib.WaveInRecorder m_Recorder;
        プライベート WaveLib.FifoStream m_Fifo;

        ウェブカメラ MyWebCam;

        public void OnPickupHeadset()
        {
            stopRingTone();
            m_Fifo = 新しい WaveLib.FifoStream();

            WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(AUDIO_FREQ, BITS, CHANNELS);
            m_Player = 新しい 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;
            試す
            {
                MyWebCam = 新しい WebCam();                
                MyWebCam.InitializeWebCam(ref pbMyPhoto, pbPhoto.Width, pbPhoto.Height);
                MyWebCam.Start();
            }
            キャッチ { }

        }

        プライベート バイト[] m_PlayBuffer;
        private void PlayerCB(IntPtr data, int size)
        {
            試す
            {
                if (m_PlayBuffer == null || m_PlayBuffer.Length != サイズ)
                    m_PlayBuffer = 新しいバイト[サイズ];

                if (m_Fifo.Length >= サイズ)
                {
                    m_Fifo.Read(m_PlayBuffer, 0, サイズ);
                }
                そうしないと
                {
                    // 読めるものを読む
                    int fifoLength = (int)m_Fifo.Length;
                    m_Fifo.Read(m_PlayBuffer, 0, fifoLength);

                    // バッファの残りをゼロにする
                    for (int i = fifoLength; i < m_PlayBuffer.Length; i++)
                        m_PlayBuffer[i] = 0;                        
                }

                // 再生バッファを返す
                Marshal.Copy(m_PlayBuffer, 0, データ, サイズ);
            }
            キャッチ { }
        }


        プライベート バイト[] m_RecBuffer;
        private void RecorderCB(IntPtr データ、int サイズ)
        {
            試す
            {
                if (m_RecBuffer == null || m_RecBuffer.Length != サイズ)
                    m_RecBuffer = 新しいバイト[サイズ];
                Marshal.Copy(データ、m_RecBuffer、0、サイズ);

                // 方法がわかれば、ここでオーディオをエンコードします

                // サーバーにデータを送信
                if (theForm.CallClient != null)
                {
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                    args.SetBuffer(m_RecBuffer, 0, m_RecBuffer.Length);
                    theForm.CallClient.SendAsync(引数);
                }
            }
            キャッチ { }
        }

        //サーバー(他のクライアント)からデータを受信したときにネットワークスタックから呼び出される
        public void PlayBuffer(byte[] buffer, int length)
        {
            試す
            {
                // 方法がわかれば、ここでオーディオをデコードします

                m_Fifo.Write(バッファ、0、長さ);
            }
            キャッチ { }
        }

では、ここからどこへ行けばよいのでしょうか。

4

2 に答える 2

1

ここでのあなたの目標は、一種の相互に排他的です。11025Hz / 8bit / Mono WAVファイルのノイズが大きい(大量の「ヒス」がある)理由は、サンプルレートとビット解像度が低いためです(44100Hz / 16bit / StereoがCD品質のオーディオの標準です)。

そのレートで録音とストリーミングを続けると、ノイズの多いオーディオが発生します。このノイズを除去する(または実際に減衰させる)唯一の方法は、オーディオを44100Hz / 16ビットにアップサンプリングしてから、何らかのノイズリダクションアルゴリズムを実行することです。このアップサンプリングは、クライアントアプリケーションで実行する必要があります。ストリーミングの前にサーバーで実行すると、元のオーディオの8倍の大きさのオーディオをストリーミングすることになります(サーバーで実行しても、まったく意味がありません。そもそも、より密度の高いフォーマットで録音する方が良いでしょう)。

元のオーディオをCD品質の形式で録音してから、MP3やOggVorbisなどの標準形式に圧縮します。この以前の質問を参照してください:

.NETに最適なオーディオ圧縮ライブラリは何ですか?

更新: 私はこれを使用していませんが:

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

エンコーダーが必要だと思いますが、OggVorbis用のエンコーダーが見つかりませんでした。WMV形式へのエンコードも試してみてください。

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

更新2: 申し訳ありませんが、ストリーミングの知識レベルはかなり低いです。私があなたがしているようなことをしているなら、私はavifil32.dll最初にオーディオと静止画像から(非圧縮の)AVIファイルを作成し(PInvokeを介した方法を使用して)、次にそれをMPEG(または標準のフォーマット-YouTubeが持っているもの)に圧縮します彼らが彼らの好みのフォーマットについて話しているページ、そしておそらくこれらの1つを使うのは良いことです)。

これで必要なことができるかどうかはわかりませんが、このリンクは次のとおりです。

http://csharpmagics.blogspot.com/

この無料プレーヤーの使用:

http://www.videolan.org/

うまくいくかもしれません。

于 2010-06-08T19:56:49.583 に答える
0

帯域幅の使用を制限するためにデータを圧縮するだけの場合は、GZipStream を使用してみてください。

于 2010-06-10T21:07:14.073 に答える