首页 > 解决方案 > IMFTransform SetInputType()/SetOutputType() 失败

问题描述

我正在尝试在 Windows 7 上使用 WASAPI 共享模式和媒体基础 IMFSourceReader 播放 MP3(和类似的音频文件)。据我了解,我必须在 IMFSourceReader 解码和 WASAPI 播放之间使用 IMFTransform。除了我在 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

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

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

标签: audioms-media-foundationwasapi

解决方案


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

当您配置 Source Reader 对象时,IMFSourceReader::SetCurrentMediaType让您指定您希望数据包含的媒体类型。如果您设置与 WASAPI 要求兼容的媒体类型,Source Reader 将自动添加转换以为您转换数据。

然而...

音频重采样支持已添加到 Windows 8 的源阅读器。在 Windows 8 之前的 Windows 版本中,源阅读器不支持音频重采样。如果您需要在 Windows 8 之前的 Windows 版本中重新采样音频,您可以使用 Audio Resampler DSP。

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

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

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

此外,您通常应该能够使用Media Foundation Media Session API以较小的努力播放音频文件。Media Session 使用相同的原语来构建播放管道并负责格式拟合。

啊,你是说我需要创建一个附加对象,它是解码器以适应 IMFSourceReader 和 IMFTransform/Resampler 之间的关系吗?

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

您可以自己管理解码器,但您不需要这样做,因为 Source Reader 的解码器会更可靠地执行相同的操作。

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

我不确定如何决定或创建合适的解码器对象?我是否需要以某种方式列举合适的列表而不是假设特定的列表?

提到的MFTEnumMFTEnumExAPI 调用可以枚举所有可用的或按给定标准过滤的解码器。

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


推荐阅读