DirectShow переподключение фильтра

Не хотел опять лезть с дурацкими вопросами, но как обычно :man_shrugging:
Имею массив сплиттеров GUID | Name. Их надо в цикле перебрать и взять первый успешно подключенный. Подключение первого в списке проходит успешно. Но пин для подключения видео-декодера у него отсутствует. Это значит, что сплиттер не смог правильно распознать контейнер. Для сплиттеров это обычная ситуация. Пока не подключишь сплиттер - не узнаешь. По-этому, собственно, и нужен перебор. В таком случае надо отключить текущий сплиттер и перейти к следующему.
Но проблема в том, что следующие сплиттеры при попытке подключения будут выдавать ошибку VFW_E_CANNOT_CONNECT. Даже если их не перебирать, а просто подключить / отключить / подключить один и тот же сплиттер - будет та же ошибка.

        private int FindAndConnectMediaSplitter_Manual(IEnumerable<FilterItem> splitters, IPin sourcePinOut)
        {
            foreach (FilterItem item in splitters)
            {
                int errorCode = CreateDirectShowFilter(item.GetGuid(), out IBaseFilter filter);
                if (errorCode != S_OK)
                {
                    System.Diagnostics.Debug.WriteLine($"Loading {item.DisplayName}: {ErrorCodeToString(errorCode)}");                    
                    continue;
                }
                System.Diagnostics.Debug.WriteLine($"Loading {item.DisplayName}: S_OK");

                graphBuilder.AddFilter(filter, item.DisplayName);
                FindPin(filter, 0, PinDirection.Input, out IPin pinIn);
                errorCode = graphBuilder.Connect(sourcePinOut, pinIn);
                if (errorCode != S_OK)
                {
                    System.Diagnostics.Debug.WriteLine($"Connecting {item.DisplayName}: {ErrorCodeToString(errorCode)}");
                    graphBuilder.RemoveFilter(filter);
                    Marshal.ReleaseComObject(filter);
                    continue;
                }
                System.Diagnostics.Debug.WriteLine($"Connecting {item.DisplayName}: S_OK");


                FindPin(filter, "ideo", PinDirection.Output, out IPin splitterPinOut);
                if (splitterPinOut == null)
                {
                    System.Diagnostics.Debug.WriteLine("Video output pin not found! Skipping this bad bad filter.");
                    graphBuilder.Disconnect(pinIn);
                    graphBuilder.RemoveFilter(filter);
                    Marshal.ReleaseComObject(filter);
                    continue;
                }

                mediaSplitter = filter;

                return errorCode;
            }

            System.Diagnostics.Debug.WriteLine("No one valid media splitter found!");
            return S_FALSE;
        }

На Delphi такой алгоритм работает.
Если коротко, то проблема в следующем:

                errorCode = graphBuilder.Connect(sourcePinOut, pinIn); //S_OK
                errorCode = graphBuilder.Disconnect(pinIn); //S_OK
                errorCode = graphBuilder.Connect(sourcePinOut, pinIn); //VFW_E_CANNOT_CONNECT

Я например уничтожаю полностью граф и начинаю пересобирать его заного уже с новыми фильтрами.

Подобный глюк в разных софтинах встречается типа GraphEditPlus. Там если оторвать фильтр и поставить другой не всегда запускается рендер. Приходится всю программу перезапускать.

ЧТо то типа такого:

VideoLib.DSCam.DirectShowHelper.CodecTypes[] queue = new VideoLib.DSCam.DirectShowHelper.CodecTypes[] { VideoLib.DSCam.DirectShowHelper.CodecTypes.MJPEG_Decompressor, VideoLib.DSCam.DirectShowHelper.CodecTypes.AVI_Decompressor, VideoLib.DSCam.DirectShowHelper.CodecTypes.LAV_Video_Decoder };

            for (int i = 0; i < queue.Length; i++)
            {
                try
                {
                    if (this.Device == null)
                        this.Device = new VideoLib.DSCam.DSCamera(source);
                    this.Device.VideoResolution = Extensions.GetCapability(this.Device, 1280 * 2, 960, 500);
                    this.Device.StartRender(queue[i]);                    
                    FrameBuf?.Dispose();
                    FrameBuf = new OpenCvSharp.Mat(new OpenCvSharp.Size(FrameWidth, FrameHeight), OpenCvSharp.MatType.CV_8UC3);
                    this.Device.OnNewFrameReceivedEvent += this.Device_OnNewFrameReceivedEvent;
                    break;
                }
                catch
                {
                    this.Device.Dispose();
                    this.Device = null;
                }
            }
            if (this.Device == null)
                throw new ArgumentException("No suitable codec found.");
 public void StartRender(DirectShowHelper.CodecTypes ctp)
        {
            graph = (IGraphBuilder)new FilterGraph();
            Console.WriteLine("Building graph...");
            DirectShowHelper.BuildGraph(ctp, graph, pCamera, ActiveDevice.Name, VideoResolution.MType, pSampleGrabber, pNullRenderer, this);

            Console.WriteLine("Running...");

            mediaControl = (IMediaControl)graph;
            mediaEvent = (IMediaEvent)graph;
            int hr = mediaControl.Run();
            DirectShowHelper.checkHR(hr, "Can't run the graph");
}

но тогда вся, годами выверенная, логика программы пойдёт по трубе.

Но на Delphi же работает :thinking:


О, слушайте! :dizzy_face: А теперь он эту ошибку сразу выдаёт! :dizzy_face: На первой же итерации.
Я не знаю, как это комментировать и что говорить.

Перезагрузить комп вначале… по прошлому то опыту должно помочь.
А вообще попробуйте в билдере строить граф типа в GraphEditPlus. Там тоже будет ошибка?

Спасибо за напоминание :grin: Обязательно перезагружусь, но не сейчас. Сейчас этого сделать невозможно.

Там всё нормально работает. Я, видимо, код закосячил случайно :flushed: Сейчас вернул всё как было в первом посте. Ситуация та же. Ошибка при переподключении. как и было. Код на Delphi работает.
Если каждый раз пересоздавать Граф, как вы говорили, то работает. Но это во-первых долго (но фиг бы с ним), во-вторых большую часть придётся переписывать. Тоже, в целом, не критично. Но если оно в Delphi работает, то почему не работает на C#? Это же API винды. Какая разница, из какого языка его вызывают? :thinking:

Проблема оказалась в том, что я вызывал метод Disconnect(), а делать этого не надо (почему-то :thinking: ). На Delphi я этого не делаю. Если его не вызывать, тогда всё работает.
Этого метода (почему-то) нет на MSDN :thinking: Вероятно, он использовался в каких-то древних версиях винды, а потом они что-то переделали и он стал не нужен. Но если так, то почему они об этом не написали, а тупо выпилили страницу? :dizzy_face:

DD уже древний как мир. Там весь код помечен как неиспользуемый. Какие то части просто удалены.
Уже несколько лет МС настаивает на использовании MediaFoundation. Вы бы еще баги в TCP/IP поискали.

Вы уже говорили. Я помню.

Я боюсь, что там вдруг окажется, что нельзя воспроизвести несколько видео одновременно в одном процессе (или кодеки нельзя будет выбирать, или еще какие новомодные ограничения). А для меня такая возможность очень важна.