Share via


이벤트가 발생하는 경우 학습

[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드가 DirectShow 대신 Media Foundation에서 MediaPlayer, IMFMediaEngine오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

DirectShow 이벤트를 처리하려면 애플리케이션에서 큐에서 이벤트가 대기하는 시기를 확인하는 방법이 필요합니다. Filter Graph Manager는 다음 두 가지 방법을 제공합니다.

  • 창 알림: Filter Graph Manager는 새 이벤트가 있을 때마다 사용자 정의 Windows 메시지를 애플리케이션 창으로 보냅니다.
  • 이벤트 신호: Filter Graph Manager는 큐에 DirectShow 이벤트가 있는 경우 Windows 이벤트를 알리고 큐가 비어 있는 경우 이벤트를 다시 설정합니다.

애플리케이션은 두 가지 기술 중 하나를 사용할 수 있습니다. 창 알림은 일반적으로 더 간단합니다.

창 알림

창 알림을 설정하려면 IMediaEventEx::SetNotifyWindow 메서드를 호출하고 프라이빗 메시지를 지정합니다. 애플리케이션은 WM_APP 0xBFFF 범위의 메시지 번호를 프라이빗 메시지로 사용할 수 있습니다. Filter Graph Manager가 큐에 새 이벤트 알림을 배치할 때마다 지정된 창에 이 메시지를 게시합니다. 애플리케이션은 창의 메시지 루프 내에서 메시지에 응답합니다.

다음 코드 예제에서는 알림 창을 설정하는 방법을 보여줍니다.

#define WM_GRAPHNOTIFY WM_APP + 1   // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

메시지는 일반 Windows 메시지이며 DirectShow 이벤트 알림 큐와 별도로 게시됩니다. 이 방법의 장점은 대부분의 애플리케이션이 이미 메시지 루프를 구현한다는 것입니다. 따라서 추가 작업 없이 DirectShow 이벤트 처리를 통합할 수 있습니다.

다음 코드 예제에서는 알림 메시지에 응답하는 방법에 대한 개요를 보여줍니다. 전체 예제는 이벤트에 응답을 참조하세요.

LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
    switch (msg)
    {
        case WM_GRAPHNOTIFY:
            HandleEvent();  // Application-defined function.
            break;
        // Handle other Windows messages here too.
    }
    return (DefWindowProc(hwnd, msg, wParam, lParam));
}

이벤트 알림과 메시지 루프는 모두 비동기이므로 애플리케이션이 메시지에 응답할 때까지 큐에 둘 이상의 이벤트가 포함될 수 있습니다. 또한 이벤트가 유효하지 않은 경우 큐에서 이벤트를 지울 수 있습니다. 따라서 이벤트 처리 코드에서 오류 코드를 반환할 때까지 IAMMediaEvent::GetEvent 를 호출하여 큐가 비어 있음을 나타냅니다.

IMediaEventEx 포인터를 해제하기 전에 NULL 포인터를 사용하여 SetNotifyWindow를 호출하여 이벤트 알림을 취소합니다. 이벤트 처리 코드에서 GetEvent를 호출하기 전에 IMediaEventEx 포인터가 유효한지 여부를 검사. 이러한 단계는 IMediaEventEx 포인터를 릴리스한 후 애플리케이션이 이벤트 알림을 수신하는 가능한 오류를 방지합니다.

이벤트 신호

Filter Graph Manager는 이벤트 큐의 상태를 반영하는 수동 재설정 이벤트를 유지합니다. 큐에 보류 중인 이벤트 알림이 포함된 경우 Filter Graph Manager는 수동 재설정 이벤트에 신호를 보냅니다. 큐가 비어 있으면 IMediaEvent::GetEvent 메서드를 호출하면 이벤트가 다시 설정됩니다. 애플리케이션은 이 이벤트를 사용하여 큐의 상태를 확인할 수 있습니다.

참고

여기서 용어는 혼동될 수 있습니다. 수동 재설정 이벤트는 Windows CreateEvent 함수에서 만든 이벤트의 유형입니다. DirectShow에서 정의한 이벤트와는 아무 상관이 없습니다.

 

IMediaEvent::GetEventHandle 메서드를 호출하여 수동 재설정 이벤트에 대한 핸들을 가져옵니다. WaitForMultipleObjects와 같은 함수를 호출하여 이벤트가 신호를 받을 때까지 기다립니다. 이벤트가 신호를 받으면 IMediaEvent::GetEvent 를 호출하여 DirectShow 이벤트를 가져옵니다.

다음 코드 예제에서 이 접근 방식을 보여 줍니다. 이벤트 핸들을 가져오고 이벤트가 신호를 받을 때까지 100밀리초 간격으로 기다립니다. 이벤트가 신호를 받으면 GetEvent 를 호출하고 이벤트 코드 및 이벤트 매개 변수를 콘솔 창에 출력합니다. EC_COMPLETE 이벤트가 발생하면 루프가 종료되어 재생이 완료되었음을 나타냅니다.

HANDLE  hEvent; 
long    evCode, param1, param2;
BOOLEAN bDone = FALSE;
HRESULT hr = S_OK;
hr = pEvent->GetEventHandle((OAEVENT*)&hEvent);
if (FAILED(hr))
{
    /* Insert failure-handling code here. */
}

while(!bDone) 
{
    if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
    { 
        while (S_OK == pEvent->GetEvent(&evCode, &param1, &param2, 0)) 
        {
            printf("Event code: %#04x\n Params: %d, %d\n", evCode, param1, param2);
            pEvent->FreeEventParams(evCode, param1, param2);
            bDone = (EC_COMPLETE == evCode);
        }
    }
} 

필터 그래프는 적절한 경우 이벤트를 자동으로 설정하거나 다시 설정하므로 애플리케이션에서 설정하면 안 됩니다. 또한 필터 그래프를 해제하면 필터 그래프가 이벤트 핸들을 닫기 때문에 해당 지점 이후에는 이벤트 핸들을 사용하지 마세요.