DirectShow DirectShow 튜토리얼 AVI 파일의 재압축 파일의 쓰기   [목차열람] [주소복사] [슬롯비우기]
파일의 쓰기
 
Microsoft DirectX 9.0

파일의 쓰기

파일을 기입하려면 ,IMediaControl::Run 메서드를 호출해, 필터 그래프를 실행하는 것만으로 있다. 재생이 종료하는 것을 기다리고 나서,IMediaControl::Stop 를 호출해 그래프를 명시적으로 정지하는 것. 이와 같이 하지 않으면 파일은 올바르게 기입해지지 않다.

파일 쓰기 처리의 진행 상황을 표시하려면 , Mux 필터에 IMediaSeeking 인터페이스의 유무를 문의한다. IMediaSeeking::GetDuration 메서드를 호출해, 파일의 시간폭을 얻어온다. 그래프의 실행중은, 정기적으로 IMediaSeeking::GetCurrentPosition 메서드를 호출해, 스트림에서의 그래프의 현재 위치를 얻어온다. 현재 위치를 시간폭으로 나누면 완료한 비율을 얻을 수 있다.

 :  애플리케이션은 보통, 필터 그래프 매니저에 IMediaSeeking 의 유무를 문의하지만, 파일의 쓰기는, 이 규칙의 예외이다. 필터 그래프 매니저는, 시작 위치와 그래프가 실행하고 나서의 경과시간부터 현재 위치를 계산하지만, 이 계산방법은 파일 재생에 대해서는 정확해도, 파일 쓰기에 대해서는 정확하지 않다. 따라서, 정확한 결과를 얻기 위해서(때문에)는, MUX 필터로부터 위치를 얻어올 필요가 있다.

다음 코드에서는, 파일의 시간폭을 취득해, 타이머를 시작 해 애플리케이션 UI 를 업데이트 해, 필터 그래프를 실행한다. 간결하게 하기 위한(해), 에러 체크는 생략 했다.

IMediaSeeking *pSeek = NULL;
IMediaEventEx *pEvent = NULL;
IMediaControl *pControl = NULL;
REFERENCE_TIME rtTotal;

// 인터페이스의 유무를 문의한다. 다음에 잊지 않고 릴리즈 하는 것.
hr = pMux->QueryInterface(IID_IMediaSeeking, (void**) &pSeek);
hr = pGraph->QueryInterface(IID_IMediaEventEx, (void**) &pEvent);
hr = pGraph->QueryInterface(IID_IMediaControl, (void**) &pControl);

// 간결하게 하기 위한(해), 에러 체크는 생략 했다.

// DirectShow 이벤트 통지 윈도우를 설정한다.
hr = pEvent->SetNotifyWindow((OAHWND) hwnd, WM_GRAPHNOTIFY, 0);

// progress bar의 범위를 파일의 길이 (초단위)로 설정한다.
hr = pSeek->GetDuration(&rtTotal);
SendDlgItemMessage(hwnd, IDC_PROGRESS1, PBM_SETRANGE, 0, 
   MAKELPARAM(0, rtTotal / 10000000));
// 타이머를 시작 한다.
UINT_PTR res = SetTimer(hwnd, nIDEvent, 100, NULL);
// 그래프를 실행한다.
pControl->Run();

애플리케이션이 바다거북 겨이삭띠를 받으면 정확한 위치에서 UI 를 업데이트 할 수 있다.

void OnTimer(HWND hDlg, IMediaSeeking *pSeek)
{
    REFERENCE_TIME rtNow;
    HRESULT hr = pSeek->GetCurrentPosition(&rtNow);
    if (SUCCEEDED(hr))
    {
        SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, rtNow/10000000, 0);
    }
}

애플리케이션이 DirectShow 종료 이벤트를 받으면 다음 코드에 나타내도록(듯이) 그래프를 정지해야 한다.

// 애플리케이션 윈도우 프로시저.
LRESULT CALLBACK WndProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    /*  ...  */
    case WM_GRAPHNOTIFY:
        DoHandleEvent();
        break;
    /*  ...  */
    }
}

void DoHandleEvent()
{
    long evCode, param1, param2;
    bool bComplete = false;
    if (! pEvent) return;

    // 모든 이벤트를 취득해, 완료한 것을 확인한다.
    while (SUCCEEDED(pEvent->GetEvent(&evCode, &param1, &param2, 0))
    {
        pEvent->FreeEventParams(evCode, param1, param2);
        switch(evCode)
        {
            case EC_USERABORT:
            case EC_ERRORABORT:
            case EC_COMPLETE:
                bComplete = true;
                break;
        }
    }
    if (bComplete)
    {
        pControl->Stop(); // 중요!  그래프를 정지할 필요가 있다!

        // 이벤트 통지를 무효로 한다.
        pEvent->SetNotifyWindow(NULL, 0, 0);
        pEvent->Release();
        pEvent = NULL;
        // progress bar를 제로에 리셋 해, 타이머를 없앤다.
        SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, 0, 0);
        KillTimer(hwnd, nIDEvent);
    }
}
↑TOP