代码之家  ›  专栏  ›  技术社区  ›  user834850

WaveOutWrite直接从Webcam音频捕获回调

  •  0
  • user834850  · 技术社区  · 9 年前

    我使用VFW和音频捕获回调从Webcam捕获音频数据,同时在同一捕获回调的主体内,使用waveOutWrite将采样数据引导到默认MAPPER。

    网络摄像头的信号质量为1通道/8位/11025采样/秒。 默认音频设备支持声音格式,这要归功于 波形打开 具有 格式查询 旗帜

    波形写入 无错误 ,但我能听到的与我的期望相去甚远。房间里很安静,应该听起来像是空虚的白噪音。

    请听声音 YouTube rec

    它开始时,一包一包大小约为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 0 5 0,然后以相同的数字和相同的周期再次上下移动。 不完全相同(+/-)。 此外,我可以使用内置的Windows录音机录制来自摄像头的信号,我可以看到信号电平在我的声音上下跳动,因此网络摄像头的麦克风也可以。。 我想这可能是VFW输入音频信号馈线的问题。 即使它接受了WAVEFORMATEX并发回了WAVEHDR,它们都是正常的……但缓冲区数据是由其他来源填充的,而不是网络摄像头,尽管VFW表示它必须来自网络摄像头,因为视频是从同一来源捕获的,而且它在工作,我只是添加了一条附加消息: 发送消息(camHwnd,WM_CAP_SET_CALLBACK_WAVESTREAM,0,音频回调); 我非常确定如果我使用waveIn而不是VFW,它会正常工作。。 我稍后再检查。。 但为什么VFW的工作方式与预期不同?

    1 回复  |  直到 9 年前
        1
  •  0
  •   user834850 user834850    9 年前

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

    但无论如何,我想分享我的知识。

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

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

    3) 记住,当你从麦克风模式录制时,最好关闭本地输出波设备。您的目标是收集音频数据以录制或通过网络发送。不要尝试获取数据并在本地发送。 有时,扬声器的延迟值比麦克风数据采样的速度稍高,而且缓冲区会变得混乱,就像我的情况一样。 然后我就遵循了这一原则——“录音是当你收集、保存或发送音频数据时,它应该在录音后或同时播放,但要在终端PC上播放。”。

    4) 用代码继续

    推荐文章