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 где-то.
Любая помощь? Я новичок в этом.
2 ответа
Некоторые декодеры будут использовать аппаратное ускорение с использованием DXVA. Это реализуется путем согласования частично декодированного формата и передачи этих частично декодированных данных в устройство визуализации для завершения декодирования и визуализации. Если вы вставите образец граббера, настроенный на RGB24, между декодером и средством визуализации, вы отключите аппаратное ускорение.
В этом, я уверен, суть проблемы. Боюсь, детали все еще немного расплывчаты, например, почему он работает, когда вы используете VMR-7 по умолчанию, но не работает, когда вы используете VMR-9. Я предполагаю, что декодер пытается использовать dxva и терпит неудачу, в случае vmr-9, но имеет разумную программную резервную копию, которая хорошо работает в vmr-7.
Я не знаком с WPFMediaKit, но я думаю, что самое простое решение - заменить явное создание vmr-9 явным созданием vmr-7. То есть, если декодер работает только с программным обеспечением с vmr-7, используйте его и сконцентрируйтесь на устранении проблемы с перерисовкой окна.
В конце концов, код, который я выложил (который сам по себе был довольно бесстыдно слегка изменен из исходного кода WPFMediakit Джереми Моррила), на самом деле был адекватен для рендеринга файлов.WMV и для примера.
Кажется, что изменчивость как-то связана с запуском через отладчик VS или сам VS2008. Поработав некоторое время с XAML в визуальном редакторе, а затем запустив приложение, я представлю это изменчивое поведение. Выключение VS2008, кажется, исправляет это.:П
Так что не очень много ответа, но, по крайней мере, исправление (досадный перезапуск VS2008), когда оно возникает.