背景:我正在使用SinkWriter将NV12缓冲区编码为包装在MPEG4容器中的h264视频流。一切正常,但是有一个问题,因为SinkWriter抽象了低级编码器配置,我无法控制GOP大小,B图片计数,CODECAPIAPI_AVEncCommonRateControlMode等属性。
问题是由于SinkWriter仅在SetInputMediaType调用之后实例化编码器转换,并且只有在此之后,我们才能获得CodecAPI实例。因此,我们无法在所有这些事情发生之前控制编码器并配置必要的道具,它也永远不会支持通过CodecAPI实例对编码器做进一步的更改。
实验:我尝试了PropertyStore(MF_SINK_WRITER_ENCODER_CONFIG)方法,但似乎没有任何变化(可能是特定于平台/编码器的行为),我还可以看到很多人抱怨这些API的行为不可预测。然后,我遇到了this MSDN线程(将近7年的帖子),用户在其中描述了他如何通过在Windows7计算机上本地注册自定义类工厂来处理此问题。
问题:以the MSDN thread为参考,我尝试实现IClassFactory并通过MFTRegisterLocal注册它,但从未为我调用CreateInstance函数(Windows 10计算机)。我只得到了为IID_IClassFactory和IID_IMFAttributes接口调用的QueryInterface方法。而且,SinkWriter似乎正在继续自行获取MFT。
我知道我可能做错了什么,而且我不是COM方面的专家。我还有其他方法可以实现这一目标吗?
自定义类工厂实现:
class MyClassFactory : public IClassFactory {
public:
MyClassFactory () : _cRef(1) {}
~MyClassFactory() {}
// Only this method is getting called
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
HRESULT hr = E_NOTIMPL;
// Only the below 2 cases (IID_IClassFactory and IID_IMFAttributes) are getting hit
if (IID_IClassFactory == riid)
{
*ppv = static_cast<IClassFactory*>(this);
if (*ppv) {
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
}
hr = S_OK;
}
else if (IID_IMFAttributes == riid)
{
if (!pEncoder) {
hr = FindEncoderEx(&pEncoder);
}
IMFAttributes *attributes;
hr = pEncoder->GetAttributes(&attributes);
*ppv = attributes;
}
else
{
//This case has never been reached
}
return hr;
}
//This is never called
STDMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv)
{
HRESULT hr = S_OK;
if (pUnkOuter != NULL)
{
if (riid != __uuidof(IUnknown))
{
return E_NOINTERFACE;
}
}
if (!pEncoder) {
hr = FindEncoderEx(&pEncoder);
}
hr = pEncoder->QueryInterface(riid, ppv);
return hr;
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
assert(_cRef > 0);
LONG cRef = InterlockedDecrement(&_cRef);
if (!cRef)
delete this;
return cRef;
}
STDMETHODIMP LockServer(BOOL fLock)
{
if (fLock)
{
AddRef();
}
else {
Release();
}
return S_OK;
}
HRESULT FindEncoderEx(IMFTransform** ppEncoder)
{
...
}
protected:
LONG _cRef;
CComPtr<IMFTransform> pEncoder = NULL;
};
注册自定义类工厂:
MyClassFactory* cf = new MyClassFactory();
MFT_REGISTER_TYPE_INFO infoInput = { MFMediaType_Video, MFVideoFormat_NV12 };
MFT_REGISTER_TYPE_INFO infoOutput = { MFMediaType_Video, MFVideoFormat_H264 };
MFTRegisterLocal(cf, MFT_CATEGORY_VIDEO_ENCODER, L"MyClassFactory", 0, 1, &infoInput, 1, &infoOutput);
任何帮助将不胜感激。
您在这里如履薄冰,是因为您尝试做的事情不应该起作用。您可以(或至少可以)注册本地转换,但API通常会比其他现有MFT更喜欢您的其他MFT,因为它们具有更高的内部价值(并且具有硬件辅助支持),因此不希望您覆盖现有行为。
您的实际选择是:
MF_SINK_WRITER_ENCODER_CONFIG
attribute通过编码器特定配置