如何从已激活对象获取激活对象?及IMFTransform解码器CLSID获取方法
针对你的两个问题,我结合WMF的实践经验来逐一说明:
1. 从已激活对象中获取激活对象
首先要明确:大部分COM激活对象(比如IMFActivate)的设计是用来创建实例的一次性工具,当你调用IMFActivate::ActivateObject拿到实例后,实例本身通常不会主动保留对激活对象的引用。所以最省心的方式是在创建实例的同时,就把激活对象的指针保存下来,避免后续需要时抓瞎。
如果真的没提前保存,你可以试试这两个办法:
- 直接对已激活对象调用
QueryInterface,看看它是否实现了IMFActivate接口——这种情况很少见,但某些自定义组件可能会这么做。 - 如果对象支持
IServiceProvider接口,先查询到这个接口,再调用QueryService传入SID_SActivateObject服务ID,尝试获取激活对象的引用。不过这也得看组件开发者有没有实现这个服务,不是所有对象都支持。
2. 获取IMFTransform解码器的CLSID(找回激活对象或直接获取)
你遇到的场景很典型:从MediaSource拿到了解码器的IMFTransform实例,但MFT_TRANSFORM_CLSID_Attribute只能从激活对象里拿。这里有两个更靠谱的方案:
方案一:从IMFTransform实例追溯激活对象
先尝试给IMFTransform查询IServiceProvider接口,成功后再通过服务获取激活对象,最后读取CLSID属性。代码示例如下:
IMFActivate* pActivate = nullptr; IServiceProvider* pSP = nullptr; HRESULT hr = pTransform->QueryInterface(IID_PPV_ARGS(&pSP)); if (SUCCEEDED(hr)) { hr = pSP->QueryService(SID_SActivateObject, IID_IMFActivate, reinterpret_cast<void**>(&pActivate)); pSP->Release(); } if (SUCCEEDED(hr) && pActivate != nullptr) { CLSID decoderClsid; hr = pActivate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &decoderClsid); // 这里可以用StringFromGUID2把CLSID转成字符串验证 pActivate->Release(); }
这个方法是WMF中推荐的方式,只要解码器的实现符合规范,大概率能成功。
方案二:拓扑构建阶段提前保存激活对象
如果你是通过MediaSession或拓扑加载器创建的解码器,其实在拓扑解析之前,每个节点对应的都是IMFActivate对象。如果能在那个阶段就把解码器节点的IMFActivate保存下来,后续直接读取属性就行——不过这个方法需要你在代码流程中提前介入拓扑构建,如果你已经走到拿到IMFTransform实例这一步,可能不太适用了。
兜底方案:枚举系统MFT匹配特征
如果上面的方法都失败,你可以用MFTEnumEx枚举系统中所有注册的解码器MFT,然后通过比较当前IMFTransform支持的媒体类型、显示名称等特征,找到对应的CLSID。这个方法比较繁琐,适合前面的方法都走不通的情况。
内容的提问来源于stack exchange,提问作者Chen OT

