全手動連接Filter Graph

 

昨天努了一天,終於搞完了一個全手動連接的filter graph 程序,雖然很簡單,但是還是費了老大的勁。不扯了,上菜……

 

開發環境:Vista+VS2008+DX9.0,控制檯應用程序(便於調試)

 

第一步:在GraphEdit中模擬視頻播放過程。

我的graph圖如下,如果不能正常播放,先要註冊需要的filter,我就註冊了MPEG Layer-3 Decoder:

 
第二步:動手編程吧。
 
1、包含文件:
#include "stdafx.h"
#include <dshow.h>
#pragma comment(lib, "strmiids.lib")
2、定義自己註冊的filter,在main()函數前進行定義:
static const GUID CLSID_AudioDecoder=
 { 0x38BE3000,0xDBF4,0x11D0,{0x86,0x0e,0x00,0xa0,0x24,0xcf,0xef,0x6d}};
 
3、定義需要用到的COM組件:
 
IGraphBuilder *pGraph = NULL;
 IMediaControl *pControl = NULL;
 IMediaEvent *pEvent = NULL;
 IBaseFilter *pInputFileFilter = NULL;
 IBaseFilter *pAviSplitter= NULL;
 IBaseFilter *pVideoDecoder= NULL;
 IBaseFilter *pVideoColour= NULL;
 IBaseFilter *pAudioDecoder= NULL;
 IBaseFilter *pDVideoRenderer=NULL;
 IBaseFilter *pDSoundRenderer = NULL;
 IPin *pFileOut = NULL, *pSplitterIn=NULL,
   *pSplitterOut1=NULL,*pSplitterOut2=NULL,
   *pVideoDecIn = NULL,*pVideoDecOut = NULL,*pVideoColIn = NULL,*pVideoColOut = NULL,
   *pVideoRenIn = NULL,*pAudioDecIn = NULL,*pAudioDecOut = NULL,*pAudioRenIn = NULL;
4、COM庫初始化:
 HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 if (FAILED(hr))
 {
  printf("ERROR - Could not initialize COM library");
  return hr;
 }
5、創建濾波器鏈表管理器(Filter Graph Manager),獲得控制、事件的接口
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void **)&pGraph);
 if (FAILED(hr))
 {
  printf("ERROR - Could not create the Filter Graph Manager.");
  CoUninitialize();
  return hr;
 }
 // Now get the media control interface...
 hr = pGraph->QueryInterface(IID_IMediaControl,(void **)&pControl);
 if (FAILED(hr))
 {
  pGraph->Release();
  CoUninitialize();
  return hr;
 }
 // And the media event interface.
 hr = pGraph->QueryInterface(IID_IMediaEvent,(void **)&pEvent);
 if (FAILED(hr))
 {
  pControl->Release();
  pGraph->Release();
  CoUninitialize();
  return hr;
 }
6、添加源濾波器,我指定了我的D盤上的start.avi文件:
hr = pGraph->AddSourceFilter(L"d://start.avi",L"source",&pInputFileFilter);
7、創建連接AVI分流器
   hr = CoCreateInstance(CLSID_AviSplitter, NULL,CLSCTX_INPROC_SERVER,
       IID_IBaseFilter,(void **)&pAviSplitter);
   if (SUCCEEDED(hr))
   {
    hr = pGraph->AddFilter(pAviSplitter, L"Avi Splitter");
    //連接Source和splitter
    if (SUCCEEDED(hr))
    {
     //獲得空閒(未連接)的輸出引腳
     pFileOut = GetPin(pInputFileFilter, PINDIR_OUTPUT);//GetPin函數很重要,在最後面講
     if (pFileOut!= NULL)
     {
      // Is the pin unconnected? Obtain the input pin of the Avi Splitter.
      pSplitterIn= GetPin(pAviSplitter,PINDIR_INPUT);
      if (pSplitterIn!= NULL)
      {
       // Is the pin good? Connect the pins together:
       hr = pGraph->ConnectDirect(pFileOut, pSplitterIn,NULL);
      }
     }
    }
   }
8、創建連接視頻解碼器
   hr = CoCreateInstance(CLSID_AVIDec, NULL,CLSCTX_INPROC_SERVER,
       IID_IBaseFilter,(void **)&pVideoDecoder);
   if (SUCCEEDED(hr))
   {
    hr = pGraph->AddFilter(pVideoDecoder, L"Video Decoder");
    //連接splitter和Video Decoder
    if (SUCCEEDED(hr))
    {
     pSplitterOut1= GetPin(pAviSplitter,PINDIR_OUTPUT);//獲取分流器輸出引腳1
     if (pSplitterOut1!= NULL)
     {
      // Is the pin good? Obtain the input pin of the Avi Decoder.
      pVideoDecIn=GetPin(pVideoDecoder,PINDIR_INPUT);//獲取AVI解碼器輸入引腳
      if (pVideoDecIn!= NULL)
      { 
       hr = pGraph->ConnectDirect(pSplitterOut1,pVideoDecIn,NULL);
      }
     }
    }
   } 
 9、創建連接視頻色彩轉換器
   hr = CoCreateInstance(CLSID_Colour, NULL,CLSCTX_INPROC_SERVER,
       IID_IBaseFilter,(void **)&pVideoColour);
   if (SUCCEEDED(hr))
   {
    hr = pGraph->AddFilter(pVideoColour, L"Video Colour");
    //連接Video Decoder和Video Colour
    if (SUCCEEDED(hr))
    {
     pVideoDecOut= GetPin(pVideoDecoder,PINDIR_OUTPUT);//獲取解碼器輸出引腳
     if (pVideoDecOut!= NULL)
     { 
       pVideoColIn=GetPin(pVideoColour,PINDIR_INPUT);//獲取色彩轉換器輸入引腳
      if (pVideoColIn!= NULL)
      { 
       hr = pGraph->ConnectDirect(pVideoDecOut,pVideoColIn,NULL);
      }
     }
    }
   }
 10、創建連接視頻渲染器
   hr = CoCreateInstance(CLSID_VideoRendererDefault, NULL,CLSCTX_INPROC_SERVER,
       IID_IBaseFilter,(void **)&pDVideoRenderer);
   if (SUCCEEDED(hr))
   {
    hr = pGraph->AddFilter(pDVideoRenderer, L"Video Renderer");
    //連接Video Decoder和Video Renderer
    if (SUCCEEDED(hr))
    {
     pVideoColOut= GetPin(pVideoColour,PINDIR_OUTPUT);//獲取AVI解碼器輸出引腳
     if (pVideoColOut!= NULL)
     { 
      pVideoRenIn=GetPin(pDVideoRenderer,PINDIR_INPUT);//獲取AVI渲染器輸入引腳
      if (pVideoRenIn!= NULL)
      { 
       hr = pGraph->ConnectDirect(pVideoColOut,pVideoRenIn,NULL);
      }
     }
    }
   }
11、視頻流連接完畢,音頻流類似,所以在此一步到位。
   // 創建連接音頻解碼器
   hr = CoCreateInstance(CLSID_AudioDecoder, NULL,CLSCTX_INPROC_SERVER,
       IID_IBaseFilter,(void **)&pAudioDecoder);
   if (SUCCEEDED(hr))
   {
    hr = pGraph->AddFilter(pAudioDecoder, L"Audio Decoder");
    //連接splitter和Video Decoder
    if (SUCCEEDED(hr))
    {
     pSplitterOut2= GetPin(pAviSplitter,PINDIR_OUTPUT);//獲取分流器輸出引腳2,兩個輸出引腳啊開始不知道怎麼搞
     if (pSplitterOut2!= NULL)
     { 
      pAudioDecIn=GetPin(pAudioDecoder,PINDIR_INPUT);//獲取AVI解碼器輸入引腳
      if (pAudioDecIn!= NULL)
      {
       // Is the pin good? Connect the pins together:
       hr = pGraph->ConnectDirect(pSplitterOut2,pAudioDecIn,NULL);
      }
     }
    }
   }
   //// 創建連接音頻渲染器
   hr = CoCreateInstance(CLSID_DSoundRender, NULL,CLSCTX_INPROC_SERVER,
       IID_IBaseFilter,(void **)&pDSoundRenderer);
   if (SUCCEEDED(hr))
   {
    hr = pGraph->AddFilter(pDSoundRenderer, L"Audio Renderer");
    if (SUCCEEDED(hr))
    {
     pAudioDecOut= GetPin(pAudioDecoder, PINDIR_OUTPUT);//獲取音頻解碼器輸出引腳
     if (pAudioDecOut!= NULL)
     { 
      pAudioRenIn= GetPin(pDSoundRenderer,PINDIR_INPUT);//獲取音頻渲染器輸入引腳
      if (pAudioRenIn!= NULL)
      { 
       hr = pGraph->ConnectDirect(pAudioDecOut,pAudioRenIn,NULL);
      }
     }
    }
   }
   //音頻渲染器創建連接完畢
12、所有的都連接好了,下面的控制就根據自己需要定,我就不寫了大同小異,還有釋放部分,我還不太懂就不誤導大家了。下面看GetPin()函數,特別注意這個函數適合處理多個同方向的引腳查詢。
IPin* GetPin(IBaseFilter *pFilter, PIN_DIRECTION dir)//查找 dir方向上的空閒PIN
{
 IEnumPins* pEnumPins;
 IPin* pOutpin;
 PIN_DIRECTION pDir;
 pFilter->EnumPins(&pEnumPins);
 while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK)
 {
  pOutpin->QueryDirection(&pDir);
  if (pDir==dir)//方向對了
  {
   IPin *pTmp=0;
   HRESULT hr=pOutpin->ConnectedTo(&pTmp);
   if (SUCCEEDED(hr))// 已經連接了,不是我們想要的
    ;
   else    //第一個未連接的,就是它了 
   {
    pEnumPins->Release();
    return pOutpin;
   }
  }
  pOutpin->Release();
 }
 pEnumPins->Release();
 return 0;
}
結束語:
一切OK,調試一下沒問題就可以收工了,我的反正沒問題,呵呵
參考資料:
1、Visual C++音頻/視頻處理技術及工程實踐。路錦正,周冬梅。電子工業出版社,
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章