0

我正在使用 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 的工作方式不像它应该的那样?

4

1 回答 1

0

问题很简单——那就是 USB 硬件故障。我需要拔下 USB 摄像头并重新插入。

但无论如何,我想分享我对此的了解。

1)我们应该使用异步机制来获取和发送音频数据包到播放端。在第一个缓冲区播放之前,我们必须避免发送新缓冲区进行播放。该方法被称为 - “双重”甚至“三重”缓冲。使用 VFW,您可以使用 WM_CAP_GET_SEQUENCE_SETUP 消息和 CAPTUREPARAMS 结构非常舒适地组织它。wNumAudioRequested 参数用于设置将循环使用多少个不同的缓冲区,以将音频数据发送到您的 audioCallback。默认设置为 10,绰绰有余。

2)检查您的音频信号是否为有效信号的最佳方法是:在您的 WAVESTREAM 回调中,将接收缓冲区中的字节与音频数据编组到托管的静态字节数组中。然后,在回调中,使用 Console.Write(array[i] + " ") 输出 50-100 个样本值,并查看这些值是否随着您的声音上下变化。考虑到零电平位于 WAVEFORMATEX->wBitsPerSample 值的中间,在我的情况下(8 位/样本),值是 125 126 127 128 129。它被接受为静音,没有信号,或零噪声. 一旦你确定你有正确的音频数据,现在你可以进一步实现你的目标。

3) 请记住,当您在麦克风模式下录制时,最好关闭本地输出波形设备。您的目标是收集音频数据以记录或通过网络发送。不要尝试在本地获取数据和 waveOuit。有时你的扬声器的延迟值比采样麦克风数据的速度要高一点,你会弄乱缓冲区,因为它发生在我身上。然后我就遵循了一个原则——“录音是你采集、保存或发送音频数据的时候,应该在录音后或者同时播放,但是在终端PC上播放。

4) 继续代码

于 2015-08-29T02:56:27.683 回答