Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
[Funkcja skojarzona z tą stroną, DirectShow, jest starszą funkcją. Został zastąpiony przez MediaPlayer, IMFMediaEnginei Audio/Video Capture w Media Foundation. Te funkcje zostały zoptymalizowane pod kątem systemów Windows 10 i Windows 11. Firma Microsoft zdecydowanie zaleca, aby nowy kod używał MediaPlayer, IMFMediaEngine i Audio/Video Capture w programie Media Foundation zamiast DirectShow, jeśli to możliwe. Firma Microsoft sugeruje, że istniejący kod, który używa starszych interfejsów API, należy przepisać go do korzystania z nowych interfejsów API, jeśli to możliwe.]
W tym artykule opisano sposób reagowania na zdarzenia występujące na wykresie filtru.
Jak działa powiadomienie o zdarzeniach
Gdy aplikacja DirectShow jest uruchomiona, zdarzenia mogą występować w grafie filtru. Na przykład filtr może napotkać błąd przesyłania strumieniowego. Filtry alarmują Menedżera Graphu Filtrów, wysyłając zdarzenia, które składają się z kodu zdarzenia i dwóch parametrów zdarzenia. Kod zdarzenia wskazuje typ zdarzenia, a parametry zdarzenia dostarczają dodatkowe informacje. Znaczenie parametrów zależy od kodu zdarzenia. Aby uzyskać pełną listę kodów powiadomień zdarzeń, zobacz Kody zdarzeń.
Niektóre zdarzenia są obsługiwane w trybie dyskretnym przez Menedżera filtrów programu Graph bez powiadamiania aplikacji. Inne zdarzenia są umieszczane w kolejce dla aplikacji. W zależności od aplikacji istnieją różne zdarzenia, które mogą być konieczne do obsługi. Ten artykuł koncentruje się na trzech zdarzeniach, które są bardzo typowe:
- Zdarzenie EC_COMPLETE wskazuje, że odtwarzanie zostało ukończone normalnie.
- Zdarzenie EC_USERABORT wskazuje, że użytkownik przerwał odtwarzanie. Programy renderujących wideo wysyłają to zdarzenie, jeśli użytkownik zamknie okno wideo.
- Zdarzenie EC_ERRORABORT wskazuje, że wystąpił błąd powodujący zatrzymanie odtwarzania.
Korzystanie z powiadomienia o zdarzeniu
Aplikacja może poinstruować Menedżera filtrów programu Graph o wysłaniu komunikatu systemu Windows do wyznaczonego okna za każdym razem, gdy wystąpi nowe zdarzenie. Dzięki temu aplikacja może odpowiadać wewnątrz pętli komunikatów okna. Najpierw zdefiniuj komunikat, który zostanie wysłany do okna aplikacji. Aplikacje mogą używać numerów wiadomości w zakresie od WM_APP do 0xBFFF jako wiadomości prywatnych.
#define WM_GRAPHNOTIFY WM_APP + 1
Następnie wykonaj zapytanie względem menedżera programu Graph filter dla interfejsuinterfejsuIMediaEventEx i wywołaj metodę IMediaEventEx::SetNotifyWindow:
IMediaEventEx *g_pEvent = NULL;
g_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&g_pEvent);
g_pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
Ta metoda wyznacza określone okno (g_hwnd) jako odbiorcę wiadomości. Wywołaj metodę po utworzeniu grafu filtru, ale przed uruchomieniem grafu.
WM_GRAPHNOTIFY jest zwykłym komunikatem systemu Windows. Za każdym razem, gdy menedżer filtrów programu Graph umieszcza nowe zdarzenie w kolejce zdarzeń, publikuje komunikat WM_GRAPHNOTIFY do wyznaczonego okna aplikacji. Parametr lParam komunikatu jest równy trzeciemu parametrowi w SetNotifyWindow. Ten parametr umożliwia wysyłanie danych wystąpienia wraz z wiadomością. Parametr wParam komunikatu okna jest zawsze zerowy.
W funkcji WindowProc aplikacji dodaj instrukcję case dla komunikatu WM_GRAPHNOTIFY:
case WM_GRAPHNOTIFY:
HandleGraphEvent();
break;
W funkcji obsługi zdarzeń wywołaj metodę IMediaEvent::GetEvent, aby pobrać zdarzenia z kolejki:
void HandleGraphEvent()
{
// Disregard if we don't have an IMediaEventEx pointer.
if (g_pEvent == NULL)
{
return;
}
// Get all the events
long evCode;
LONG_PTR param1, param2;
HRESULT hr;
while (SUCCEEDED(g_pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0)))
{
g_pEvent->FreeEventParams(evCode, param1, param2);
switch (evCode)
{
case EC_COMPLETE: // Fall through.
case EC_USERABORT: // Fall through.
case EC_ERRORABORT:
CleanUp();
PostQuitMessage(0);
return;
}
}
}
Metoda GetEvent pobiera kod zdarzenia i dwa parametry zdarzenia. Czwarty getEvent parametr określa czas oczekiwania na zdarzenie w milisekundach. Ponieważ aplikacja wywołuje tę metodę w odpowiedzi na komunikat WM_GRAPHNOTIFY, zdarzenie jest już w kolejce. W związku z tym ustawiliśmy wartość limitu czasu na zero.
Powiadomienie o zdarzeniach i pętla komunikatu są asynchroniczne, więc kolejka może przechowywać więcej niż jedno zdarzenie o czasie, gdy aplikacja odpowie na komunikat. Ponadto Menedżer filtrów programu Graph może usunąć niektóre zdarzenia z kolejki, jeśli staną się nieprawidłowe. W związku z tym należy wywołać getEvent, dopóki nie zwróci kodu błędu, co oznacza, że kolejka jest pusta.
W tym przykładzie aplikacja odpowiada na EC_COMPLETE, EC_USERABORTi EC_ERRORABORT poprzez wywołanie funkcji CleanUp zdefiniowanej przez aplikację, co powoduje, że aplikacja kończy działanie w uporządkowany sposób. W przykładzie są ignorowane dwa parametry zdarzenia. Po pobraniu zdarzenia wywołaj IMediaEvent::FreeEventParams, aby zwolnić wszelkie zasoby skojarzone z parametrami zdarzenia.
Należy pamiętać, że zdarzenie EC_COMPLETE nie powoduje zatrzymania wykresu filtru. Aplikacja może zatrzymać lub wstrzymać graf. Jeśli zatrzymasz graf, filtry zwalniają wszystkie zasoby, które przechowują. Jeśli wstrzymasz graf, filtry będą nadal przechowywać zasoby. Ponadto, gdy program renderujący wideo zostanie wstrzymany, wyświetla zamrożony obraz ostatniej klatki.
Przed wydaniem wskaźnika IMediaEventEx anuluj powiadomienie o zdarzeniu, wywołując SetNotifyWindow z uchwytem okna NULL:
// Disable event notification before releasing the graph.
g_pEvent->SetNotifyWindow(NULL, 0, 0);
g_pEvent->Release();
g_pEvent = NULL;
W obsłudze komunikatu WM_GRAPHNOTIFY sprawdź wskaźnik IMediaEventEx przed wywołaniem GetEvent:
if (g_pEvent == NULL) return;
Zapobiega to możliwemu błędowi, który może wystąpić, jeśli aplikacja otrzyma powiadomienie o zdarzeniu po zwolnieniu wskaźnika.
Tematy pokrewne