DirectShow DirectShow 에 대해 DirectShow 에서의 이벤트 통지 이벤트 발생시의 확인   [목차열람] [주소복사] [슬롯비우기]
이벤트 발생시의 확인
 
Microsoft DirectX 9.0

이벤트 발생시의 확인

DirectShow 의 이벤트를 처리하기 위해서, 애플리케이션에는 이벤트가 큐내에서 대기 상태인 것을 검출할 방법이 필요하다. 필터 그래프 매니저는 그 때문에(위해) 2 개의 방법을 제공하고 있다.

애플리케이션에서는, 몇개의 방법을 사용할 수 있다. 보통, 윈도우 통지가 단순하다.

윈도우 통지

윈도우 통지를 셋업 하려면 ,IMediaEventEx::SetNotifyWindow 메서드를 호출해, Private 메시지를 지정한다. 애플리케이션에서는, WM_APP 로부터 0xBFFF 까지의 범위의 메시지 번호를 Private 메시지로서 사용할 수 있다. 필터 그래프 매니저는, 새로운 이벤트 통지를 큐에 넣으면 지정된 윈도우에 이 메시지를 송신한다. 애플리케이션은 윈도우의 메시지 루프내로부터 메시지에 응답한다.

다음 샘플 코드는, 통지 윈도우의 설정 방법법을 나타내고 있다.

#define WM_GRAPHNOTIFY WM_APP + 1   // Private 메시지.
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();  // 애플리케이션 정의의 함수.
            break;
        // 여기서 다른 Windows 메시지도 처리한다.
    }
    return (DefWindowProc(hwnd, msg, wParam, lParam));
}

이벤트 통지와 메시지 루프는 양쪽 모두 비동기이기 (위해)때문에, 애플리케이션이 메시지에 응답 하면 와까지, 복수의 이벤트가 큐에 들어가 있는 일이 있다. 또, 이벤트가 무효가 되었을 때는 큐로부터 이벤트가 클리어 되는 일이 있다. 따라서, 이벤트 처리 코드에서는, 큐가 하늘인 것을 나타내는 에러 코드가 돌려주어질 때까지 GetEvent 를 호출하는 것.

IMediaEventEx 포인터를 릴리즈 하기 전에, NULL 포인터를 지정해 SetNotifyWindow 를 호출하는 것에 의해 이벤트 통지를 취소한다. 이벤트 처리 코드에서는,GetEvent 를 호출하기 전에,IMediaEventEx 포인터가 유효한지 어떤지를 체크하는 것. 이러한 순서에 의해, 애플리케이션이 IMediaEventEx 포인터를 릴리즈 한 다음에 이벤트 통지를 수신 하면 말하는 에러를 방지할 수 있다.

이벤트 송신

필터 그래프 매니저는 이벤트 큐 상태를 반영한 수동 리셋 이벤트를 보관 유지한다. 큐에 보류 상태의 이벤트 통지가 포함되어 있는 경우, 필터 그래프 매니저는 수동 리셋 이벤트를 송신한다. 큐가 하늘의 경우는,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)
{
    /* 에러 처리 코드를 여기에 삽입한다.  */
}
while(! bDone) 
{
    if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
    { 
        while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr)) 
        {
            printf("Event code: %#04x\n Params: %d, %d\n", evCode, param1, param2);
            pEvent->FreeEventParams(evCode, param1, param2);
            bDone = (EC_COMPLETE == evCode);
        }
    }
} 

필터 그래프가 필요에 따라서 이벤트를 자동적으로 설정 또는 리셋 하므로, 애플리케이션으로 이벤트의 설정 또는 리셋을 실시해서는 안된다. 게다가 필터 그래프를 릴리즈 하면 필터 그래프는 이벤트 핸들을 닫는다. 그 때문에, 그 후는 이벤트 핸들을 사용하지 않는 것.

↑TOP