使用 DirectShow 预览时无法捕获相机源
Unable to capture a camera feed while previewing using DirectShow
该应用程序是使用 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 显示了到图形的远程连接。通过在 GraphEdit 中手动将 SmartTee 捕获链接到 MuxFilter,图表运行良好。
任何关于可能的错误原因的提示将不胜感激。
没有看到对 ICaptureGRaphBuilder2.RenderStream 的实际调用,我只能对 E_INVALIDARG 错误做出一些假设。
但是,从与图形的远程连接来看,我可以看出您的图形存在严重错误。两个输出引脚不应连接到同一个输入引脚。
您应该始终首先为捕获路径调用 RenderStream,因为它是协商媒体类型的捕获引脚。您的源过滤器上已经有 Capture pin(为什么其中有 2 个?)。我认为您需要像这样调用您的 Capture RenderStream:
RenderStream(PIN_CATEGORY_CAPTURE, MEDIATYPE_Video, pSource, pMux, pWriter);
其中:
pSource是Video Camera Terminal CapFilter的IBaseFilter接口,
pMux 是 MuxFilter 的 IBaseFilter 接口(应该只有一个 MuxFilter 添加到图中!),
pWriter 是 Writer 过滤器 (interview.avi) 的 IBaseFilter 接口。
您应该只添加一个 Video Camera Terminal CapFilter 实例、一个 MuxFilter (AVI Mux) 实例和一个 File Writer 过滤器实例 (interview.avi)。
使用此设置,捕获路径的 RenderStream 调用应该会成功。之后,您可以尝试为预览路径调用 RenderStream,如果智能 T 恤尚未在第一次调用时添加,则应添加。
如果我可以进一步帮助您,请告诉我。
该应用程序是使用 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 显示了到图形的远程连接。通过在 GraphEdit 中手动将 SmartTee 捕获链接到 MuxFilter,图表运行良好。
任何关于可能的错误原因的提示将不胜感激。
没有看到对 ICaptureGRaphBuilder2.RenderStream 的实际调用,我只能对 E_INVALIDARG 错误做出一些假设。 但是,从与图形的远程连接来看,我可以看出您的图形存在严重错误。两个输出引脚不应连接到同一个输入引脚。 您应该始终首先为捕获路径调用 RenderStream,因为它是协商媒体类型的捕获引脚。您的源过滤器上已经有 Capture pin(为什么其中有 2 个?)。我认为您需要像这样调用您的 Capture RenderStream:
RenderStream(PIN_CATEGORY_CAPTURE, MEDIATYPE_Video, pSource, pMux, pWriter);
其中: pSource是Video Camera Terminal CapFilter的IBaseFilter接口, pMux 是 MuxFilter 的 IBaseFilter 接口(应该只有一个 MuxFilter 添加到图中!), pWriter 是 Writer 过滤器 (interview.avi) 的 IBaseFilter 接口。
您应该只添加一个 Video Camera Terminal CapFilter 实例、一个 MuxFilter (AVI Mux) 实例和一个 File Writer 过滤器实例 (interview.avi)。 使用此设置,捕获路径的 RenderStream 调用应该会成功。之后,您可以尝试为预览路径调用 RenderStream,如果智能 T 恤尚未在第一次调用时添加,则应添加。 如果我可以进一步帮助您,请告诉我。