WaveOutWrite прямо из функции обратного вызова для захвата звука с веб-камеры

Я захватываю аудиоданные с веб-камеры, используя VFW и при обратном вызове захвата звука, и в то же время внутри тела того же обратного вызова захвата направляю дискретизированные данные в MAPPER по умолчанию, используя waveOutWrite.

Качество сигнала с веб-камеры: 1 канал / 8 бит / 11025 отсчетов / сек. Звуковой формат поддерживается аудиоустройством по умолчанию благодаря waveOpen с флагом FORMAT_QUERY.

Возвращает waveWriteOut NOERROR, но то, что я слышу, далеко от моих ожиданий. В комнате тихо и должно звучать как белый шум пустоты.

Пожалуйста, слушайте звук YouTube rec

Он запускается, упаковка за упаковкой размером около 16К, структура 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 байт = выглядит как ОК ..

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 работает не так, как положено?


person Community    schedule 26.08.2015    source источник
comment
Возможно, это петля обратной связи. Кроме того, учитывая, что вы записываете из Интернета и загружаете цифро-аналоговый преобразователь, и оба они не обязательно работают с одинаковой скоростью, откуда вы знаете, что у вас нет переполнения или опустошения буфера?   -  person jaket    schedule 26.08.2015
comment
Пожалуйста, смотрите дополнительный UPD   -  person    schedule 26.08.2015


Ответы (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) Помните, что когда вы записываете в микрофонном режиме, локальное выходное волновое устройство лучше закрыть. Ваша цель - собрать аудиоданные для записи или отправки по сети. Не пытайтесь получать данные и волновать их локально. Иногда значение задержки вашего динамика немного превышает скорость выборки данных микрофона, и вы получите беспорядок с буферами, как это произошло со мной. Тогда я просто следовал принципу: «запись - это когда вы собираете, сохраняете или отправляете аудиоданные, и их нужно воспроизводить после записи или одновременно, но на конечном ПК».

4) Продолжение следует кодом

person Community    schedule 29.08.2015