该应用程序使用DirectShowLib和USB摄像头(Logitech C930e)在C#中实现。该图是使用RenderStream方法编译的。由于未提供预览图钉,因此会自动生成SmartTee筛选器。
一次调用RenderStream进行预览,然后进行捕获。但是,即使交换(捕获然后预览),它也无法将第二个呼叫连接到SmartTee。引发的错误处理程序为:-2147024809(0x80070057; E_INVALIDARG
;参数不正确)
代码片段如下
DirectShowLib.ISampleGrabber sg = null;
DirectShowLib.ICaptureGraphBuilder2 cg = null;
DirectShowLib.IGraphBuilder fg = null;
IBaseFilter capFilter;
IBaseFilter videoCompressorFilter;
IBaseFilter muxFilter;
IBaseFilter grabFilter;
IBaseFilter VideoRendererFilter;
Guid captureCat = PinCategory.Capture;
Guid previewCat = PinCategory.Preview;
Guid med = MediaType.Video;
DsGuid DSCaptureCat = (DsGuid)captureCat;
DsGuid DSPreviewCat = (DsGuid)previewCat;
DsGuid DSmed = (DsGuid)med;
/*GetInterfaces*/
Type comType = null;
object comObj = null;
fg = (IGraphBuilder)new FilterGraph();
comType = Type.GetTypeFromCLSID(CgGuid);
comObj = Activator.CreateInstance(comType);
cg = (ICaptureGraphBuilder2)comObj; comObj = null;
sg = (ISampleGrabber)new SampleGrabber();
grabFilter = (IBaseFilter)sg;
VideoRendererFilter = (IBaseFilter)new VideoRenderer();
/*CreateCaptureDevice*/
object capObj = null;
capFilter = (IBaseFilter)capObj;
/*SetupGraph*/
hr = cg.SetFiltergraph(fg);
if (renderFromDevice && deviceSet)
{
hr = fg.AddFilter(capFilter, "CapFilter");
}
AMMediaType media = new AMMediaType();
media.majorType = MediaType.Video;
media.subType = MediaSubType.RGB24;
media.formatType = FormatType.VideoInfo;
hr = sg.SetMediaType(media);
DsUtils.FreeAMMediaType(media);
media = null;
[1]
/*RenderToScreen*/
hr = fg.AddFilter(grabFilter, "FrameGrabFilter");
hr = cg.RenderStream(DSPreviewCat, DSmed, capFilter, grabFilter, null);
[2]
/*DerenderGraph*/
if (renderFromDevice)
removeDownstream(capFilter, videoCompressorFilter == null);
else if (grabFilter != null)
removeDownstream(grabFilter, true);
[3]
/*RenderToMovie*/
videoFilename = Path.Combine(dirname, "interview.avi");
cg.SetOutputFileName(MediaSubType.Avi, videoFilename, out muxFilter, out fileWriterFilter); //this automatically adds muxFilter to graph!
string s;
AMMediaType media = new AMMediaType();
hr = fileWriterFilter.GetCurFile(out s, media);
hr = fileWriterFilter.SetFileName(videoFilename, media);
DsUtils.FreeAMMediaType(media);
media = null;
hr = fg.AddFilter(muxFilter, "MuxFilter"); //this adds the second muxFilter! now removed
hr = cg.RenderStream(DSCaptureCat, DSmed, capFilter, null, muxFilter);
[4]
/*RenderToScreen2*/
hr = fg.AddFilter(grabFilter, "FrameGrabFilter");
hr = fg.AddFilter(VideoRendererFilter, "VideoRendererFilter");
IEnumFilters enumFilters = null;
FilterInfo pInfo;
IBaseFilter pFilter1, pFilter2, pFilter3;
IPin outPin1, inPin1, outPin2, inPin2, inPin3;
hr = fg.EnumFilters(out enumFilters);
IBaseFilter[] filters = new IBaseFilter[1];
int fetched;
while (enumFilters.Next(1, filters, out fetched) == 0)
{
hr = filters[0].QueryFilterInfo(out pInfo);
hr = fg.FindFilterByName("Smart Tee", out pFilter1);
inPin1 = DsFindPin.ByDirection(pFilter1, PinDirection.Input, 0);
outPin1 = DsFindPin.ByName(pFilter1, "Preview");
hr = fg.FindFilterByName("FrameGrabFilter", out pFilter2);
inPin2 = DsFindPin.ByDirection(pFilter2, PinDirection.Input, 0);
outPin2 = DsFindPin.ByDirection(pFilter2, PinDirection.Output, 0);
hr = fg.FindFilterByName("VideoRendererFilter", out pFilter3);
inPin3 = DsFindPin.ByDirection(pFilter3, PinDirection.Input, 0);
hr = fg.Connect(outPin1, inPin2);
hr = fg.Connect(outPin2, inPin3);
}
下面的GraphEdit显示了到图形的远程连接。通过手动将SmartTee捕获链接到GraphEdit中的MuxFilter,图形可以正常运行。
关于可能的错误原因的任何提示将不胜感激。
最佳答案
在没有看到对ICaptureGRaphBuilder2.RenderStream的实际调用的情况下,我只能对E_INVALIDARG错误做出一些假设。
但是,从远程连接到图形,我可以看到您的图形存在严重错误。两个输出引脚不应连接到同一输入引脚。
您应该始终始终首先为Capture路径调用RenderStream,因为协商媒体类型的是Capture引脚。您的源滤波器上已经有Capture引脚(为什么连2个也如此?)。我认为您需要像这样调用Capture RenderStream:
RenderStream(PIN_CATEGORY_CAPTURE,MEDIATYPE_Video,pSource,pMux,pWriter);
哪里:
pSource是摄像机终端CapFilter的IBaseFilter接口,
pMux是MuxFilter的IBaseFilter接口(应该只向图中添加一个MuxFilter!),
pWriter是Writer筛选器(interview.avi)的IBaseFilter接口。
您应该仅添加一个摄像机终端CapFilter实例,仅添加一个MuxFilter(AVI Mux)实例,以及仅一个File Writer过滤器(interview.avi)实例。
通过此设置,对Capture路径的RenderStream调用应该会成功。之后,您可以尝试调用RenderStream作为预览路径,并且如果尚未在第一个调用中添加Smart tee,则应添加Smart tee。
让我知道是否可以进一步帮助您。