У нас есть приложение, которое использует DirectShow с двумя фильтрами для реализации бесшовного воспроизведения видео.
каждая «панель» инициализируется фильтром
new QuartzTypeLib.FilgraphManager()
и позже присваивается WndProc
с использованием MediaEventEx.SetNotifyWindow
для того же окна, но с другим LParam (идентификатор панели 0 или 1)
В документации указано, что WM_GRAPHNOTIFY отправляется при появлении новых событий, но в очереди может быть несколько событий или очередь может быть пустой. Кроме того, WM_GRAPHNOTIFY не отправляется один раз для каждого события, но может быть отправлен один раз, если в очереди есть одно или несколько событий.
Поскольку я использую одно и то же окно для уведомлений от обоих фильтров, могу ли я быть уверен, что получаю события из обеих очередей, если они происходят одновременно, или мне нужно проанализировать обе очереди в каждом сообщении WM_GRAPHNOTIFY или я могу безопасно обработать очередь из lParam?
Ниже приведена очень упрощенная версия моего кода.
private const int WM_APP = 0x8000;
private const int WM_GRAPHNOTIFY = WM_APP + 1;
private const int EC_COMPLETE = 0x01;
private const int EC_USERABORT = 0x02;
private const int EC_ERRORABORT = 0x03;
void InitializePanels()
{
for (int panel = 0; panel <= 1; panel++)
{
PlaybackPanels[panel].FilterGraph = new QuartzTypeLib.FilgraphManager();
PlaybackPanels[panel].MediaEventEx = PlaybackPanels[(panel].FilterGraph as IMediaEventEx;
PlaybackPanels[panel].MediaEventEx.SetNotifyWindow((int)this.Handle, WM_GRAPHNOTIFY, panel);
PlaybackPanels[panel].MediaControl = PlaybackPanels[panel].FilterGraph as IMediaControl;
// Additional code to load media files here...
PlaybackPanels[panel].MediaControl.Pause();
}
PlaybackPanels[0].MediaControl.Run();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_GRAPHNOTIFY)
{
int lEventCode;
int lParam1, lParam2;
int playerPanelID = m.LParam.ToInt32();
int _while = 0;
while (_while < 100)
{
try
{
PlaybackPanels[playerPanelID].MediaEventEx.GetEvent(out lEventCode, out lParam1, out lParam2, 0);
PlaybackPanels[playerPanelID].MediaEventEx.FreeEventParams(lEventCode, lParam1, lParam2);
if (lEventCode == EC_COMPLETE)
{
int nextPanel = 1 - playerPanelID;
PlaybackPanels[nextPanel].MediaControl.Run();
}
else if (lEventCode == EC_USERABORT || lEventCode == EC_ERRORABORT)
{
/// Handle error...
}
}
catch (System.Runtime.InteropServices.COMException ex)
{
// REMARKS: When the window receives the message, it should call the IMediaEvent::GetEvent method to retrieve the event.
// Events are asynchronous, so the queue might contain several events (or none).
// Call GetEvent repeatedly, until it returns an error code.
if ((uint)ex.ErrorCode == 0x80004004) //Operation Aborted (E_ABORT)
{
// We are done processing the event queue. *Resume event loop*
break;
}
else
{
throw;
}
}
_while++;
}
}
base.WndProc(ref m);
}