通过ICodecAPI为H.264 IMFSinkWriter编码器设置属性

时间:2019-06-03 16:50:49

标签: h.264 video-encoding ms-media-foundation mft

我正在尝试通过检索ICodecAPI接口来调整通过ActivateObject()创建的H.264编码器的属性。 尽管我没有收到任何错误,但我的设置并未考虑在内。

代码在Windows 10下运行。

我复制用于创建IMFSinkWriter的代码,并在下面检索ICodecAPI。错误处理未显示,但没有错误产生。

我已经阅读了thread,这意味着可能无法调整IMFSinkWriter使用的编码器,但是由于MSDN文档中没有声明,我想听听是否有人设法将ICodecAPI与IMFSinkWritter。

如果不可能,将采取什么方式?我需要在H.264中编码并流式传输到MP4。我想更改GOP,Qp,CABAC等,这似乎无法通过输出媒体类型实现。 我应该能够分别创建编码器并将其挂接到MP4文件编写器上吗?任何有关如何做到这一点的指针都表示赞赏...

hr = encoderToOpen.activate->ActivateObject(__uuidof(IMFTransform), (LPVOID *)&encoderTransform);
hr = encoderTransform->GetAttributes(&attributes);
hr = attributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
hr = MFCreateSinkWriterFromURL(fileName, NULL, attributes, &encoder);

// Initialise outputMediaType (code not shown)

hr = encoder->AddStream(outputMediaType, &streamIndex);
hr = encoder->SetInputMediaType(streamIndex, sourceMediaType, NULL);

// Retrieve the ICodecAPI
ICodecAPI *codecApi;
streamIndex = 0;
hr = encoder->GetServiceForStream(streamIndex, GUID_NULL, __uuidof(ICodecAPI), (LPVOID*)&codecApi);

VARIANT v;
hr = codecApi->GetValue(&CODECAPI_AVEncCommonQuality, &v);
v.vt = VT_UI4;
v.ulVal = 8;
hr = codecApi->SetValue(&CODECAPI_AVEncMPVGOPSize, &v);

// Start encoding (code not shown)

1 个答案:

答案 0 :(得分:0)

Media Foundation的Sink Writer是一个简化的API,它消除了编码器配置问题。这里的根本问题是,您不拥有编码器MFT,而是在编写者的头上进行访问,然后在一切都设置好之后,编码器围绕更改设置的行为取决于实现,在这种情况下,编码器是特定于供应商的实现可能会因硬件而异。

您更可靠的选择是直接管理MFT编码,并为Sink Writer提供已经编码的视频。

使工作更轻松的潜在技巧是也检索IMFTransform编码器并清除,然后在完成ICodecAPI更新后重新设置输入/输出媒体类型。忽略媒体类型,建议编码器重新配置内部结构,并且已经进行了微调。请注意,通常来说,这可能会有一些副作用。

  

“技巧”似乎适用于某些ICodecAPI参数(例如,CODECAPIAPI_AVEncCommonQualityVsSpeed),并且仅适用于Microsoft的h.264编码器。对CODECAPI_AVEncH264CABACEn无效。该文档确实确实是专门针对Microsoft的编码器,而不是通用API。我使用的是QuickSync和NVidia编解码器,您是否知道假设我自己创建MFT,是否可以通过ICodecAPI对其进行配置?

供应商提供的编码器符合Certified Hardware Encoder的要求,因此它们必须支持MSDN文章中提到的ICodecAPI值。重要的是,未定义配置调用的顺序。如果您自己管理编码器,则应在设置媒体类型之前进行ICodecAPI设置。在Sink Writer场景中,它已经配置了媒体类型,然后您可以进行微调。因此,我的技巧建议包括重置现有媒体类型的部分。因为此技巧对实现细节敏感,所以我建议获取当前的媒体类型,然后在MFT上清除它们,做ICodecAPI事情,然后再返回类型。我认为这应该在更多方案中起作用,而不仅仅是MS编码器。但是它仍然是不可靠的黑客手段。

IMO Nvidia的编码器实施非常糟糕(各供应商之间最差),Intel的编码器更好,但仍然存在其自身的问题。同样,仅提供IMO MFT来满足硬件视频编码的最低认证要求,因此,它们的实现方式不完全一致。各种软件包都倾向于通过供应商SDK而不是Media Foundation Transform接口来实现视频编码。在其中一个项目中,我曾经还跳过了利用MFT进行编码的想法,而是在供应商SDK之上实现了自己的MFT。

  

本文中的类工厂方法是否与IMFSinkWriter一起使用?这样可以避免编写过多的代码...

我想是的,即使我觉得以这种方式修补它不是一件令人愉快的工作,它也应该起作用。另外,您可能需要考虑对HW编码器的支持,因为Sink Writer在某些情况下也倾向于使用硬件辅助编码,包括使用DXGI设备的情况。

另一种类似的黑客手段,但可能更具侵入性(尽管在实施过程中,您必须更好地了解内部原理)是在Sink Writer初始化范围内重新定义供应商特定的编码器CLSID。只有三种编码器(AMD,Intel,Nvidia;好吧,上海兆鑫半导体公司有第四种编码器,但它并不十分流行),并且它们的CLSID是已知的。如果您以聪明的方式CoRegisterClassObject,则可以挂钩MFT实例,让Media Foundation决定选择哪种编码器。不过,这只是另一个主意,因此它可能取决于其他因素的最佳处理方法。