본문 바로가기

About Programing/07. Direct Show

[DirectShow기초] File Play

이 예는 MSDN에 나온 샘플 DirectShow어플리케이션이다. 
 
앞에서 말했던 DirectShow 어플리케이션 작성의 4가지 스텝을 다시 기억해 보자.

1. 필터그래프 매니저의 인스턴스 생성
2. 매니저를 이용해서 필터 그래프 생성
3. 매니저를 이용해서 필터그래프에서 데이터를 처리하도록 함
4. 사용이 끝나면 리소스 반환

1. 인스턴스 생성
 앞에서 이야기했듯이 매니저나 필터 모두 COM객체이기 때문에, 우선 COM라이브러리를 초기화 해야 한다.
이 작업은 CoInitialize를 호출함으로써 이루어진다.
 

HRESULT hr = CoInitialize(NULL); 

if (FAILED(hr)) { 

         // 에러처리 코드(간단하게 하기 위해 생략) 

}



 에러처리는 생략했으며, 필요한 분은 COM책을 들여다 보시면 다 있다.
(참고로, MSDN에 따르면, DirectShow는 free-threading model이기 때문에,
COINIT_MULTITHREADED옵션을 사용해도 된다고 한다.이때는 CoINitializeEx를 사용하라.)
 이제 필터그래프매니저를 생성해야 한다. COM에서는 객체 생성을 위해 CoCreateInstance를 사용한다.

IGraphBuilder *pGraph;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); 


 CLSID_FilterGraph는 필터그래프매니저의 클래스ID이다.
(뭔소린지 모르는 분은 COM책을 보시라. 앞으로 설명할 내용에서 나오는 용어들도 마찬가지).
 또한, 이 예제에서는 inprocess DLL로 사용하기 때문에, CLSCTX_INPROC_SERVER로
실행 컨택스트를 정해준다. IID_IGraphBuilder는 우리가 사용할 인터페이스 ID이다. 이 인터페이스는
그래프 생성시 사용할 메소드들이 정의되어 있다. pGraph의 주소를 void**로 넘겨주는것은
CoCreateInstance함수가 그렇게 정의되어 있기 때문이다.
 CoCreateInstance함수는 pGraph에다 생성된 COM객체의 인터페이스에 대한 포인터를 넘겨주게 된다.
 
이제 IGraphBuilder인터페이스를 얻었고, 다른 두개의 인터페이스를 얻을 차례이다.

- IMediaControl은 스트리밍을 콘트롤한다. 그래프의 작동을 시작하고, 중지하는 메소드를 포함하고 있다.
- IMediaEvent는 필터그래프매니저에서 발생하는 이벤트를 얻기 위한 메소드를 제공한다.
 
두 인터페이스 모두 IGraphBuilder에다 QueryInterface를 해서 얻는다.
 
IMediaControl *pControl;
IMediaEvent *pEvent;

hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl); 
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

 
2. 그래프 생성
 이제 필터그래프를 만들수 있게 되었다. 파일을 플레이하기 위한 필터그래프는 다음 메소드를
호출해서 할 수 있다.
 
hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
 

 IGraphBuilder::RenderFile 메소드는 지정한 파일을 읽을 수 있는 필터그래프를 생성한다.
첫번째 파라미터는 wide character타입이다. 따라서, L"C:\\Example.avi"을 사용했다.
두번째 파라미터는 항상 NULL이어야 한다.

이 메소드는 파일이 없거나, 파일의 포맷을 알아낼 수 없을 경우 실패한다. 
메소드에서 성공하게 되면, 그래프 생성이 완료된 것이고, 파일의 플레이를 시작할 수 있게 된 것이다. 
 
3. 그래프 동작 
 필터그래프 생성후, IMediaControl::Run을 호출하면 그래프가 동작하게 된다.
즉, 파일을 플레이하게 된다는 것이다. 다음과 같이 호출한다.
 
hr = pControl->Run();
 

 필터 그래프가 동작하게 되면, 데이터가 필터 그래프를 통해 흘러서 비디오와 오디오가 렌더링되게 된다.
이때 비디오/오디오의 플레이는 독립된 쓰레드로 진행된다.  
 플레이의 완료까지 기다리려면 IMediaEvent::WaitForCompletion메소드를 호출함으로써 기다릴 수 있다.  
 
long evCode = 0;
pEvent->WaitForCompletion(INFINITE, &evCode);
 
 
 이 메소드는 플레이가 종료되거나, 지정한 시간이 지날 될 때까지 블럭되며,
이벤트를 evCode에 넘겨주게 된다. 어플리케이션은 이벤트코드를 보고 어떤 이유로
WaitForCompletion이 리턴했는지를 알수 있다.
 
4. 리소스 해제 
사용이 끝난 COM객체는 release해주고, COM라이브러리도 반환해야 한다. 다음과 같다. 
 
pControl->Release(); 
pEvent->Release(); 
pGraph->Release(); 
CoUninitialize(); 
 


* 링크 및 실행 방법
다음 파일은 항상 Include 해야 한다.

Dshow.h

링크시에는 다음을 참조해 필요한 라이브러리는 함께 링크해야 한다.

Strmiids.lib : 모든 DirectShow 어플리케이션에 필요.
Quartz.lib : AMGetErrorText 메서드의 호출에 필요.
Strmbase.lib :DirectShow의 base classes를 사용할 경우만 필요

 dshow.h를 사용하기 위해서는 platform SDK를 깔아야 하며, directX SDK도 함께 깔아야 한다.
두 파일은 모두 MS의 다운로드 페이지나 naver자료실에서 다운로드 받을 수 있다.