Samplegrabber отлично работает с файлами AVI / MPEG, но не работает с WMV.

Я использовал последнюю версию WPFMediaKit. Я пытаюсь написать образец приложения, которое будет использовать Samplegrabber для захвата видеокадров видеофайлов, чтобы я мог иметь их как отдельные растровые изображения.

Пока мне повезло со следующим кодом при построении и рендеринге моего графика. Однако, когда я использую этот код для воспроизведения видеофайла .wmv, когда прикреплен samplegrabber, он будет воспроизводить скачкообразно или прерывисто. Если я закомментирую строку, в которой добавляю фильтр samplegrabber, он работает нормально. Опять же, он правильно работает с семплграббером с AVI / MPEG и т. Д.

 protected virtual void OpenSource()
    {
        FrameCount = 0;
        /* Make sure we clean up any remaining mess */
        FreeResources();

        if (m_sourceUri == null)
            return;

        string fileSource = m_sourceUri.OriginalString;

        if (string.IsNullOrEmpty(fileSource))
            return;

        try
        {
            /* Creates the GraphBuilder COM object */
            m_graph = new FilterGraphNoThread() as IGraphBuilder;

            if (m_graph == null)
                throw new Exception("Could not create a graph");


            /* Add our prefered audio renderer */
            InsertAudioRenderer(AudioRenderer);

            var filterGraph = m_graph as IFilterGraph2;

            if (filterGraph == null)
                throw new Exception("Could not QueryInterface for the IFilterGraph2");

            IBaseFilter renderer = CreateVideoMixingRenderer9(m_graph, 1);                                

            IBaseFilter sourceFilter;

            /* Have DirectShow find the correct source filter for the Uri */
            var hr = filterGraph.AddSourceFilter(fileSource, fileSource, out sourceFilter);
            DsError.ThrowExceptionForHR(hr);

            /* We will want to enum all the pins on the source filter */
            IEnumPins pinEnum;

            hr = sourceFilter.EnumPins(out pinEnum);
            DsError.ThrowExceptionForHR(hr);

            IntPtr fetched = IntPtr.Zero;
            IPin[] pins = { null };

            /* Counter for how many pins successfully rendered */
            int pinsRendered = 0;                

            m_sampleGrabber = (ISampleGrabber)new SampleGrabber();
            SetupSampleGrabber(m_sampleGrabber);
            hr = m_graph.AddFilter(m_sampleGrabber as IBaseFilter, "SampleGrabber");
            DsError.ThrowExceptionForHR(hr);

            /* Loop over each pin of the source filter */
            while (pinEnum.Next(pins.Length, pins, fetched) == 0)
            {
                if (filterGraph.RenderEx(pins[0],
                                         AMRenderExFlags.RenderToExistingRenderers,
                                         IntPtr.Zero) >= 0)
                pinsRendered++;

                Marshal.ReleaseComObject(pins[0]);
            }

            Marshal.ReleaseComObject(pinEnum);
            Marshal.ReleaseComObject(sourceFilter);

            if (pinsRendered == 0)
                throw new Exception("Could not render any streams from the source Uri");

            /* Configure the graph in the base class */
            SetupFilterGraph(m_graph);

            HasVideo = true;
            /* Sets the NaturalVideoWidth/Height */
            //SetNativePixelSizes(renderer);
        }
        catch (Exception ex)
        {
            /* This exection will happen usually if the media does
             * not exist or could not open due to not having the
             * proper filters installed */
            FreeResources();

            /* Fire our failed event */
            InvokeMediaFailed(new MediaFailedEventArgs(ex.Message, ex));
        }

        InvokeMediaOpened();
    }

И:

 private void SetupSampleGrabber(ISampleGrabber sampleGrabber)
    {
        FrameCount = 0;
        var mediaType = new AMMediaType
        {
            majorType = MediaType.Video,
            subType = MediaSubType.RGB24,
            formatType = FormatType.VideoInfo
        };

        int hr = sampleGrabber.SetMediaType(mediaType);

        DsUtils.FreeAMMediaType(mediaType);
        DsError.ThrowExceptionForHR(hr);

        hr = sampleGrabber.SetCallback(this, 0);
        DsError.ThrowExceptionForHR(hr);
    }

Я читал кое-что о том, что форматы .wmv или .asf асинхронны или что-то в этом роде. Я попытался вставить WMAsfReader для декодирования, который работает, но как только он переходит в VMR9, он дает такое же поведение. Кроме того, я добился правильной работы, когда я закомментировал строку IBaseFilter renderer = CreateVideoMixingRenderer9(m_graph, 1); и получил filterGraph.Render(pins[0]); - единственный недостаток заключается в том, что теперь он отображается в собственном окне Activemovie, а не в моем элементе управления, однако сэмплграббер работает правильно и без каких-либо пропусков . Итак, я думаю, что ошибка где-то в VMR9 / samplegrabbing.

Любая помощь? Я новичок в этом.


person Jon Comtois    schedule 15.04.2010    source источник


Ответы (2)


Некоторые декодеры будут использовать аппаратное ускорение с помощью DXVA. Это реализуется путем согласования частично декодированного формата и передачи этих частично декодированных данных модулю визуализации для завершения декодирования и визуализации. Если вы вставите образец захвата, настроенный на RGB24, между декодером и средством визуализации, вы отключите аппаратное ускорение.

В этом, я уверен, суть проблемы. Боюсь, детали все еще немного расплывчаты, например, почему он работает, когда вы используете VMR-7 по умолчанию, но не работает, когда вы используете VMR-9. Я предполагаю, что декодер пытается использовать dxva и терпит неудачу в случае vmr-9, но имеет разумную программную резервную копию, которая хорошо работает в vmr-7.

Я не знаком с WPFMediaKit, но я думаю, что самое простое решение - заменить явное создание vmr-9 явным созданием vmr-7. То есть, если декодер работает только программно с vmr-7, используйте его и сконцентрируйтесь на исправлении проблемы с переопределением окон.

person Geraint Davies    schedule 16.04.2010
comment
Спасибо, я проведу небольшое расследование, чтобы увидеть, можно ли использовать VMR7 вместо WPFMediakit или использовать свой собственный на основе кода, аналогичного тому, как реализован VMR9. Что-то, что я обнаружил с этой проблемой, заключается в том, что я получаю разные результаты на разных компьютерах (т. Е. Я принес это домой на работу вчера вечером и нет прерывистого воспроизведения для WMV). Я собираюсь исследовать с помощью graphedit, выходит ли график одинаковым или что на каждом из них. Или у вас может быть что-то с аппаратным ускорением. - person Jon Comtois; 16.04.2010

В итоге код, который я опубликовал (который сам по себе был слегка изменен мной из исходного кода WPFMediakit Джереми Моррилла), на самом деле был достаточным для рендеринга файлов .WMV и его выборки.

Кажется, что беспокойство имеет какое-то отношение к работе отладчика VS или самой VS2008. После того, как я немного поработал с XAML в визуальном редакторе, а затем запустил приложение, я представлю это прерывистое поведение. Завершение работы VS2008, кажется, исправляет это. :П

Так что не так много ответа, но по крайней мере (раздражает - перезапуск VS2008) исправление, когда оно появляется.

person Jon Comtois    schedule 16.04.2010