Приложение реализовано на C# с использованием DirectShowLib и USB-камеры (Logitech C930e). График скомпилирован с использованием метода RenderStream. Фильтр SmartTee генерируется автоматически, так как нет предустановленного штифта.Невозможно захватить подачу камеры при предварительном просмотре с помощью DirectShow
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 к MuxFilter в GraphEdit.
Любые намеки относительно возможную причину ошибки будет очень высоко ценится.
Большое спасибо за ваш ответ и помощь. Я добавил фрагмент кода для большей ясности. Возможно, вы, вероятно, правы в том, чтобы сначала вызвать RenderStream для Capture. Тем не менее, в моем случае, мне нужно сначала просмотреть видео в моем приложении, после чего захват будет добавлен пользователем, если потребуется. Последовательность, которая генерирует приведенный выше график, является [1] - [2] - [3] - [1] или [1] - [2] - [1] - [3]. Мое последнее грязное средство - это добавить ручное построение графа для второго вызова предварительного просмотра. Эта последовательность [1] - [2] - [3] - [4] работает. –
1-2-3-4 выглядит нормально на первый взгляд. В противном случае, если вам нужно его оптимизировать (если это вообще возможно), вы можете попробовать перестроить весь график, удалив все фильтры и повторно добавив их, а затем выполните RenderStream (Capture ...) и RenderStream (Preview ...), когда пользователь решает включить захват в предварительный просмотр. – VuVirt
Каков наилучший способ удалить существующий график? –