我正在尝试使用directshow编写一个C ++应用程序,将视频捕获保存到文件中。 代码中的步骤是: 1.创建Capture Graph Builder 2.创建系统设备枚举器 3.创建系统设备枚举器 - 以获取捕获筛选器 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 错误
有什么建议吗?
由于
答案 0 :(得分:1)
看看this topic。看来你错过了一些步骤。
首先,您没有在任何地方使用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);
// ...
}
其次,您使用的是不受图表管理器管理的过滤器。引自here:
在调用方法之前,必须将pSource,pIntermediate和pSink指定的所有过滤器添加到图形中。
您必须使用AddFilter将过滤器pCap
和pMux
添加到之前创建的图表管理器中。您应该在调用RenderStream之前执行此操作。这是因为RenderStream最终会在管理器上调用连接方法。
如果上述步骤无法解决您的问题,您可以尝试其他一些方法。
设备过滤器。您使用的是CLSID_VideoInputDeviceCategory
的第一台设备,但是您确定这是正确的设备吗?网络摄像头等也包含在此类别中。确保没有连接相同类别的其他设备,然后重试。
<强>连接即可。每个设备都不同。可能是您的设备无法直接连接到多路复用器。在这种情况下,我们必须找出原因,并确定是否需要连接其他过滤器(如解码器)。 GraphEdit是查找这些过滤器的快捷方式。
引脚类别/媒体类型。根据我的经验,E_INVALIDARG是由RenderStream
的前2个参数引起的90%的时间。尝试将引脚类别或媒体类型设置为NULL
。
系统设备枚举器:正如您所描述的那样,您正在创建两次系统设备枚举器。这对我来说似乎很奇怪,为什么不使用一个,用于两个目的?
如果您的代码仍然不起作用,您应该向我提供更多信息。使用GraphEdit时,您是否实现了目标?您的VDM电视卡过滤器如何(引脚,媒体类型)?