2

我编写了一个小型变换过滤器(派生自 TransInPlaceFilter 基类),并设法使其在 Directshow 图中正常工作,完全用 C++ 编码。我基本上遵循了MSDN上描述的 5 个第一步,以及第 6 步的最后一部分(为了在应用程序中直接使用过滤器)。

由于很多原因(包括能够在 GraphEdit 中使用过滤器),我需要将该过滤器导出到 DLL 中并进行注册。

我一直在尝试遵循这些步骤:设置“CreateInstance”方法、CFactoryTemplate 类、过滤器/引脚描述(AMOVIESETUP_FILTER、AMOVIESETUP_PIN、AMOVIESETUP_MEDIA)、注册/取消注册函数,最后是 DLLmain/入口点。

该代码成功编译并提供了一个 DLL,使用 Regsvr32 似乎可以毫无问题地注册。

但后来我无法使用过滤器:

  • 它出现在 GraphEdit 的列表中,但是当我尝试插入它时失败:0x800401f9(“DLL 中的错误”)。
  • 当我尝试在 C++ 中创建它时(使用pCustomFilter.CoCreateInstance(CLSID_Custom),在定义正确的 GUID 之后),我收到错误 0x80040154 (REGDB_E_CLASSNOTREG)

我在这里很困惑。我是否错过了 DLL/注册代码中的某些内容?如果有任何用处,我将发布我正在使用的大部分代码。

任何帮助将不胜感激。

static const WCHAR g_wszName[] = L"Custom Filter";

AMOVIESETUP_MEDIATYPE sudMediaTypes[] = {
    { &MEDIATYPE_Video, &MEDIASUBTYPE_NULL },
    { &MEDIATYPE_Audio, &MEDIASUBTYPE_NULL },
};

AMOVIESETUP_PIN sudPins[2] = {
    {
        L"Input",            // Name
        FALSE,          // Is this pin rendered?
        FALSE,          // Is it an output pin?
        FALSE,          // Can the filter create zero instances?
        FALSE,          // Does the filter create multiple instances?
        &GUID_NULL,     // Obsolete.
        NULL,           // Obsolete.
        2,              // Number of media types.
        sudMediaTypes   // Pointer to media types.
    },
    {
        L"Output",            // Name
        FALSE,          // Is this pin rendered?
        TRUE,           // Is it an output pin?
        FALSE,          // Can the filter create zero instances?
        FALSE,          // Does the filter create multiple instances?
        &GUID_NULL,     // Obsolete.
        NULL,           // Obsolete.
        2,              // Number of media types.
        sudMediaTypes   // Pointer to media types.
    }
};

AMOVIESETUP_FILTER sudFilterReg = {
    &CLSID_Custom,          // Filter CLSID.
    g_wszName,              // Filter name.
    MERIT_DO_NOT_USE,       // Merit.
    2,                      // Number of pin types.
    sudPins             // Pointer to pin information.
};


CFactoryTemplate g_Templates[] = 
{
  { 
    g_wszName,
    &CLSID_Custom,
    CCustomFilter::CreateInstance,
    NULL,
    &sudFilterReg
  }
};

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

STDAPI DllRegisterServer()
{
    return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
    return AMovieDllRegisterServer2( FALSE );
}


extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
{
    return DllEntryPoint(reinterpret_cast<HINSTANCE>(hDllHandle), dwReason, lpReserved);
}

// ---
// Meanwhile, in my filter class...
// ---
CUnknown * WINAPI CCustomFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
    CCustomFilter *pFilter = new CCustomFilter();
    if (pFilter== NULL) 
    {
        *pHr = E_OUTOFMEMORY;
    }
    return pFilter;
}
4

3 回答 3

3

问题解决了。这实际上是两件事:

  1. 直接调试 DLL(我没有想到的东西......),更具体地说是 CoCreateInstance 函数,帮助我注意到字符串宏的问题。TransInPlaceFilter 的构造函数被调用时使用了错误的参数,这导致了崩溃。

  2. 有人让我注意到我没有导出所有必需的功能(如MSDN 上所述)。我的 .def 文件缺少 DllMain、DllGetClassObject 和 DllCanUnloadNow。最后两个函数只需要出现在 def 中,因为它们已经在基类库中定义了。

`

LIBRARY "custom_filter"
EXPORTS
    DllMain                 PRIVATE /* missing */
    DllGetClassObject       PRIVATE /* missing */
    DllCanUnloadNow         PRIVATE /* missing */
    DllRegisterServer       PRIVATE
    DllUnregisterServer     PRIVATE

非常感谢你的帮助 !

于 2011-02-14T10:17:02.233 回答
1

要检查的一件事是 GUID 在任何地方都相同:AMOVIESETUP_FILTER、CFactoryTemplate 并传递给 CTransInPlaceFilter 构造函数。

此外,最好将 CCustomFilter::CreateInstance 的 pUnk 和 pHr 参数传递给 CCustomFilter 构造函数,然后从那里传递给 CTransInPlaceFilter 构造函数,这样任何错误都可以传播给调用者。在您的情况下,任何此类错误都会被您的构造函数吞噬。例子:

CUnknown* WINAPI FramerateDisplayFilter::CreateInstance(LPUNKNOWN pUnk, 
                                                        HRESULT *pHr )
{
  FramerateDisplayFilter *pFilter = new FramerateDisplayFilter(pUnk, pHr);
  if (pFilter== NULL) 
  {
    *pHr = E_OUTOFMEMORY;
  }
  return pFilter;
}


FramerateDisplayFilter::FramerateDisplayFilter(LPUNKNOWN pUnk, HRESULT *pHr)
: CTransInPlaceFilter(NAME("CSIR RTVC Framerate Estimator Filter"), pUnk,   
                      CLSID_RTVCFramerateEstimatorFilter, pHr, false),
  m_uiEstimatedFramerate(0),
  m_bSeenFirstFrame(false),
  m_previousTimestamp(0)
{;}
于 2011-02-12T12:43:15.373 回答
0

您是否确认写入了正确的注册表项?

CoCreateInstance 的注册表项与筛选器枚举的项不同,因此筛选器可能出现在 GraphEdit 的筛选器列表中,但 CoCreateInstance 失败。

http://msdn.microsoft.com/en-us/library/dd390639(v=VS.85).aspx

于 2011-02-13T05:04:10.537 回答