我正在使用 VFW 和音频捕获回调从网络摄像头捕获音频数据,同时,在同一捕获回调的主体内,使用 waveOutWrite 将采样数据定向到默认 MAPPER。
网络摄像头的信号质量为 1 通道/8 位/11025 个样本/秒。由于带有FORMAT_QUERY标志的waveOpen,默认音频设备支持声音格式。
waveWriteOut的返回是NOERROR,但我能听到的与我的期望相去甚远。房间里很安静,应该是空虚的白噪音。
请听听YouTube 录音
它开始,一个包一个包大小约 16K,WAVEHDR 结构还可以。然后它逐渐减慢并退出系统未恢复错误。
这和什么相似?
下面是来自 VFW 的音频 dta 接收器代码,lpWHdr 看起来不错,甚至内部标志触发为 2 = Prepared .. 似乎 VFW 和 WaveAudio 是相互创建的 :)
public static void capAudioStreamCallback(UIntPtr hWnd, ref WAVE.WAVEHDR lpWHdr) {
Say(String.Format(DateTime.Now.ToString("mm:ss:fff ") + "Received {0} of audio data", lpWHdr.dwBytesRecorded.ToString()));
Application.DoEvents();
WA.WAVEHDR_FLAGS flag = (WA.WAVEHDR_FLAGS) lpWHdr.dwFlags;
if ((WA.WAVEHDR_FLAGS)lpWHdr.dwFlags != WA.WAVEHDR_FLAGS.WHDR_PREPARED)
CheckWAError("waveOutPrepareHeader", WA.waveOutPrepareHeader(phwo, lpWHdr, (uint)Marshal.SizeOf(lpWHdr)));
CheckWAError("waveOutWrite", WA.waveOutWrite(phwo, lpWHdr, (uint)Marshal.SizeOf(lpWHdr)));
CheckWAError("waveOutUnprepareHeader", WA.waveOutUnprepareHeader(phwo, lpWHdr, (uint)Marshal.SizeOf(lpWHdr)));
return;
}
static void CheckWAError(string Func, WA.MMSYSERR err) {
if (err == WA.MMSYSERR.MMSYSERR_BASE_NOERROR) { Say(Func + " WA Ok"); return; }
IntPtr str = Marshal.AllocHGlobal(200);
string s = "";
WA.waveOutGetErrorText(err, str, 200);
s = Marshal.PtrToStringAnsi(str);
Marshal.FreeHGlobal(str);
Say(Func + " err: " + s);
}
我认为缓冲区没有溢出,因为您可以看到 DateTime 毫秒标记,它每 1400 毫秒打勾,采样率 = 11025,缓冲区大小约为 16500 字节 = 看起来不错..
UPD:我只是将非托管缓冲区复制到托管并查看了它的值。看起来像锯齿甚至超载的鼻窦。0 4 0 3 0 32 109 213 255 251 255 243 241 97 0 7 0 2 1 1 0 5 0 然后以大约相同的数字和相同的周期再次上下波动。不完全一样,大致相同(+/-)。此外,我可以使用内部 Windows 记录器记录来自该摄像头的信号,我可以看到信号电平在我的声音上下跳动,所以网络摄像头的麦克风也可以。我想这可能是什么VFW输入音频信号馈线错误。即使它接受了 WAVEFORMATEX 并发回了 WAVEHDR,它们都很好......但是缓冲区数据填充了其他来源,而不是网络摄像头,尽管 VFW 说它必须来自网络摄像头,因为视频是从同一来源捕获的,它正在工作,我只是添加了一条额外消息: SendMessage(camHwnd, WM_CAP_SET_CALLBACK_WAVESTREAM, 0, audioCallback); 我很确定如果我会使用waveIn 而不是VFW,它会正常工作.. 我稍后会检查它.. 但是为什么VFW 的工作方式不像它应该的那样?