#audio #ms-media-foundation #wasapi
#Аудио #ms-media-foundation #wasapi
Вопрос:
Я пытаюсь воспроизвести MP3 (и аналогичные аудиофайлы), используя общий режим WASAPI и media foundation IMFSourceReader в Windows 7. Насколько я понимаю, я должен использовать IMFTransform между декодированием IMFSourceReader и воспроизведением WASAPI. Кажется, все в порядке, кроме того, когда я вызываю setInputType() / SetOutputType() в IMFTransform?
Соответствующие фрагменты кода:
MFCreateSourceReaderFromURL(...); // Various test mp3 files
...
sourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, amp;reader.audioType);
//sourceReader->GetNativeMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, amp;reader.audioType);
...
audioClient->GetMixFormat(amp;player.mixFormat);
...
MFCreateMediaType(amp;player.audioType);
MFInitMediaTypeFromWaveFormatEx(player.audioType, player.mixFormat, sizeof(WAVEFORMATEX) player.mixFormat->cbSize);
...
hr = CoCreateInstance(CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)amp;unknown);
ASSERT(SUCCEEDED(hr));
hr = unknown->QueryInterface(IID_PPV_ARGS(amp;resampler.transform));
ASSERT(SUCCEEDED(hr));
unknown->Release();
hr = resampler.transform->SetInputType(0, inType, 0);
ASSERT(hr != DMO_E_INVALIDSTREAMINDEX);
ASSERT(hr != DMO_E_TYPE_NOT_ACCEPTED);
ASSERT(SUCCEEDED(hr)); // Fails here with hr = 0xc00d36b4
hr = resampler.transform->SetOutputType(0, outType, 0);
ASSERT(hr != DMO_E_INVALIDSTREAMINDEX);
ASSERT(hr != DMO_E_TYPE_NOT_ACCEPTED);
ASSERT(SUCCEEDED(hr)); // Fails here with hr = 0xc00d6d60
Я подозреваю, что я неправильно понимаю, как согласовывать ввод / вывод IMFMediaType между вещами, а также как учитывать, что IMFTransform должен работать с несжатыми данными?
Мне кажется странным, что тип вывода завершается ошибкой, но, возможно, это связано с тем, что сначала происходит сбой типа ввода, и если я попытаюсь сначала установить тип вывода, он также завершится неудачей.
Ответ №1:
В последних версиях Windows вы, вероятно, предпочли бы воспользоваться стандартной функциональностью, которая уже есть для вас.
При настройке объекта Source Reader IMFSourceReader::SetCurrentMediaType
позволяет указать тип носителя, в котором вы хотите использовать свои данные. Если вы установите тип носителя, совместимый с требованиями WASAPI, программа чтения исходных текстов автоматически добавит преобразование для преобразования данных для вас.
Однако…
Поддержка передискретизации звука была добавлена в программу чтения исходных текстов с Windows 8. В версиях Windows, предшествующих Windows 8, программа чтения исходных текстов не поддерживает передискретизацию звука. Если вам нужно выполнить повторную выборку звука в версиях Windows, более ранних, чем Windows 8, вы можете использовать DSP для повторной выборки звука.
… это означает, что вам действительно может потребоваться управлять MFT самостоятельно. Предполагается, что тип входного носителя для MFT поступает из IMFSourceReader::GetCurrentMediaType
. Чтобы указать читателю исходного кода использовать несжатый звук, вам необходимо создать декодер типа мультимедиа для этого типа потока, в который будет декодироваться аудио. Например, если ваш файл имеет формат MP3, тогда вы должны прочитать количество каналов, частоту дискретизации и создать совместимый тип носителя PCM (или взять системный декодер и запросить его отдельно для типа выходного носителя, что даже более чистый способ). Вы бы установили этот тип несжатого аудионосителя с помощью IMFSourceReader::SetCurrentMediaType
. Этот тип носителя также будет вашим типом входного носителя для MFT с повторной выборкой звука. Это даст указание читателю исходного кода добавить необходимые декодеры и IMFSourceReader::ReadSample
предоставит вам преобразованные данные.
Тип выходного носителя для reasmpler MFT будет получен из аудиоформата, полученного из WASAPI и преобразованного с помощью вызовов API, которые вы упомянули в верхней части вашего фрагмента кода.
Для поиска кодов ошибок вы можете использовать это:
Кроме того, вы, как правило, должны иметь возможность воспроизводить аудиофайлы с помощью Media Foundation Media Session API с меньшими усилиями. Сеанс мультимедиа использует те же примитивы для построения конвейера воспроизведения и обеспечивает подгонку формата.
Ах, так вы говорите, что мне нужно создать дополнительный объект, который является декодером, чтобы он помещался между IMFSourceReader и IMFTransform / Resampler?
Нет. SetCurrentMediaType
При использовании правильного типа носителя у вас есть программа чтения исходного кода, добавляющая декодер внутри, чтобы он мог предоставить вам уже распакованные данные. Начиная с Windows 8, он также способен выполнять преобразование между вариантами PCM, но в Windows 7 вам нужно позаботиться об этом самостоятельно с помощью передискретизации звука DSP.
Вы можете управлять декодером самостоятельно, но вам это не нужно, поскольку декодер исходного кода будет делать то же самое более надежно.
Возможно, вам понадобится отдельный декодер, чтобы помочь вам угадать, что будет выдавать декодер PCM media type, чтобы вы запросили его у Source Reader. MFTEnumEx
это правильный API для поиска декодера.
Я не уверен, как выбрать или создать подходящий объект декодера? Нужно ли мне каким-то образом перечислять список подходящих, а не предполагать конкретные?
Упомянутые MFTEnum
MFTEnumEx
вызовы API могут перечислять декодеры, как все доступные, так и отфильтрованные по заданным критериям.
Еще один способ — использовать частичный тип носителя (см. Соответствующее объяснение и фрагмент кода здесь: Учебное пособие: декодирование аудио). Частичный тип носителя — это сигнал о желаемом формате, запрашивающий, чтобы API Media Foundation предоставил примитив, соответствующий этому частичному типу. Соответствующие ссылки для обсуждения см. В комментариях ниже.
Комментарии:
1. Ах, так вы говорите, что мне нужно создать дополнительный объект, который является декодером, чтобы он помещался между IMFSourceReader и IMFTransform / Resampler? Я хотел создать его на самом низком уровне, чтобы я мог также получить доступ к несжатым аудиоданным по мере их эффективной передачи — вот почему я не смотрел на API сеанса (плюс это немного сбивает с толку, что возможно где!).).
2. Я все еще в замешательстве после прочтения: learn.microsoft.com/en-us/windows/win32/medfound /. … Поскольку я не уверен, как выбрать или создать подходящий объект декодера? Нужно ли мне каким-то образом перечислять список подходящих, а не предполагать конкретные? Я вижу пример в документах с конкретным CLSID_CWMV9EncMediaObject (но, очевидно, я хочу декодировать). Я не уверен, как бы я «взял системный декодер и отдельно запросил его для типа выходного носителя»?
3. Я думаю, что это был шаг, который я пропустил: learn.microsoft.com/en-us/windows/win32/api/mfapi /… , и, возможно, некоторая информация о топологических соединениях здесь: learn.microsoft.com/en-us/windows/win32/medfound /…
4. Это оказалось весьма полезным: codeproject.com/Articles/501521 /…
5. Использование MFTEnumEx() Я могу найти 1 декодер для MFAudioFormat_AAC в PCM / float, но ничего для MP3 на моем ПК с Win7. Нет ли декодера MP3 по умолчанию для Win7? Тем временем я попытаюсь собрать его воедино вокруг теста AAC и отчитаться, чтобы помочь сформировать более полный ответ