使用NAudio播放(无效)音频流
我有一个通过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);
}
}
}
}
一些不得不通过简单地开始了新的要求,每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代码中的流的锁定,您必须创建自己的流,以管理读写位置分开,并在内部处理锁定。
查看PipeStream
课http://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音讯播放。
写另一个Stream
(子类)围绕从网络摄像头获得的一个,并在原地改变WAV头。它可能工作!
最简单的方法是使用RawSourceWaveStream,然后传入一个已经跳过WAV头的流。