ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • VMR9 다이렉트 쇼.
    GamePrograming/Direct3D 2010. 7. 15. 10:22

    VMR9을 이용한 동영상 재생 클래스

     

    DirectX9 VMR9(Video Mixing Renderer)을 사용한 동영상 재생 및 믹싱 클래스

     

    쥬얼리 - One More Time

     

    Introduction

     비디오 파일을 재생하기 위해 DirectShow Video Mixing Renderer9을 사용한 간단한 래퍼 클래스.

     DirectX9 에서는 멀티미디어 응용프로그램에서 새로운 비디오 렌더러를 사용할 수 있다.
    하지만, 이 렌더러(VMR9)는 호환성 문제 때문에 기본 렌더러로 사용되지 않는다.
    Windows XP에서 기본 렌더러는 VMR7 이다. 이 렌더러는 하위버전 윈도우에 있던 것이다.

     가장 큰 차이점은 성능과 오버레이 믹싱 능력: VMR7은 DirectDraw를 사용하고, VMR9은 그래픽카드의 3D가속 기능을 지원하는 Direct3D를 기반으로 한다.

    그 결과 최근 그래픽카드에서 향상된 성능, 더 나은 오버레이 믹싱, DirectX9을 지원하는 윈도우에서 호환성
    그리고, de-interlacing & ProcAmp (contrast, saturation, etc.)과 같은 몇가지 새로운 기능을 사용할 수 있다.

     

    아무튼, VMR9이 매우 훌륭해 보이지만 윈도우 버전에 관계없이 기본 렌더러가 아니다.
    그래서 VMR9을 수동으로 붙여야 하며 이 클래스를 만든 이유다.

     What you need...

     데모를 실행하려면 DirectX9 runtime이 설치되어 있어야 하고, Direct3D와 호환되는 그래픽카드가 장착되어 있어야 한다.
    빌드하려면 DirectX9 SDK를 깔아야 한다. 소스는 Visual C++ 6 SP5, Visual Studio .NET 2003 SP1에서 생성했다.

     

     Using the code

     

    A first look

     

    모든 DirectShow 그래프 관리 및 VMR 루틴은 클래스 하나에 포함되어 있다 : CVMR9Graph.

     

    [-] Collapse

    class CVMR9Graph
    {
        // Constructor / destructor
    public:
        CVMR9Graph();
        CVMR9Graph(HWND MediaWindow,
                 int NumberOfStream = 4);
        virtual ~CVMR9Graph();

        // Methods
    public:
        // Graph configuration
        void SetNumberOfLayer(int nNumberOfLayer);
        BOOL SetMediaWindow(HWND MediaWindow);
        BOOL SetMediaFile(const char* pszFileName,
                                 int nLayer = 0);
        BOOL PreserveAspectRatio(BOOL bPreserve = TRUE);
        IBaseFilter* AddFilter(const char* pszName,
                                 const GUID& clsid);

        // Graph control
        BOOL PlayGraph();
        BOOL StopGraph();
        BOOL ResetGraph();
        IMediaEvent* GetPtrMediaEvent();
        IMediaControl* GetPtrMediaControl();
        IMediaSeeking* GetPtrMediaSeeking();
        IBasicAudio* GetPtrBasicAudio();


        // Layer control
        BOOL GetVideoRect(LPRECT pRect);
        int GetAlphaLayer(int nLayer);
        BOOL SetAlphaLayer(int nLayer, int nAlpha);
        DWORD GetLayerZOrder(int nLayer);
        BOOL SetLayerZOrder(int nLayer, DWORD dwZOrder);
        BOOL SetLayerRect(int nLayer, RECT layerRect);

        // Bitmap control
        BOOL SetBitmap(const char* pszBitmapFileName,
          int nAlpha, COLORREF cTransColor, RECT bitmapRect);
        BOOL SetBitmapParams(int nAlpha,
          COLORREF cTransColor, RECT bitmapRect);

        // Reflected from window
        BOOL Repaint();
        BOOL Resize();

        // helper
        LPCTSTR GetLastError();

    protected:
        // [...]
    };

     

    편의를 위해 헤더에 DirectShow, Direct3D 헤더와 pragma 지시자로 lib를 포함하도록 했다.

     

    Step 1 : Building a simple player

     

    간단한 동영상 플레이어 만들기 아주 쉽다:

    1. 프로젝트에 VMR9Graph.hVMR9Graph.cpp 파일을 포함한다,
    2. 응용프로그램에 CVMR9Graph 인스턴스를 추가,
    3. 동영상 재생을 위한 윈도우를 만든다,
    4. CVMR9Graph::SetMediaWindow(hMyVideoPlaybackHandle)를 호출하여 동영상 재생 윈도우 설정,
    5. CVMR9Graph::SetMediaFile(0, pszPathToMyFile)을 호출하여 재생할 동영상 파일을 설정,
    6. CVMR9Graph::RunGraph() 호출하여 동영상을 재생한다.

    이러면 동영상이 재생되지만 동영상 크기에 맞게 창이 조정되지는 않는다...

     

    Step 2 : Forwarding events

     

    응용프로그램에서 동영상 갱신이나 창크기를 그래프에게 전달해야 한다:

    • WM_SIZE 메시지 핸들러를 만들어 CVMR9Graph::Resize()를 호출하고,
    • WM_PAINT 메시지 핸들러를 만들어 CVMR9Graph::Repaint()를 호출한다.

    CVMR9Graph::PreserveAspectRatio(FALSE)를 호출하여 동영상 가로/세로 비율을 유지 여부를 지정할 수 있다.

     

    Step 3: Mixing video

     

    여러개의 파일은 재생 레이어로 처리됐다. 각 레이어는 알파 블렌딩, 크기, 위치 같은 몇가지 속성을 지원한다.

    여러 레이어 동영상은 크기가 큰 것을 기준으로 처리된다.

     

    삽입된 각 레이어는 인덱스로 식별한다;

     

    다음 예제는 동영상 파일 2개를 읽어서 첫번째 동영상의 알파값을 50%로 설정한다.

     

    [-] Collapse

    // load media files
    myGraph.SetMediaFile(0, "C:\\Video1.avi");
    myGraph.SetMediaFile(1, "C:\\Video2.mpg");

    // set alpha value to video1
    myGraph.SetAlphaLayer(0, 50);

     

    데모 프로그램에서 알파값이 실시간으로 적용되는 것을 볼 수 있다.

     

    Note 1: 나는 DivX 파일 2개를 믹싱할 수 없지만, DivX 하나와 다른 코덱은 가능하다... 왜 그런지 모르겠다... DirectShow 샘플도 같은 문제가 있다.

    Note 2: CVMR9Graph는 사운드 렌더러를 하나만 붙인다. 그래서 첫번째 동영상만 소리가 나온다. 사운드 렌더러를 추가하려면 CVMR9Graph::AddFilter(_T"Another Sound Renderer", CLSID_DSoundRender)를 호출하면 된다.

     

    Step 4 : Setting an overlay bitmap

     

    CVMR9Graph에서 오버레이 비트맵은 Direct3D 서피스에 로딩된다. 비트맵 형식은 GIF, JPEG, PNG, BMP, DIB, TGA, or DDS format.

     

    오버레이 비트맵은 다음 파라메터와 함께 CVMR9Graph::SetBitmap()을 호출한다 :

    • 비트맵 파일의 경로,
    • 알파값 (오버레이 비트맵은 최상위에 나타난다),
    • 비트맵 투명 컬러키,
    • 비트맵 크기와 위치.

    오버레이 비트맵은 상당히 유용한 기능이다:

    • 조그만 오버레이 표시기를 표현하거나,
    • 동영상 영역을 오려낼 때 (비정형 스킨 윈도우를 만들어 재생하면 재밌을 듯...).

     

    Last step: Go further away

     

    클래스는 간결하고 재생 컨트롤은 최소화하려고 했는데 다음의 DirectShow 인터패이스를 추가할 수 있다. 

    • IMediaEvent: 그래프의 상태와 이벤트를 받는다. CVMR9Graph는 자동으로 WM_MEDIA_NOTIF 메시지를 재생창에 보낸다; 이때 IMediaEvent::GetEvent()를 호출하여 이벤트 타입을 얻어오면 된다.
    • IMediaControl: 재생, 일시정지 등의 기능을 제공한다.
    • IMediaSeeking: 재생 속도와 위치를 제어할 수 있다.
    • IBasicAudio: 사운드 볼륨과 밸런스를 제어할 수 있다.

     

    Known issue

     그래프가 동작중일 때, CVMR9Graph::Stop() 이나 CVMR9Graph::SetMediaFile()을 호출할 수 있지만 일부의 경우에 제대로 동작하지 않는다. 특히 비트맵 파일과 조합한 후...

     CVMR9Graph::ResetGraph()를 호출하면 그래프를 파괴하고 새 인스턴스를 생성한다.

     재생 창을 리사이징할 때 약간 깜박임이 있다... 왜냐하면 MFC window와 표준 OnEraseBackgnd() 구현 때문이다? -_-;;

     

    // TODO : some improvements 

    IVMRMonitorConfig9 인터페이스가 있지만 사용하지 않는다. 멀티 모니터에서 유용하다.

    - 데브피아 오새롬(diebuster)님 글 펌 -

    댓글

Designed by Tistory.