Пишу приложение, которое должно непрерывно, без стыков, воспроизводить серию видеофайлов, а также осуществлять вывод некоторых дополнительных графических элементов. Собственно, первый вариант данной программы написал уже давно, но он был несколько жульнический: создавалось несколько экземпляров 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);
}
//...
}