coding2007/02/13 11:27

특정위도우에 비디오 재생을 하는 방법에 대해 설명하겠습니다.

...

비디오파일을 나타낼때, filter graph는 video renderer filter가 포함되어 있어야 합니다.
비디오는 압축되지 않은 데이터를 비디오 데이터를 입력 받고 윈도우에 스크린 나타는것을 나타냅니다.


달리지정하지않으면, 비디오 재생 윈도우는 타이틀바와 테두리가 있는 최상위 윈도우입니다.
어플리케이션에서 만든 특정윈도우에서 비디오가 나타나기를 원할것입니다.
어플리케이션 윈도우의 자식 비디오 윈도우에 나타나게 만들것입니다.

윈도우의 위치, 스타일 지정한 비디오 윈도우의 프로퍼티를 세팅해서 만들수 있습니다.
Filter Graph Manager의 IVideoWindow 인터페이스로 이걸 할수 있습니다.

첫번째로 filter graph manager의 인스턴스를 만들고, IGraphBuilder::RenderFile 메소드를 호출하여 filter graph를 생성합니다.

그리고, 재생을 시작하기전에 비디오 윈도우의 프로퍼티를 다음과 같이 세팅합니다.


1. 비디오 재생 윈도우를 원하는 부모윈도우에 붙입니다.
이것을 하기 위해, IVideoWindow::put_Owner 메소드를 호출하여 부모윈도우의 핸들을 넘깁니다.
이 메소드는 OAHWND 타입의 변수 하나를 받는다. 그래서 이 타입으로 핸들을 캐스팅합니다.

IVideoWindow *pVidWind = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVidWin);
pVidWin->put_Owner((OAHWND)g_hwnd);


2. 비디오 윈도우의 스타일을 차일드 윈도우로 바꿉니다.
이것을 하기위하여, IVideoWindow::put_WindowStyle 메소드를 호출하고 스타일 플래그 조합을 넘깁니다.
WS_CHILD 윈도우는 윈도우가 자식윈도우를 갖는것이고 WS_CLIPSIBLINGS 플래그는 다른 자식윈도우의 클라이언트 영역에 그려지는것을 막습니다.

pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);


3. IVideoWindow::SetWindowPosition 메소드를 호출해서 비디오 윈도우의 위치를 세팅합니다.
이 메소드는 윈도우의 왼쪽 끝, 위쪽 끝, 길이와 높이의 장치 장표를 지정합니다.
예제 프로그램은 부모 윈도우 전체에 채우기 위해 비디오 윈도우를 늘립니다.

RECT grc;
GetClientRect(g_hwnd, &grc);
pVidWind->SetWindowPosition(0, 0, grc.right, grc.bottom);

GetClientRect 함수는 RECT 구조체를 윈도우의 클라이언트 영역의 좌표로 채웁니다.
좌표는 클라이언트 영역의 upper-left 코너와 관련이 있어서, left와 top은 0이고 right와 bottom은 width와 height로 정의 되어있습니다.

어플리케이션 종료 전에 비디오 윈도우의 visibility를 false로 세팅해야 합니다.
다른 방법으로, 스크린에 비디오 이미지가 남아있고, 사용자가 그것을 없앨수 없습니다.
그러므로, 오너를 NULL로 리셋합니다.
다르게 윈도우에 다른 윈도우에 메세지를 보내서 에러의 원인이 될수 있습니다.

HRESULT hr = pVidWin->put_Visible(OAFALSE);
hr = pVidWin-put_Owner(NULL);

예제소스

#############################################
***** Header *****
#############################################


void CleanUp();
void PlayFile();


IGraphBuilder *m_pGraph;
IMediaControl *m_pMediaControl;
IVideoWindow *m_pVidWin;

afx_msg void OnButton2();//Video Window Play
afx_msg void OnButton3();//Video Window End


#############################################
***** Cpp *****
#############################################

/////////////////////////////
//Setting the Video Window
/////////////////////////////
void CDShowTestDlg::PlayFile()
{
m_pGraph = NULL;
m_pMediaControl = NULL;
m_pVidWin = NULL;

CoInitialize(NULL);

CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void**)&m_pGraph);

m_pGraph->QueryInterface(IID_IMediaControl, (void**)&m_pMediaControl);
m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&m_pVidWin);

//The RenderFile method builds a filter graph that renders the specified file.
m_pGraph->RenderFile(L"D:\\exam.wmv", NULL);


//The put_Owner method specifies a parent window for the video window.
m_pVidWin->put_Owner((OAHWND)(GetDlgItem(IDC_STATIC1)->m_hWnd));
//The put_WindowStyle method sets the window styles on the video window.
m_pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

RECT grc;
GetDlgItem(IDC_STATIC1)->GetClientRect(&grc);
//The SetWindowPosition method sets the position of the video window.
m_pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);


//The Run method runs all the filters in the filter graph.
//While the graph is running, data moves through the graph and is rendered.
m_pMediaControl->Run();
}

/////////////////////////////
//Setting the Video Window
/////////////////////////////
void CDShowTestDlg::CleanUp()
{
//The put_Visible method shows or hides the video window.
m_pVidWin->put_Visible(OAFALSE);
//Reset the owner to NULL before releasing the Filter Graph Manager.
m_pVidWin->put_Owner(NULL);


m_pMediaControl->Release();
m_pVidWin->Release();
m_pGraph->Release();
}

////////////////////////////////////
//Setting the Video Window
//Video Window Play
//////////////////////////////////////
void CDShowTestDlg::OnButton2()
{
// TODO: Add your control notification handler code here
PlayFile();

}

///////////////////////////////
//Setting the Video Window
//Video Window End
//////////////////////////////
void CDShowTestDlg::OnButton3()
{
// TODO: Add your control notification handler code here
CleanUp();

CoUninitialize();
}


'coding' 카테고리의 다른 글

ODBC를 이용하여 Excel 파일 만들기  (0) 2007/02/13
DirectShow 비디오 윈도우 셋팅  (10) 2007/02/13
DirectShow 재생 방법  (0) 2007/02/13
DirectShow 빌드 셋팅  (0) 2007/02/13
Posted by redef
TAG ,

TRACKBACK http://www.redef.pe.kr/trackback/30 관련글 쓰기

댓글을 달아 주세요

  1. 글쓴이님 샘플프로젝트소스를 얻을수 없을까요? yuninsig@hanmail.net

    2009/07/06 17:12 [ ADDR : EDIT/ DEL : REPLY ]
    • 안녕하세요...
      샘플프로젝트는 direct sdk를 설치하시면 예제코드가 있습니다...
      위의 글 역시 direct show 도움말을 참고했던 내용입니다..

      2009/07/06 18:08 [ ADDR : EDIT/ DEL ]
  2. 따라하기 스샷식으로 알려주시기는 어렵겠죠?; 다이어로그창을 하나 만들어서 해야하는건지..

    2009/07/07 16:43 [ ADDR : EDIT/ DEL : REPLY ]
    • 소스 자체는 정말 간단합니다...
      간단하게 만든 예제를 메일로 보내드렸습니다.
      헤더파일에 약간의 설명을 첨부했으니 같이 확인해보세요..
      도움이 되실지 모르겠네요...^^

      2009/07/07 18:07 [ ADDR : EDIT/ DEL ]
  3. gogogo2729

    문의드릴게있습니다.
    지금 다이렉트쇼로 미디어 플레이어를 만들고 잇는중인데..
    곰플레이어 처럼 다음 파일로 넘어갈때 전체화면이 유지가 될려면 어떻게해야되는지 부탁드립니다..
    제가 만들고 있는 것에서는 다음파일로 넘어갈때 전체화면이 꺼졌다가 다음 파일로 넘어가면 다시 전체화면이 됩니다..

    2009/08/03 04:02 [ ADDR : EDIT/ DEL : REPLY ]
    • 안녕하세요. 제가 다이렉트쇼를 이용해서 전문적으로 개발하을 하고 있지는 않아서요...정확하게 말씀을 드리지는 못하겠네요...^^;
      혹시 저에게 공개해주셔도 되는 소스라면...제가 소스를 보고 조금의 도움을 드릴 수 있지는 않을까 싶은데요...
      http://www.redef.pe.kr/54 에 제 연락처가 있습니다...

      2009/08/03 13:06 [ ADDR : EDIT/ DEL ]
  4. 초보ㅠ

    안녕하세요
    다이얼로그 화면 갱신과 관련하여 여기저기 찾아다니다 우연히 여기 까지 들어오게 되었습니다...

    제가 "easysize.h" 파일을 사용해서 resizing을 구현하였습니다... "easysize.h" 파일은 코드 프로젝트에서 구하였습니다...

    그런데 "easysize.h" 방법은 깜빡임이 심해서 WS_CLIPCHILDREN | WS_CLIPSIBLINGS 플래그를 추가하였습니다,

    그랬더니 깜빡임 증상은 없어졌는데 화면이 갱신이 안되서 resizing 할때 잔상이 남습니다.
    그래서 RedrawWindow()함수를 OnSize() 함수에 추가하였는데 아무런 반응이 없어서

    RedrawWindow(NULL, NULL, RDW_NOCHILDREN | RDW_NOERASE | RDW_INVALIDATE);
    를 추가하였더니 화면 갱신은 되는데 다시 감빡임 현상이 발생하네요...ㅠㅜ

    WS_CLIPCHILDREN | WS_CLIPSIBLINGS 플래그 사용 후 화면 갱신하는 방법에 대해 혹시 알고 계시다면 조언을 구하고 싶습니다.
    이거때문에 하루 종일 삽질을 얼마나 해댔는지..ㅠㅜ 나아지는것도 없고...해결은 해야되는데 시간은 없고...
    조금이라도 좋으니 도움 말씀 부탁드립니다...

    2010/03/15 22:14 [ ADDR : EDIT/ DEL : REPLY ]
    • 현재 말씀하신 내용만 봐서는 잘은 모르겠지만...
      그냥 문의해주신 정황만 봤을때...
      WM_ERASEBKGND에 대한 구현을 해줘 보셨나요?

      2010/03/16 16:47 [ ADDR : EDIT/ DEL ]
  5. 초보ㅠ

    넹.. 내용을 조금 수정해서..
    void SubDlg::OnSize(UINT nType, int cx, int cy)
    {
    UPDATE_EASYSIZE;
    AMainDialog::OnSize(nType, cx, cy);
    RedrawWindow();
    }
    BOOL SubDlg::OnEraseBkgnd(CDC* pDC)
    {
    if (IsWindow(GetDlgItem(IDC_LOG_LIST)->m_hWnd)) {
    GetDlgItem(IDC_LIST)->RedrawWindow();
    GetDlgItem(IDCANCEL)->RedrawWindow();
    }

    return AMainDialog::OnEraseBkgnd(pDC);
    } //AMainDialog는 Cdialog를 상속받는 클래스로 제가 구현한것입니다.. SubDlg의 부모 클래스입니다..

    이렇게 구현했는데요...
    이렇게 했더니 무한 루프에 빠집니다...
    WS_CLIPCHILDREN | WS_CLIPSIBLINGS 플래그를 쓰면 생기는 화면이 갱신이 되지 않아 잔상 남는 문제를 어떻게 해결 해야되는건가요??ㅜㅠ

    2010/03/16 20:48 [ ADDR : EDIT/ DEL : REPLY ]
    • http://www.redef.pe.kr/54 에 보시면 제 이메일 주소가 있습니다...
      공개해주셔도 되는 소스라면 메일로 좀 보내주실 수 있을까요?
      혹시라도 도움을 드릴 수 있으면 드리도록 노력해 보겠습니다...^^

      2010/03/17 10:08 [ ADDR : EDIT/ DEL ]