audio - 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 需要对未压缩数据进行操作?
对我来说,输出类型失败似乎很奇怪,但也许这是输入类型首先失败的连锁反应 - 如果我尝试先设置输出类型,它也会失败。
解决方案
在最新版本的 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。
我不确定如何决定或创建合适的解码器对象?我是否需要以某种方式列举合适的列表而不是假设特定的列表?
提到的MFTEnum
,MFTEnumEx
API 调用可以枚举所有可用的或按给定标准过滤的解码器。
另一种方法是使用部分媒体类型(请参阅此处的相关说明和代码片段:教程:解码音频)。部分媒体类型是有关所需格式的信号,要求媒体基础 API 提供与此部分类型匹配的原语。有关相关讨论链接,请参阅下面的评论。
推荐阅读
- git - 如何从 Docker 容器克隆 Git 存储库
- sql - 当存储过程没有输入参数时 sp_getapplock 正在工作
- python - 在具有入口点的应用程序上使用 cProfile
- redisearch - Redisearch ft.mget 命令对单个查询中的文档 ID 数量是否有限制?
- reactjs - Reactjs 中的 Lodash/FP 选择
- django - 将多个复选框 POST 值放入 django 视图
- python-3.7 - AttributeError:模块“os”没有属性“getcwd”?
- swift - 在 UITabBarController 中的 tabBar 和 Navigation 视图之间添加 UIView
- html - 模态正文文本流出 - 自动换行不起作用
- python - Python 中的 JSON 导入