Вопрос по 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);
    }

    //...
}
Re: Вопрос по MultiVMR9
От: transcoder  
Дата: 25.02.08 11:46
Оценка:
Здравствуйте, примерно аналогичная задача стояла и у меня несколько месяцев назад. С помощью DES всё удачно решилось... Конечно, без танцев с бубном не обошлось, но меня устраивает
Re[2]: Вопрос по MultiVMR9
От: DirectX  
Дата: 25.02.08 12:50
Оценка:
Здравствуйте, transcoder, Вы писали:

T>Здравствуйте, примерно аналогичная задача стояла и у меня несколько месяцев назад. С помощью DES всё удачно решилось... Конечно, без танцев с бубном не обошлось, но меня устраивает


Спасибо за ответ. Я этот способ еще тогда рассматривал. К сожалению для моей задачи он не вполне подходит по причине неопределённости как количества файлов, так и времени их демонстрации. Кроме этого предполагается использовать потоковые источники.

В общем пока что пытаюсь красиво вытащить создание графа в отдельный поток. Пока что с переменным успехом занимаюсь вопросами корректной синхронизации. Но мето данный вполне рабочий если разобраться с этим моментом. Если кому интересно, когда разберусь, попробую написать статью на тему этой библиотеки и её использования в .NET

Кстати, для меня остался не до конца выясненным вопрос по следующему моменту: почему видеоизображение, выводимое через VMR9 в режиме custom allocator/presenter имеет заметные на глаз различия в гамма-коррекции по сравнению с использованием других рендереров? Оно слегка менее контрастное что ли, нет чистого чёрного. Возможно это шутки ambient light?
Re: Вопрос по MultiVMR9
От: DirectX  
Дата: 11.03.08 10:40
Оценка:
Продолжаю в свободное время писать эту программу. Пока что попытки вынести создание графа в отдельный поток ни к чему хорошему не привели.

При обычном вызове функции BuildAndRender, где и происходит построение графа, всё проходит нормально, если не считать лёгкого подвисания основного потока приложения и связанный с этим лаг. В дополнение к этой функции создал с помощью делегатов ее асинхронный вариант, который вызывает BuildAndRender в отдельном потоке с помощью BeginInvoke с уведомлением о завершении этого процесса через еще один делегат. В общем, теоретически такая связка должна была бы работать, поскольку никаких обращений к не успевшим инициализироваться объектам в программе нет. Но на практике программа вываливалась по причине невозможности привести объект VMR9 к одному из поддерживаемых интерфейсов.

Разбирательства на значительно упрощенной версии программы (без всяких MultiVMR, фактически обычный плеер с VMR9), привели к следующему интересному результату. Ошибка возникает именно при попытке воспользоваться интерфейсами VMR9, созданными в другом потоке. При этом интерфейсы самого графа работают нормально. Т.е. допустим если в момент создания объекта VMR9 получить у него интерфейс IVMRWindowlessControl9 и не отходя от кассы назначить с его помощью позицию видеоокна, то всё пройдет нормально и изображение появится где надо, но если воспользоваться этим интерфейсом впоследствии, то возникнет исключение InvalidCastException по поводу невозможности привести VideoMixingRenderer9 к IVMRWindowlessControl9.

Самое интересное, что тот же граф и его интерфейсы
IMediaControl mediaControl = (IMediaControl)graph;
IMediaSeeking mediaSeeking = (IMediaSeeking)graph;

созданные в том же дополнительном потоке работают нормально и далее. Видеоизображение появляется и видно всё время (только его впоследствии нельзя корректировать), что ИМХО говорит в пользу того, что ссылка на VMR не должна быть равна нулю.

Кроме этого такой интересный факт: после окончания строительства графа и завершения потока функция

public bool CheckVMRConnection()
{
  bool connected = false;
  IEnumPins enumPins;
  IPin[] pins = new IPin[1];
  IPin connectedPin = null;

  if (VMR == null)
    return false;
  if (VMR.EnumPins(out enumPins) != 0)
    return false;
  try
  {
    while (enumPins.Next(pins.Length, pins, IntPtr.Zero) == 0)
    {
      try
      {
        if (pins[0].ConnectedTo(out connectedPin) == 0)
          if (connectedPin != null)
          {
            connected = true;
            break;
          }
      }
      finally
      {
        if (connectedPin != null)
          Marshal.ReleaseComObject(connectedPin);
        Marshal.ReleaseComObject(pins[0]);
      }
    }
  }
  finally
  {
    Marshal.ReleaseComObject(enumPins);
  }

  return connected;
}

возвращает false, причем не на первых двух проверках, что характерно. Перечислитель получается, а вот enumPins.Next(pins.Length, pins, IntPtr.Zero) сразу же выдаёт !S_OK. Как будто у фильтра нет выводов.

При этом в GraphEdit весь граф включая VMR виден.

В чем может быть причина?
Re: Вопрос по MultiVMR9
От: Triba1  
Дата: 05.04.08 19:32
Оценка:
Здравствуйте, DirectX, Вы писали:

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


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


мне тоже неожиданно для меня пришлось работать c Directshow и порывшись в инете, понимаю что multiVMR9 это то что теоретически мне нужно... длл мне удалось скомпилить на 3-й, но вот нормально вытянуть интерфейсы... — это уже проблема ((( не могли бы вы поделить сорцами, плс...
Re[2]: Вопрос по MultiVMR9
От: DirectX  
Дата: 06.04.08 05:50
Оценка: 3 (1)
http://rapidshare.com/files/105232463/MultiVMR9_source.zip.html
Re: Вопрос по MultiVMR9
От: cencio Украина http://ua-coder.blogspot.com
Дата: 06.04.08 10:55
Оценка:
Здравствуйте, DirectX, Вы писали:

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


желательно не забывать что это семпл, и не вставлять его аз-из в комерческий код, там в результате может куча проблем повылазит, например попробуй хотябы проиграгать HD видео, 2 года назад делать проект, там из-за этого большие проблемы с перформансом были, ну и еще по мелочам
а вот проблемы с подгрузкой нового файла небыло, не помню точно что и как уже, если интересует, пиши ПМ, посмотрю
Re: Вопрос по MultiVMR9
От: netz www.gissoft.ru
Дата: 10.06.08 18:10
Оценка:
У меня сейчас стоит задача создания слайдшоу из картинок и видео с плавными переходами и различными эффектами.
Ранее я решил эту задачу, но при переключении с видео на видео или с картинки на видео происходило моргание.
Сейчас у меня все сделано следующим образом:
1. в цикле перебираем файлы:
1.1 если это картинка, то прячем окно DirectShow, отображаем обычное окно и на его канве рисует картинку, делая плавный переход между предыдущим кадром и картинкой
1.2 если это видео, то получаю первый кадр видео, далее все делаю как в пункте 1.1 для отображения плавного перехода, после завершения спец-эффекта показываю окно DirectShow и запускаю видео.

Я так подозреваю что все нужно делать в окне DirectShow, но как добиться смены видео без моргания? Буду рад любым советам
Re[2]: Вопрос по MultiVMR9
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 11.06.08 05:19
Оценка:
Здравствуйте, netz, Вы писали:

N>Я так подозреваю что все нужно делать в окне DirectShow, но как добиться смены видео без моргания? Буду рад любым советам


DES умеет показывать картинки и делать плавные переходы. Если расписание событий известно заранее, можно использовать его.
Re[2]: Вопрос по MultiVMR9
От: DirectX  
Дата: 13.06.08 09:12
Оценка:
Здравствуйте, netz, Вы писали:

N>У меня сейчас стоит задача создания слайдшоу из картинок и видео с плавными переходами и различными эффектами.

N>Ранее я решил эту задачу, но при переключении с видео на видео или с картинки на видео происходило моргание.
N>Сейчас у меня все сделано следующим образом:
N>1. в цикле перебираем файлы:
N>1.1 если это картинка, то прячем окно DirectShow, отображаем обычное окно и на его канве рисует картинку, делая плавный переход между предыдущим кадром и картинкой
N>1.2 если это видео, то получаю первый кадр видео, далее все делаю как в пункте 1.1 для отображения плавного перехода, после завершения спец-эффекта показываю окно DirectShow и запускаю видео.

N>Я так подозреваю что все нужно делать в окне DirectShow, но как добиться смены видео без моргания? Буду рад любым советам


Я все же допинал проблему, с которой начался этот топик. Для данного случая также подойдёт.

В общем, как мне тут посоветовал cencio ориентироваться на пример MultiVMR9 слепо не стоило. Он все же слегка глючный в этом смысле. Поэтому я пошел немного другим путём, взял за основу проект MediaPortal. Выкачал я оттуда репозиторий svn и стал с ним разбираться. Надо заметить разобраться в нем — не самая простая затея, но основная сложность все же заключается в объёме: там не одна сотня файлов. Но при этом процентов 97 никаким боком не относились к моей задаче. Вот, короче говоря, основные вехи:

1) Использовать библиотеку SlimDX. Ее несложно найти в интернете. Желательно скачать последнюю версию. Чтобы она заработала нужен самый последний рантайм DirectX. Короче говоря, пишется для начала приложение, позволяющее рендерить 3d сцену. Что характерно, использование стандартного Managed DirectX не привело ни к чему хорошему: после показа пары кадров видео приложение сваливалось. Где могли быть мои недоработки на тему освобождения ресурсов я так и не нашел. А переход на SlimDX решил все проблемы. Похоже не зря именно он используется в медиапортале.

В сцене выставляется камера и добавляются несколько quad'ов, на которые потом накладываются текстуры. Если нужно обычную картинку, то просто загружается текстура из файла. Если нужно видео, то для этого используется п. 2

2) В медиапортале имеется специальный проект на C++, Vmr9Helper.dll. Это обычная (не com) dll, которая как раз и отвечает за низкоуровневую работу с Allocator/Presenter. В общем, из оригинального проекта я взял все моменты, которые непосредственно относятся к работе с этой библиотекой.

В итоге после множества экспериментов все это заработало. Единственная сложность (или скажем так — тонкость) — это правильный вызов процедуры Render. Дело в том, что Allocator/Presenter сам вызывает функцию PresentSurface когда готов очередной кадр. Поэтому, если в сцене воспроизводится хотя бы одно видео, то нужно вызывать функцию Render как раз один раз из PresentSurface. Тогда будет около 25 фпс. Если каждый из параллельно запущенных видеофрагментов будет дергать функцию чаще, то возникнут проблемы с мерцающими текстурами. Если же отображается обычная картинка, то функцию Render уже надо вызывать другими способами (например в OnIdle).

Определенные раздумья у меня вызвало то, как реализовать кроссфейдинг. Понятно, что для этого нужно было задействовать альфа-канал. После некоторых поисков (до этого я Direct3D вообще не занимался) я настроил параметры рендеринга так, чтобы в расчёт брались как текстуры с альфа-каналом, что мне было нужно во вторую очередь, так и альфа, хранящаяся в цвете вершины. Но это было все равно не вариант 25 раз в секунду перезаписывать вершинный буфер. Это вообще клиника была бы. Поэтому я стал копать в сторону шейдеров. На удивление быстро с их помощью я решил данную проблему. Единственный недостаток — программа достаточно требовательна к видеокарте.

В общем, если интересно, то могу исходники этого дела запостить.
Re[2]: Вопрос по MultiVMR9
От: Аноним  
Дата: 09.01.09 08:54
Оценка:
Вопрос: Как регистрировали MultiVMR9.dll? У меня все компилировалось, но библиотека регистрироваться не хочет?
Re[3]: Вопрос по MultiVMR9
От: DirectX  
Дата: 18.01.09 15:52
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вопрос: Как регистрировали MultiVMR9.dll? У меня все компилировалось, но библиотека регистрироваться не хочет?


regsvr32 MultiVMR9.dll не работает? Странно, должна. А вообще очень рекомендую MediaPortal, там более вменяемая библиотека с точки зрения использования в .NET. Ставите Subversion и выкачиваете репозиторий проекта MP-II, там все что надо есть.
Re[4]: Вопрос по MultiVMR9
От: squid  
Дата: 19.01.09 04:14
Оценка:
Здравствуйте, DirectX, Вы писали:

DX>regsvr32 MultiVMR9.dll не работает? Странно, должна. А вообще очень рекомендую MediaPortal, там более вменяемая библиотека с точки зрения использования в .NET. Ставите Subversion и выкачиваете репозиторий проекта MP-II, там все что надо есть.


GPL...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.