IMFTransform SetInputType()/SetOutputType() 失败

IMFTransform SetInputType()/SetOutputType() fails

我正在尝试使用 WASAPI 共享模式和 Windows 上的媒体基础 IMFSourceReader 播放 MP3(和类似的音频文件)。据我所知,我必须在 IMFSourceReader 解码和解码之间使用 IMFTransform WASAPI 回放。除了我在 IMFTransform 上调用 SetInputType()/SetOutputType() 之外,一切似乎都很好?

相关的代码片段是:

MFCreateSourceReaderFromURL(...);   //  Various test mp3 files
...

sourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &reader.audioType);
//sourceReader->GetNativeMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, &reader.audioType);
...

audioClient->GetMixFormat(&player.mixFormat);
...

MFCreateMediaType(&player.audioType);
MFInitMediaTypeFromWaveFormatEx(player.audioType, player.mixFormat, sizeof(WAVEFORMATEX) + player.mixFormat->cbSize);
...




hr = CoCreateInstance(CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&unknown);
ASSERT(SUCCEEDED(hr));

hr = unknown->QueryInterface(IID_PPV_ARGS(&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

我怀疑我误解了如何在事物之间协商 input/output IMFMediaType,以及如何考虑 IMFTransform 需要对未压缩数据进行操作?

输出类型失败对我来说似乎很奇怪,但这可能是输入类型先失败的连锁反应 - 如果我尝试先设置输出类型,它也会失败。

在 Windows 的最新版本中,您可能更愿意利用已经为您准备好的库存功能。

当您配置 Source Reader 对象时,IMFSourceReader::SetCurrentMediaType 允许您指定您想要数据的媒体类型。如果您设置与 WASAPI 要求兼容的媒体类型,Source Reader 会自动添加 transform 为您转换数据。

然而...

Audio resampling support was added to the source reader with Windows 8. In versions of Windows prior to Windows 8, the source reader does not support audio resampling. If you need to resample the audio in versions of Windows earlier than Windows 8, you can use the Audio Resampler DSP.

... 这意味着您确实可能需要自己管理 MFT。 MFT 的输入媒体类型应该来自 IMFSourceReader::GetCurrentMediaType。要指示源 reader 使用未压缩的音频,您需要为这种类型的流构建一个媒体类型解码器,将音频解码为。例如,如果您的文件是 MP3,那么您将读取通道数、采样率并构建兼容的 PCM 媒体类型(或者使用系统解码器并单独询问输出媒体类型,这甚至是一种更简洁的方法)。您可以使用 IMFSourceReader::SetCurrentMediaType 设置此未压缩的音频媒体类型。此媒体类型也将是音频重采样器 MFT 的输入媒体类型。这将指示源 reader 添加必要的解码器,并且 IMFSourceReader::ReadSample 将为您提供转换后的数据。

reasmpler MFT 的输出媒体类型将派生自您从 WASAPI 获得的音频格式,并使用您在代码片段顶部提到的 API 调用进行转换。

要查找错误代码,您可以使用以下命令:

此外,一般来说,您应该能够使用 Media Foundation Media Session API 以更小的努力播放音频文件。媒体会话使用相同的基元来构建播放管道并负责格式调整。

Ah so are you saying I need to create an additional object that is the decoder to fit between the IMFSourceReader and IMFTransform/Resampler?

没有。通过使用适当的媒体类型执行 SetCurrentMediaType,您可以在内部添加 Source Reader 解码器,以便它可以为您提供已经解压缩的数据。从 Windows 8 开始,它也能够在 PCM 风格之间进行转换,但在 Windows 7 中,您需要使用 Audio Resampler DSP 自己处理这个问题。

您可以自己管理解码器,但您不需要这样做,因为来源 Reader 的解码器可以更可靠地完成同样的工作。

您可能需要一个单独的解码器来帮助您猜测 PCM 媒体类型解码器会产生什么,以便您从源 Reader 请求它。 MFTEnumEx正常API看解码器

I am not sure how to decide on or create a suitable decoder object? Do I need to enumerate a list of suitable ones somehow rather than assume specific ones?

提到的 MFTEnumMFTEnumEx API 调用可以枚举解码器,全部可用或按给定条件过滤。

另一种方法是使用部分媒体类型(请参阅此处的相关说明和代码片段:Tutorial: Decoding Audio)。部分媒体类型是关于所需格式的信号,要求媒体基础 API 提供与此部分类型匹配的原语。有关相关讨论链接,请参阅下面的评论。