Media Foundation播放MP3失败:COM新手的代码问题排查请求
Media Foundation播放MP3失败的问题排查
我是COM和Windows编程新手,尝试用Media Foundation播放MP3文件。以下是在Windows 10上运行的代码,执行步骤包括:初始化COM、启动Media Foundation、通过源解析器创建媒体源、创建MP3解码器MFT、创建音频媒体激活对象、创建音频媒体接收器、创建拓扑、添加三个拓扑节点(媒体源、MP3解码器、音频媒体接收器)、将节点加入拓扑、创建媒体会话并设置拓扑、启动会话、释放COM对象、关闭Media Foundation、反初始化COM。但文件无法播放,求指出代码问题。
// ConsoleApplication1.cpp : This file contains the 'main' function. Program execution begins and ends there. // #include <iostream> #include <mfapi.h> #include <mfidl.h> #include <mfreadwrite.h> #include <Wmcodecdsp.h> #include <combaseapi.h> #include <mferror.h> #include <tchar.h> #include <evr.h> int main() { HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { std::cout << "cannot initilize COM"; } // Initialize the Media Foundation platform. hr= MFStartup(MF_VERSION); if (FAILED(hr)) { std::cout << "cannot initilize MF"; } MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID; IMFSourceResolver* pSourceResolver; IUnknown* pSource = nullptr; IMFMediaSource* mSource; IMFPresentationDescriptor* ppPresentationDescriptor; IMFTransform* mtransform = NULL; IMFTopology* topology = NULL; IMFStreamDescriptor* sdesip = NULL; IMFTopologyNode* source = NULL; IMFTopologyNode* transform; IMFTopologyNode* output = NULL; IMFMediaSink* mediasink = NULL; IMFMediaTypeHandler* mediatypehandler; IMFMediaType* mediatype; IMFMediaType* decodermediatype; IMFMediaSession* mediasession; DWORD streamdesip; hr = MFCreateSourceResolver(&pSourceResolver); if (FAILED(hr)) { std::cout << "cannot create source resolver"; } hr = pSourceResolver->CreateObjectFromURL( L"song.mp3", // URL of the source. MF_RESOLUTION_MEDIASOURCE, // Create a source object. NULL, // Optional property store. &ObjectType, // Receives the created object type. &pSource // Receives a pointer to the media source. ); if (FAILED(hr)) { std::cout << "media source"; } hr = pSource->QueryInterface(IID_PPV_ARGS(&mSource)); if (FAILED(hr)) { std::cout << "media source interface"; } hr = mSource->CreatePresentationDescriptor(&ppPresentationDescriptor); if (FAILED(hr)) { std::cout << "presentation discriptor"; } ppPresentationDescriptor->SelectStream(0); hr = CoCreateInstance(__uuidof(CMP3DecMediaObject), NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, (void**)&mtransform); if (FAILED(hr)) { std::cout << "Decoder"; } hr = MFCreateTopology( &topology ); if (FAILED(hr)) { std::cout << "topology"; } hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &source); if (FAILED(hr)) { std::cout << "source topology node"; } hr = source->SetUnknown(MF_TOPONODE_SOURCE, mSource); if (FAILED(hr)) { std::cout << "source set to topology node"; } hr = source->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, ppPresentationDescriptor); if (FAILED(hr)) { std::cout << "desciption set to topology node"; } BOOL value; hr = ppPresentationDescriptor->GetStreamDescriptorByIndex(0, &value, &sdesip); if (FAILED(hr)) { std::cout << "stream desciption get"; } sdesip->GetStreamIdentifier(&streamdesip); hr = sdesip->GetMediaTypeHandler(&mediatypehandler); if (FAILED(hr)) { std::cout << "media handler"; } hr= mediatypehandler->GetCurrentMediaType(&mediatype); if (FAILED(hr)) { std::cout << "current media type"; } hr = source->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, sdesip); if (FAILED(hr)) { std::cout << "set stream desiptor"; } hr = topology->AddNode(source); if (FAILED(hr)) { std::cout << "add source node"; } hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &transform); if (FAILED(hr)) { std::cout << "transform node"; } hr = MFCreateMediaType(&decodermediatype); if (FAILED(hr)) { std::cout << "decoder media type"; } mediatype->CopyAllItems(decodermediatype); if (FAILED(hr)) { std::cout << "set major type"; } hr = decodermediatype->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM); if (FAILED(hr)) { std::cout << "set sub type"; } hr = mtransform->SetInputType(0, mediatype, NULL); if (SUCCEEDED(hr)) { } IMFMediaType* newmediatype; hr = MFCreateMediaType(&newmediatype); if (FAILED(hr)) { std::cout << "unable to create"; } hr = mtransform->GetOutputAvailableType(0, 1, &newmediatype); if (FAILED(hr)) { std::cout << "nodata"; } hr = mtransform->SetOutputType(0, newmediatype, 0); if (FAILED(hr)) { std::cout << "output"; } hr = transform->SetObject(mtransform); if (FAILED(hr)) { std::cout << "set transform node"; } hr = topology->AddNode(transform); if (FAILED(hr)) { std::cout << "add trasnform node"; } IMFActivate* active; hr = MFCreateAudioRendererActivate(&active); if (FAILED(hr)) { std::cout << "active object"; } hr = active->ActivateObject(__uuidof(IMFMediaSink), (void**)&mediasink); if (FAILED(hr)) { std::cout << "media sink"; } hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &output); if (FAILED(hr)) { std::cout << "output node topology"; } IMFStreamSink* streamsink; hr = mediasink->GetStreamSinkByIndex(0, &streamsink); if (FAILED(hr)) { std::cout << "get stream sink"; } hr = output->SetObject(streamsink); if (FAILED(hr)) { std::cout << "set out put node"; } hr = output->SetUINT32(MF_TOPONODE_STREAMID, 0); if (FAILED(hr)) { std::cout << "uint set"; } hr = output->SetUINT32(MF_TOPOLOGY_NOSHUTDOWN_ON_REMOVE, FALSE); if (FAILED(hr)) { std::cout << "uint set"; } hr = topology->AddNode(output); if (FAILED(hr)) { std::cout << "add topo node output"; } hr = source->ConnectOutput(0, transform, 0); if (FAILED(hr)) { std::cout << "connect source"; } hr = transform->ConnectOutput(0, output, 0); if (FAILED(hr)) { std::cout << "connect output"; } hr = MFCreateMediaSession( NULL, &mediasession ); if (FAILED(hr)) { std::cout << "create media session"; } hr = mediasession->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, topology); if (FAILED(hr)) { std::cout << "fail to set topology"; } PROPVARIANT var; PropVariantInit(&var); hr = mediasession->Start(&GUID_NULL, &var); if (FAILED(hr)) { std::cout << "media session start"; } pSourceResolver->Release(); pSource->Release(); mSource->Release(); ppPresentationDescriptor->Release(); mtransform->Release(); topology->Release(); sdesip->Release(); source->Release(); transform->Release(); output->Release(); mediatypehandler->Release(); mediatype->Release(); decodermediatype->Release(); mediasession->Release(); mediasink->Release(); MFShutdown(); CoUninitialize(); }
代码中的核心问题
1. 程序立即退出,未等待播放完成
启动媒体会话后,代码立刻释放所有COM对象并终止程序,Media Foundation的异步播放逻辑还没来得及执行就被中断。需要添加等待机制:
- 注册媒体会话事件(如
MESessionEnded),用事件对象等待播放结束; - 或者添加消息循环(Media Foundation依赖消息泵处理异步操作),示例:
MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
2. COM初始化方式错误
CoInitialize(NULL)默认使用单线程单元(STA),而Media Foundation推荐使用多线程单元(MTA),应替换为:
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
STA环境下,Media Foundation的异步回调可能无法正常触发,导致播放流程停滞。
3. 错误处理不严谨
多个步骤的HRESULT检查仅输出字符串,但未终止后续流程。比如COM初始化失败后仍执行MFStartup,会引发连锁错误。应该在FAILED(hr)时直接退出,示例:
if (FAILED(hr)) { std::cout << "cannot initialize COM"; return -1; }
4. 媒体类型协商不完整
解码器输出类型与音频接收器输入类型未确保完全兼容:
- 直接使用解码器的
GetOutputAvailableType获取类型,但未验证该类型是否被音频接收器支持; - 正确做法是先获取音频接收器的媒体类型处理器,枚举其支持的类型,再选择与解码器输出兼容的类型设置给解码器。
5. 对象释放时机错误
在媒体会话运行时就释放了mediasession、topology等核心对象,导致Media Foundation内部操作失效。必须等待播放完成(收到MESessionEnded事件)后,再依次释放所有对象。
内容的提问来源于stack exchange,提问作者Khur
相关产品推荐
相关产品推荐

