DirectShow를 이용하여 카메라 동영상을 mp4로 캡쳐해 보자~


사용자 삽입 이미지

위의 그림은 동영상을 캡쳐 하기 위한 필터 그래프이다.

사실 위 그림만으로 모든것이 설명이 되지만 ..

그래도 혹시 내가 잊어버릴까봐 부가설명을 ;;

 

 

// GraphBuilder와 CaptureGraphBuilder2를 생성한다.

// 비디오 캡쳐를 위해서는 일반적으로 CaptureGraphBuilder2를 이용하는것 같다. (amcap예제 참고)

 

 RETURNIF(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
 RETURNIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&m_videoRecGraph));
 RETURNIF(CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &m_vCapBuilder2));
 CoUninitialize();


 

/* 위의 필터 그래프대로 필터들을 생성하고 graph에 추가해 준다.

 여기서 사용한 mp4 writer필터는 공개된 mp4 write 필터로서http://www.avideosoft.com/ 에서 구할 수 있다.

 상용으로 쓰기 위해서는http://www.3ivx.com/ 에서 제공하는 필터가 더 파워풀하다.  위 사이트의 필터는 640×480이

 한계이고 그 이상이 넘어가면 내 테스트 카메라에서는 화면이 일부 깨지는 현상이 발생한다.

 상용 필터의 경우는 1600×1200까지 깔끔하게 나오는 위력을 발휘한다. (역시 돈이 있어야 .. 😉

 그리고 참고적으로 위의 무료 필터는 640×480으로 캡쳐할 경우 framerate을 수동으로 맞추어야 한다는 단점이 있다.

 물론 프로그램 상에서 한번만 하면 되는것이지만.. 왠지 좀 그렇다. ; 320×240은 무리 없이 잘된다.

*/

 

 RETURNIF(CreateFilter("", &m_pCameraFilter, FILTERCG_VIDEOCAP));
 RETURNIF(CreateFilter("",&pAudioInForSpeaker,FILTERCG_AUDIOCAP));
 RETURNIF(m_videoRecGraph->AddFilter(m_pCameraFilter,L"Camera"));
 RETURNIF(CreateFilter("SampleGrabber", &m_pGrabber, FILTERCG_DSHOW));
 RETURNIF(m_videoRecGraph->AddFilter(m_pGrabber, L"Grabber"));
 RETURNIF(CreateFilter("MP4 Writer", &pMP4Encoder, FILTERCG_DSHOW));
 CComQIPtr<IFileSinkFilter> pFileSinkFilter(pMP4Encoder);
 pFileSinkFilter->SetFileName(fileName.AllocSysString(),NULL);
 RETURNIF(m_videoRecGraph->AddFilter(pMP4Encoder, L"MP4 Writer"));


 

// 카메라 아웃 핀을 가져온다.

 

RETURNIF(m_pCameraFilter->EnumPins(&pEnumPins));
while (pEnumPins->Next(1, &pPin, 0) == S_OK)
 {
  RETURNIF(pPin->QueryDirection(&direction));
  if (direction == PINDIR_OUTPUT)
  {

 

// 미디어 스트림에서 기본 값의 포맷을 읽어서 내가 원하는 설정값으로 변경해 준다.

// 일반적으로 내가 테스트 한 웹 카메라에서는 필터 그래프를 렌더한 후에는 해당 설정값이

// 바뀌지 않았다. 따라서 그래프를 렌더 하기 전에 원하는 해상도와 framerate을 설정하였다.


   AM_MEDIA_TYPE *mt;
   CComQIPtr<IAMStreamConfig> pAM(pPin);
   pAM->GetFormat(&mt);
   VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt->pbFormat;
   pVih->bmiHeader.biWidth = 640;
   pVih->bmiHeader.biHeight = 480;
   pVih->AvgTimePerFrame = 1200000;
   pAM->SetFormat(mt);
   SAFE_RELEASE(pPin);
   break;
  }
  SAFE_RELEASE(pPin);
 }
 

// CaptureBuilder2에 위의 GraphBuilder를 설정한다.


 

 RETURNIF(m_vCapBuilder2->SetFiltergraph(m_videoRecGraph)); 

 

//CaptureBuilder2를 이용하여 스트림 렌더링을 한다.

// 렌더 스트림을 할 경우 자동으로 스마트 티가 붙는다. Capture pin에는 MP4 Encoder를 붙이고,

// preview pin에는 NULL 렌더링을 수행한다. 이때 화면 캡쳐를 위해 preview 핀과 렌더러 사이에 grabber를 추가하였다.


 

 m_vCapBuilder2->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pCameraFilter, NULL, pMP4Encoder);
 m_vCapBuilder2->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pCameraFilter, m_pGrabber, NULL);

 

// parent window의 hWnd를 가지고 owner 설정과 윈도우 스타일 설정을 한다.


 CComQIPtr<IVideoWindow>pVW(m_videoRecGraph);
 if (pVW != NULL)
 {
  CComQIPtr<IBasicVideo> pBV(m_videoRecGraph);
  CRect rect,videoRect;
  RETURNIF(pVW->put_Owner((OAHWND)hWnd));
  RETURNIF(pVW->put_WindowStyle(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN));

  long width, height;
  hr = pBV->GetVideoSize(&width, &height);
  this->OnSize(m_parentHwnd);
 }

 

// 추가로 위에서 만든 필터 그래프에 오디오 녹음을 위해 audio 장치를 연결한다.


 RETURNIF(m_videoRecGraph->AddFilter(pAudioInForSpeaker,L"Camera"));
 RETURNIF(ConnectFilters(m_videoRecGraph, pAudioInForSpeaker, pMP4Encoder));


답글 남기기

이메일 주소는 공개되지 않습니다.