0

http 経由でビデオとオーディオをストリーミングする DLink Web カメラ (DCS-932L) を持っています。

動画はmjpeg(モーションjpeg)、音声は16bit PCM wav音声のモノラルです。

ビデオ ストリームの番組は問題なく読めますが、音声に問題があります。受信したヘッダーによると、オーディオ ファイルの長さはわずか 30 秒ですが、カメラがデータを送信し続けるため (wget で確認)、これは誤りです。

NAudio、VLC、Windows Media Player などの両方が、wav ヘッダーが示すように 30 秒後にすべて停止します。NAudio にストリーム ヘッダーの長さプロパティを破棄させる方法を知っている人はいますか? または、これを処理するために使用できる他のライブラリはありますか?

30 秒を再生する今日使用するコードは次のとおりです。

public void PlayWaveFromUrl(string url)
    {
        new Thread(delegate(object o)
        {
            var req = WebRequest.Create(url);
            req.Credentials = GetCredential(url);
            req.PreAuthenticate = true;

            var response = req.GetResponse();

            using (var stream = response.GetResponseStream())
            {
                byte[] buffer = new byte[65536]; // 64KB chunks
                int read;
                while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    var pos = ms.Position;
                    ms.Position = ms.Length;
                    ms.Write(buffer, 0, read);
                    ms.Position = pos;
                }
            }
        }).Start();

        // Pre-buffering some data to allow NAudio to start playing
        while (ms.Length < 65536 * 10)
            Thread.Sleep(1000);

        ms.Position = 0;
        using (WaveStream blockAlignedStream = new BlockAlignReductionStream(WaveFormatConversionStream.CreatePcmStream(new WaveFileReader(ms))))
        {
            using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
            {
                waveOut.Init(blockAlignedStream);
                waveOut.Play();
                while (waveOut.PlaybackState == PlaybackState.Playing)
                {
                    System.Threading.Thread.Sleep(100);
                }
            }
        }
    }
4

3 に答える 3

1

最も簡単な方法は、RawSourceWaveStreamを使用してから、すでにWAVヘッダーをスキップしたストリームを渡すことです。

于 2012-07-16T09:53:01.780 に答える
0

30 秒ごとに新しいリクエストを開始するだけで成功したものもあります。

参照: http://forums.ispyconnect.com/forum.aspx?g=posts&m=2717#post2717

ただし、自分でハックしたい場合は、WAV ヘッダーをその場で編集して、最初の 8 バイトのヘッダーに続くすべてのデータの長さを設定できます。初期ヘッダーの 4 バイトの 2 番目のセットは、基本的に (ファイルの合計長 - 8 バイト) であり、リトル エンディアンのバイト順で 32 ビットの符号なし整数として格納されます。

そのため、最初の 8 バイトを受信したら、WAV ファイルのサイズをもっと大きな値 (たとえばUInt32.MaxValue - 8. ただし、これには約 4GB を超えるとまだ制限があり、最終的にはリクエストを再起動する必要があります。

また、 への読み取りと書き込みに関するロックを追加する必要がありmsますMemoryStream。ロックについては示していませんが、ms.Position = 0を作成する前に設定blockAlignedStreamしたときと、nAudio クラスがストリームからの読み取りを開始したときに問題が発生すると思います。これは、リクエスト スレッドで同時にストリームに書き込みを行うためです。これは、非常に歪んだ音でポップ音を多く含んだ音として現れます。

MemoryStream は、自分でロックを管理しないと複数のスレッドで安全に使用できません。また、NAudio コードでストリームのロックを制御できないため、読み取り位置と書き込み位置を個別に管理する独自のストリームを作成する必要があります。内部でロックを処理します。

http://www.codeproject.com/Articles/16011/PipeStream-a-Memory-Efficient-and-Thread-Safe-StrePipeStreamでクラスを参照してください。

    ...
            byte[] buffer = new byte[65536]; // 64KB chunks 
            int read; 
            long totalRead; 
            int bufferPosition = 0;
            bool changedLength = false;

            while ((read = stream.Read(buffer, bufferPosition, buffer.Length)) > 0) 
            { 
                totalRead += read;
                if (!changedLength)
                {
                   if (totalRead < 8) 
                   {
                       // need more bytes
                       bufferPosition += read;
                       continue;
                   } 
                   else
                   {
                       const uint fileLength = uint.MaxValue - 8;

                       buffer[4] = (byte)(fileLength         && 0xFF);
                       buffer[5] = (byte)((fileLength >>  8) && 0xFF);
                       buffer[6] = (byte)((fileLength >> 16) && 0xFF);
                       buffer[7] = (byte)((fileLength >> 24) && 0xFF);

                       changedLength = true;
                       bufferPosition = 0;

                       var pos = ms.Position; 
                       ms.Position = ms.Length; 
                       ms.Write(buffer, 0, (int)totalRead); 
                       ms.Position = pos; 
                   }
                }                    
                else
                {
                    var pos = ms.Position; 
                    ms.Position = ms.Length; 
                    ms.Write(buffer, 0, read); 
                    ms.Position = pos; 
                }
            } 

    ...

最終的に、制限なしで永久に読み取りたい場合は、ストリームの RIFF 構造を解釈し、サンプル データを取り出し、WaveFormatConversionStream.

于 2012-07-14T19:49:02.847 に答える
0

Web カメラから取得したものの周りに別のStream(サブクラス) を記述し、WAV ヘッダーをインプレースで変更します。それはうまくいくかもしれません!

于 2012-07-14T20:04:54.293 に答える