2012-07-14 225 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头的流。