2

我正在尝试使用 directshow 编写一个 C++ 应用程序,将视频捕获保存到文件中。代码中的步骤是: 1. 创建 Capture Graph Builder 2. 创建 System Device Enumerator 3. 创建 System Device Enumerator - 为了获取捕获过滤器 4. 创建视频捕获类别的枚举器 5. 创建查询捕捉视频

附上代码

// gets the device filter
HRESULT getDeviceFilter(REFCLSID clsid, int order, IBaseFilter **pCap)
{

ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;

// Create the System Device Enumerator.
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
                              CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
                              reinterpret_cast<void**>(&pDevEnum));

if (SUCCEEDED(hr))
{
    // Create an enumerator for the video capture category.
    hr = pDevEnum->CreateClassEnumerator( clsid, &pEnum, 0);
}

IMoniker *pMoniker = NULL;

if (pEnum->Next(1, &pMoniker, NULL) == S_OK)
    hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)pCap);

return hr;
}


int main()
{
IGraphBuilder *pGraph = 0;
ICaptureGraphBuilder2 *pBuild = 0;
IBaseFilter *pCap = 0;
HRESULT hr = CoInitialize(NULL);

// Create the Capture Graph Builder.
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 
                              NULL, 
                              CLSCTX_INPROC_SERVER, 
                                  IID_ICaptureGraphBuilder2, 
                              (void**)&pBuild );


ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;

// Create the System Device Enumerator.
hr = CoCreateInstance(CLSID_SystemDeviceEnum, 
                      NULL,
                      CLSCTX_INPROC_SERVER, 
                      IID_ICreateDevEnum,
                      reinterpret_cast<void**>(&pDevEnum));



IBaseFilter *pMux = 0;
hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
                               L"C:\\Example.avi", // File name.
                               &pMux,              //     Receives a pointer to the mux.
                               NULL);              //     (Optional) Receives a pointer to the file sink.


// gets the first device, VDM tv card
hr = getDeviceFilter(CLSID_VideoInputDeviceCategory, 0, &pCap);


hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, // Pin category.
                          &MEDIATYPE_Video,      // Media type.
                          pCap,                  // Capture filter.
                          NULL,                  // Intermediate filter (optional).
                          pMux);                 // Mux or file sink filter.

// Release the mux filter.
pMux->Release();

IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
    pConfigMux->SetMasterStream(1);
    pConfigMux->Release();
}

return 0;
}

但是,在调用RenderStream 时,我收到E_INVALIDARG错误

有什么建议么?

谢谢

4

1 回答 1

1

看看这个话题。您似乎错过了一些步骤。

首先,您没有pGraph在任何地方使用。您应该创建一个图形管理器,然后通过使用SetFilterGraph为其提供指向图形管理器的指针来初始化图形构建器。

// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
    IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
    // Initialize the Capture Graph Builder.
    pBuild->SetFiltergraph(pGraph);

    // ...
}

其次,您正在使用不受图形管理器管理的过滤器。从这里引用:

在调用该方法之前,必须将 pSource、pIntermediate 和 pSink 指定的所有过滤器添加到图中。

您必须使用AddFilterpCap添加过滤器和pMux您之前创建的图形管理器。您应该在调用 RenderStream 之前执行此操作。之所以如此,是因为 RenderStream 最终会调用管理器上的连接方法。


如果上述步骤不能解决您的问题,您可以尝试其他几种方法。

设备过滤器。您正在使用 的第一个设备CLSID_VideoInputDeviceCategory,但您确定这是正确的设备吗?网络摄像头等也包含在此类别中。确保没有连接其他同类设备,然后重试。

连接。每个设备都是不同的。可能是您的设备无法直接连接到多路复用器。在这种情况下,我们必须找出原因,并确定是否需要连接额外的过滤器(如解码器)。GraphEdit是查找这些过滤器的一种非常快速的方法。

引脚类别/媒体类型。以我的经验,E_INVALIDARG 90% 的时间是由RenderStream. 尝试将 pin 类别或媒体类型设置为NULL

System Device Enumerator:正如您所描述的,您要创建两次系统设备枚举器。这对我来说似乎很奇怪,为什么不同时使用一个呢?


如果您的代码仍然无法正常工作,您应该向我提供更多信息。您在使用GraphEdit时实现了目标吗?您的 VDM 电视卡过滤器看起来如何(引脚、媒体类型)?

于 2012-12-06T12:39:07.413 回答