[英]Play (invalid) audio stream with NAudio
我有一個DLink網絡攝像頭(DCS-932L),可通過http流視頻和音頻。
視頻為mjpeg(運動jpeg),而音頻為單聲道16位PCM wav音頻。
我可以很好地閱讀節目的視頻流,但是音頻卻有問題。 根據接收到的標頭,音頻文件只有30秒長,但這是錯誤的,因為攝像頭將繼續永遠發送數據(已通過wget檢查)。
NWA,VLC,Windows Media Player等都在30秒后停止,如wav標頭所示。 有人知道讓NAudio丟棄流頭的length屬性的方法嗎? 還是我可以使用的其他任何可以處理此問題的庫?
我今天使用的播放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);
}
}
}
}
最簡單的方法是使用RawSourceWaveStream,然后傳遞已經跳過WAV標頭的流。
有些僅通過每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代碼中流的鎖定,因此必須創建自己的流來分別管理讀寫位置,並且內部處理鎖。
請參閱位於http://www.codeproject.com/Articles/16011/PipeStream-a-Memory-Efficient-and-Thread-Safe-Stre的PipeStream
類。
...
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
進行nAudio播放。
圍繞從網絡攝像頭獲取的內容編寫另一個Stream
(子類),並就地更改WAV標頭。 可能有效!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.