Справочная информация: Я кодирую буферы NV12 в видеопоток h264, обернутый в контейнер MPEG4, используя SinkWriter. Все работает нормально, но есть одна проблема, так как SinkWriter абстрагирует конфигурации низкоуровневого кодера, я не могу управлять такими свойствами, как размер GOP, количество B-изображений, CODECAPI_AVEncCommonRateControlMode и т. Д. c.
Проблема связано с тем, что SinkWriter создает преобразование кодера только после вызова SetInputMediaType , и мы сможем получить экземпляр CodecAPI только после этой точки , Таким образом, у нас нет возможности управлять кодировщиком и настраивать необходимые реквизиты до того, как все это произойдет, он также никогда не учитывает дальнейшие изменения в кодировщике через экземпляр CodecAPI.
Эксперименты: Я попробовал PropertyStore ( MF_SINK_WRITER_ENCODER_CONFIG ), но, похоже, ничего не меняется (это может быть поведение платформы / кодировщика, определяющее c поведение), я также мог видеть, что многие люди жалуются на непредсказуемое поведение этих API. Затем я наткнулся на эту ветку MSDN (почти 7-летний пост), в которой пользователь описал, как он справился с этой проблемой, локально зарегистрировав фабрику пользовательских классов на машине Windows7.
Проблема: Имея поток MSDN в качестве ссылки, я попытался реализовать IClassFactory и зарегистрировать его через MFTRegisterLocal , но функция CreateInstance никогда не получает позвал меня (Windows 10 автомат). Я получаю только метод QueryInterface, вызываемый для интерфейсов IID_IClassFactory и IID_IMFAttributes. И, похоже, 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);
Буду признателен за любую помощь.