我想将预览视频从图像传感器流式传输到我的电脑。
稍后,我想添加自定义过滤器。

首先,我使用Amcap来获取预览视频。工作正常。
但是我希望我的项目基于playcap(而不是像amcap一样复杂)。
当我启动playcap时,它会检测到设备,但是仅显示黑屏。

在这两个示例中,我都没有修改代码。
有谁知道如何解决这个问题?
也许有人能描述我如何为amcap添加自定义过滤器。
Samplecgb部分在amcap中起什么作用?

敬上,
阿佛

最佳答案

我将尝试提炼以下创建捕获图的步骤。这是一个复杂的过程,通常有多种方法可以完成大多数步骤,因此您必须从此处进行自己的研究并提出具体问题。

在下面的代码段中,我将使用_com_ptr_t smart pointers,它是使用_COM_SMARTPTR_TYPEDEF(IGraphBuilder, __uuidof(IGraphBuilder))宏定义的。因此,请定义IGraphBuilderPtr,您将执行以下操作:

_COM_SMARTPTR_TYPEDEF(IGraphBuilder, __uuidof(IGraphBuilder))
// which defines IGraphBuilderPtr


您将始终需要一张图,因此第一步非常通用:

IGraphBuilderPtr graph;
graph.CreateInstance(CLSID_FilterGraph);


然后,如果要构建捕获图,则很可能需要使用以下界面:

ICaptureGraphBuilder2Ptr cg;
cg.CreateInstance(CLSID_CaptureGraphBuilder2);
cg->SetFiltergraph(graph);


之后,您需要向该图添加一个或多个输入源。您需要找到将图像传感器包装为视频捕获设备的过滤器,并将其添加到图形中。
这将是一个多步骤的过程,可能需要执行以下操作:

枚举所有视频捕获设备:

IBaseFilterPtr fVideoInput;  // will hold the video input source

ICreateDevEnumPtr pCreate(CLSID_SystemDeviceEnum);
IEnumMonikerPtr pEnum;
HRESULT hr = pCreate->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
                                            &pEnum,
                                            0);
if (hr == S_OK)
{
    IMonikerPtr pMon;
    while (pEnum->Next(1, &pMon, NULL) == S_OK)
    {
        // inspect the moniker of each devices to determine if it's the one you're after
        // if it's the right device, then..

        HRESULT hr = mon->BindToObject(NULL,
                                       NULL,
                                       __uuidof(IBaseFilter),
                                       (void**)&fVideoInput);
    }
}


一旦有了视频输入滤波器的接口,就必须枚举它的引脚,并找到正确的输出引脚以将图形的其余部分连接到该引脚。这可以很简单,例如枚举所有引脚并选择第一个输出引脚(如果只有一个),或者枚举所有引脚并查询每个输出引脚的介质类型,然后以这种方式选择正确的引脚,或者调用FindPin的引脚名称(并且始终相同)。下面是枚举引脚并选择第一个输出的示例:

IEnumPinsPtr pEnum;
fVideoInput->EnumPins(&pEnum);
IPinPtr pin;
while (pEnum->Next(1, &pin, NULL) == S_OK)
{
    PIN_DIRECTION dir;
    pin->QueryDirection(&dir);
    if (dir == PINDIR_OUTPUT)
    {
         // this is the first output pin
         break;
    }
}


一旦有了输出引脚,就可以插入另一个滤波器,找到合适的引脚(与上面类似,但要寻找输入引脚),然后使用以下方法直接连接两个引脚:

// assuming pinOut is an output pin
//    and pinIn is an input pin, this method will try to connect them
HRESULT hr = graph->Connect(pinOut, pinIn);


或者,您可以尝试简单地渲染图钉:

hr = graph->Render(pinOut);


这是在图形中插入自定义过滤器的示例。如果过滤器已经在系统中注册(它显示在GraphEdit的列表中),那么您只需要知道过滤器的类ID。这是一个GUID,可以唯一地标识过滤器,如果您还不知道它,则可以使用GraphEdit找到它(创建新图,插入自定义过滤器,右键单击并查看属性,应该有过滤器):

IBaseFilterPtr fCustomFilter;
fCustomFilter.CreateInstance(__uuidof(CLSID_OF_YOUR_CUSTOM_FILTER));
graph->AddFilter(fCustomFilter, L"Custom Filter Name");


然后,您可以按照与上述类似的方式进行操作,为滤波器找到合适的输入引脚和合适的输出引脚,然后根据需要连接它们。

最后,这是完全可选的,并且仅对调试有用(因此请勿在生产中使用),您可以向ROT注册图形,从而可以在诸如GraphEdit(或GraphStudioNext或喜欢)。

示例代码取自MSDN for AddToROT and RemoveFromRot

DWORD dwRegistration = 0;
HRESULT hr = AddToRot(graph, &dwRegistration);
// hold on to dwRegistration, and use it later when you tear down the graph
//    to unregister it using the RemoveFromRot(&dwRegister) method

09-06 12:39