全手动连接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++音频/视频处理技术及工程实践。路锦正,周冬梅。电子工业出版社,
2、 http://hi.baidu.com/fenjianren/blog/item/7e27bbc46515f4ce38db497a.html

你可能感兴趣的:(filter,video,null,Graph,input,output)