WaveOutWrite прямо с обратного вызова захвата аудио с веб-камеры
Я снимаю аудиоданные с веб-камеры, используя VFW и Callback для захвата звука, и в то же время внутри тела того же Callback для захвата перенаправляю данные выборки в MAPPER по умолчанию, используя waveOutWrite.
Качество сигнала с веб-камеры составляет 1 канал /8 бит /11025 выборок / сек. Формат звука поддерживается аудиоустройством по умолчанию, благодаря waveOpen с флагом FORMAT_QUERY.
Возвращение waveWriteOut - NOERROR, но то, что я слышу, далеко от моих ожиданий. В комнате тихо и должно звучать как белый шум пустоты.
Просьба послушать звук YouTube Rec
Начинается, упаковка за упаковку размером около 16K, структура WAVEHDR в порядке. Затем он постепенно замедляется и завершается с ошибкой системы.
На что это похоже?
Ниже приведен код приемника аудио dta из VFW, и визуально lpWHdr идет нормально. Даже внутренний флаг срабатывает в виде 2 = Подготовлено.. похоже, что 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 байт = выглядит как Ok..
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 работает не так, как предполагалось?
1 ответ
Проблема была очень простой - аппаратный сбой USB. Мне нужно было отключить USB-камеру и подключить снова.
Но в любом случае, я хотел бы поделиться своими знаниями об этом.
1) Мы должны использовать асинхронный механизм получения и отправки пакетов аудиоданных в конец воспроизведения. Пока первый буфер не будет воспроизведен, мы должны избегать отправки нового буфера для воспроизведения. Метод называется - "двойная" или даже "тройная" буферизация. А с VFW вы можете организовать его очень удобно, используя сообщение WM_CAP_GET_SEQUENCE_SETUP и структуру CAPTUREPARAMS. Параметр wNumAudioRequested используется для установки количества циклически используемых различных буферов для отправки аудиоданных на ваш audioCallback. По умолчанию установлено 10, более чем достаточно.
2) Лучший способ проверить, является ли ваш аудиосигнал действительным сигналом: в обратном вызове WAVESTREAM выполните маршалинг байтов из полученного буфера с аудиоданными в управляемый статический массив байтов. Затем, внутри обратного вызова, выведите 50-100 выборочных значений с помощью Console.Write(array[i] + " ") и посмотрите, изменяются ли значения в вашем голосе вверх и вниз. Учтите, что нулевой уровень находится в середине значения WAVEFORMATEX->wBitsPerSample, а в моем случае (8 бит / выборка) значения равны 125 126 127 128 129. Он принимается как тишина, без сигнала или как нулевой шум, Если вы уверены, что у вас есть правильные аудиоданные, теперь вы можете пойти дальше к своей цели.
3) Помните, что при записи в режиме микрофона локальное выходное волновое устройство лучше закрывать. Ваша цель - собрать аудиоданные для записи или отправки через сеть. Не пытайтесь получать данные и WaveOuit их локально. Иногда значение задержки вашего динамика немного выше, чем скорость выборки данных с микрофона, и вы получите беспорядок с буферами, как это произошло со мной. Тогда я просто следовал принципу - "запись - это когда вы собираете, сохраняете или отправляете аудиоданные, и они должны воспроизводиться после записи или одновременно, но на компьютере конечной точки".
4) Продолжение с кодом