Вопрос по MultiVMR9
От: DirectX  
Дата: 23.02.08 22:12
Оценка:
Пишу приложение, которое должно непрерывно, без стыков, воспроизводить серию видеофайлов, а также осуществлять вывод некоторых дополнительных графических элементов. Собственно, первый вариант данной программы написал уже давно, но он был несколько жульнический: создавалось несколько экземпляров windowless VMR9 и производилась манипуляция с прямоугольниками, куда выводится изображение. Несмотря на некоторую нечестность, такой подход показал на удивление неплохие результаты и если не стоит цель обеспечивать спецэффекты при переходах, то его можно признать даже эффективным.

В настоящий момент занимаюсь написанием того же самого, но по-честному, с использованием Direct3D и Custom Allocator-Presenter. В качестве отправной точки был выбран проект MultiVMR9 из старого SDK DirectShow. К сожалению, в Vista Platform SDK 6 данный пример не входит, но у меня старые SDK имелись и пример, соответсвенно, я оттуда извлёк.

Следующим шагом было некоторое допиливание данного примера на предмет компиляции в VS 2008, в конце-концов все пришло в норму и вспомогательная библиотека MultiVMR9.dll, содержащая небольшой фреймворк для приложений подобного типа, успешно скомпилировалась. Библиотеку эту зарегистрировал и проверил на примере из того же SDK на тему многопоточного воспроизведения видео с загрузкой и выгрузкой потоков в процессе работы.

Далее написал обёртку для этой COM библиотеки для второго дотнета, небольшие танцы с бубном и всё стало нормально проигрываться, можно добавлять/удалять потоки, устанавливать координаты и прозрачность видеокартинок, но осталось одно но, о котором и приходится спрашивать:

Всё замечательно кроме того, что в момент построения субграфа очередного потока наблюдается моргание видео Причём это происходит где-то в 60% случаев, тогда, когда создание графа занимает больше некоего критического времени. Иногда такой эффект не наблюдается.

  public class MultiGraphSession : IDisposable
  {
    public MultiGraphSession()
    {
      wizard = null;
      renderEngine = null;
      mixerControl = null;
      hwndVideo = IntPtr.Zero;

      subgraphs = new Dictionary<uint, VMR9Subgraph>(16);
    }

    public virtual void Initialize(IntPtr hwnd)
    {
      hwndVideo = hwnd;

      mixerControl = (IMultiVMR9MixerControl)new MultiVMR9MixerControl();

      renderEngine = (IMultiVMR9RenderEngine)new MultiVMR9RenderEngine();
      renderEngine.Initialize(hwndVideo, 0, mixerControl, null);

      wizard = (IMultiVMR9WizardEx)new MultiVMR9WizardEx();
      wizard.Initialize(0, hwndVideo, renderEngine);
    }

    //...

    public uint AddSource(string path)
    {
      VMR9Subgraph subgraph = null;

      subgraph = new VMR9Subgraph();
      subgraph.BuildAndRender(path, wizard);

      //Thread.Sleep(500);

      subgraphs.Add(subgraph.ID, subgraph);

      return subgraph.ID;
    }

    //...
}


Как показало разбирательство заминка происходит в момент вызова функции BuildAndRender, вызов которой вызывает довольно длительное время. Чтобы смоделировать такую ситуацию добавлял задержку, результат именно такой: вывод кадров на экран прерывается, изображение на это время либо исчезает, либо не успевает исчезнуть если построение графа прошло достаточно быстро и уложилось между перерисовкой кадров.

Как можно разрешить эту проблему? Каким образом возможно сделать процесс создание субграфа асинхронным? Т.е. вопрос стоит следующим образом: возможно ли создание нового графа фильтров в отдельном потоке? Какие здесь могут быть подводные камни?

На всякий случай привожу вышеупомянутую функцию класса VMR9Subgraph. Собственно это переписанный на C# оригинальный пример:

public class VMR9Subgraph : IDisposable
{
    //...

    public void BuildAndRender(string path, IMultiVMR9Wizard wizard)
    {
      if (!File.Exists(path))
        return;

      this.path = path;

      IVMRFilterConfig9 config;
      IGraphBuilder graphBuilder;

      graph = (IFilterGraph)new FilterGraph();
      graphBuilder = (IGraphBuilder)graph;
      VMR = (IBaseFilter)new VideoMixingRenderer9();
      config = (IVMRFilterConfig9)VMR;

      graph.AddFilter(VMR, "Video Mixing Renderer 9");

      if (wizard != null)
      {
        this.wizard = wizard;
        config.SetRenderingMode(VMR9Mode.Renderless);
        id = wizard.Attach(VMR);
      }

      graphBuilder.RenderFile(path, null);

      if (!CheckVMRConnection())
      {
        wizard.Detach(id);
        throw new Exception("Application does not support this media type.\r\nTry some other media source");
      }

      mediaControl = (IMediaControl)graph;
      mediaSeeking = (IMediaSeeking)graph;

      rot = new DsROTEntry(graph);
    }

    //...
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.