2012-07-14 227 views
0

我有一個通過http傳輸視頻和音頻的DLink網絡攝像頭(DCS-932L)。使用NAudio播放(無效)音頻流

視頻是mjpeg(運動jpeg),而音頻是單聲道的16位PCM wav音頻。

我可以讀取顯示視頻流,但我遇到了音頻問題。根據接收到的頭文件,音頻文件只有30秒長,但是由於相機連續發送數據(用wget進行檢查),這是錯誤的。

NAudio,VLC,Windows媒體播放器等都在30秒後停止,因爲wav標題說他們應該。任何人都知道如何讓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); 
       } 
      } 
     } 
    } 

回答

0

一些不得不通過簡單地開始了新的要求,每30秒成功。

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

但是,如果你想自己破解它,你可以編輯就地WAV頭,並設置所有下面的最初8字節的報頭數據的長度。初始標題中的第二組4字節基本上是(總文件長度-8字節),並以小端字節順序存儲爲32位無符號整數。

因此,在收到前8個字節後,您可以嘗試將WAV文件大小設置爲更大的值,如UInt32.MaxValue - 8。但是在大約4GB之後,這仍然有一個限制,並且您最終必須重新啓動您的請求。

您還需要在讀取和寫入ms時添加一些鎖定,我認爲這是MemoryStream?我沒有顯示任何鎖定,但我認爲在創建blockAlignedStream之前設置ms.Position = 0時,以及在nAudio類開始從流中讀取時會遇到問題,因爲您還將同時寫入請求中的流線。這將表現爲非常扭曲的聲音和很多流行音樂。

MemoryStream對於多線程而言並不安全,不需要自己管理鎖定,並且由於您無法控制NAudio代碼中的流的鎖定,您必須創建自己的流,以管理讀寫位置分開,並在內部處理鎖定。

查看PipeStreamhttp://www.codeproject.com/Articles/16011/PipeStream-a-Memory-Efficient-and-Thread-Safe-Stre

... 
      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執行n音訊播放。

0

寫另一個Stream(子類)圍繞從網絡攝像頭獲得的一個,並在原地改變WAV頭。它可能工作!

1

最簡單的方法是使用RawSourceWaveStream,然後傳入一個已經跳過WAV頭的流。