MFC Filter20191008

MFC Filter
 Filter并不总是在一个Win32 DLL中实现的。根据实际的需要,我们可能要在Filter
的实现中用到MFC,更或者我们将Filter实现在一个EXE应用程序中。下面介绍这样一种在
MFC应用程序中开发Filter的方式。
 在应用程序中定义的Filter,严格来说,已经不能算是标准的COM组件了,它没有独
立的实现模块,不需要注册,当然也不能通过标准的COM类工厂来创建。创建这种Filter
的正确方法是,直接在应用程序中new出一个Filter类对象实例来。代码如下:
 m_pFilterObject=new CFilterClass();
 //Make the initial refcount 1 to match COM creation
 m_pFilterObject->AddRef();
 接下去,这个Filter就跟其他标准的通过CoCreateInstance函数创建的Filter一样使用
了。举例来说,假设我们在播放媒体文件的时候,想要知道一些数据流的信息(比如视频流
图像的宽、高、帧率等),另外完成一些简单功能(比如抓帧等)。但是,我们又不想使用
另外的DLL来开发Filter。于是,我们就可以在应用程序中定义一个Transform filter,并
插入到媒体文件播放的Filter链路中。代码如下:
 class CAppTransform:public CTransInPlaceFilter
 {
  public:
   CAppTransform(LPUNKNOWN pUnkOuter,HRESULT *phr);
   HRESULT CheckInputType(const CMediaType *mtIn);
   HRESULT Transform(IMediaSample *pSample);
 };
 然后,如下实现:
 CAppTransform::CAppTransform(LPUNKNOWN pUnkOuter,HRESULT *phr):
 CTransInPlaceFilter(NAME("App Trans-IP"),pUnkOuter,GUID_NULL,phr)
 {
 }
 HRESULT CAppTransform::Transform(IMediaSample *pSample)
 {
  //Override to do someting inside the application
  //Such as grabbing a poster frame...
  return S_OK;
 }
 //Check if we can support this specific proposed type and format
 HRESULT CAppTransform::CheckInputType(const CMediaType *pmt)
 {
  //We accept a series of raw media types
  if(pmt->majortype==MEDIATYPE_Video &&
   (pmt->subtype==MEDIASUBTYPE_RGB32||
   pmt->subtype==MEDIASUBTYPE_RGB24||
   pmt->subtype==MEDIASUBTYPE_RGB565||
   pmt->subtype==MEDIASUBTYPE_RGB555||
   pmt->subtype==MEDIASUBTYPE_UYVY||
   pmt->subtype==MEDIASUBTYPE_YUY2))
  {
   return NOERROR;
  }
  return E_FAIL;
 }
 为了播放媒体文件,我们另外设计了一个类CAppGraphBuilder,用于Filter Graph的
构建。我们的思路是,首先使用IGraphBuilder::RenderFile构建一个完整的媒体文件回放
链路,然后找到Video Renderer(或者Overlay Mixer),在它之前插入我们自己的Transform
Filter。代码如下:
 //给定一个媒体文件,创建一个回放链路,随后插入我们的Transform Filter
 HRESULT CAppGraphBuilder::BuildFromFile(LPCWSTR pszFile)
 {
  DestroyGraph();
  //创建一个Filter Graph
  HRESULT hr=CoCreateInstance(
     CLSID_FilterGraph,
     NULL,
     CLSCTX_INPROC,
     IID_IGraphBuilder,
     (void**)&m_pGraph);
  if(FAILED(hr))
  {
   return hr;
  }
  AddToObjectTable();
  //首先构建一个源文件的回放Filter Graph
  hr=m_pGraph->RenderFile(pszFile,NULL);
  if(FAILED(hr))
  {
   return hr;
  }
  //通过IVideoWindow接口找到Video Renderer
  IBaseFilter *pVR;
  hr=FindFilterByInterface(IID_IVideoWindow,&pVR);
  if(FAILED(hr))
  {
   return hr;
  }
  //注意,如果Video Renderer的上一级Filter是Overlay Mixer,则将没有实际的
  //数据传送到Video Renderer上,这种情况下,我们的Filter应该插在Overlay
  //Mixer之前
  IPin *pPin=InputPinOf(pVR);  //获取Video Renderer的输入Pin
  AM_MEDIA_TYPE mt;
  pPin->ConnectionMediaType(&mt); //取得连接用的媒体类型
  pPin->Release();
  CMediaType mtIn=mt;
  FreeMediaType(mt);
  if(mtIn.subtype==MEDIASUBTYPE_Overlay)
  {
   //This connection may be a overlay mixer
   //need to move upstream one place
   IBaseFilter *pOvMix=NULL;
   hr=NextUpstream(pVR,&pOvMix);
   pVR->Release();
   if(FAILED(hr))
   {
    return hr;
   }
   pVR=pOvMix;
  }
  //创建我们的Transform Filter
  CreateAppFilter();
  //将我们的Filter插入到已有的Filter链路中
  hr=ConnectUpstreamof(pVR,m_pFilter);
  pVR->Release();
  return hr;
 }
 //创建我们的Transform Filter,注意不是用CoCreateInstance函数
 void CAppGraphBuilder::CreateAppFilter(void)
 {
  if(m_pFilter)
  {
   m_pFilter->Release();
   m_pFilter=NULL;
  }
  HRESULT hr=S_OK;
  //创建Filter对象实例
  m_pFilter=new CAppTransform(NULL,&hr);
  //增加一个引用计数,防止COM的自动销毁
  m_pFilter->AddRef();
  //获取IBaseFilter接口
  IBaseFilter *pFilter=NULL;
  hr=m_pFilter->QueryInterface(IID_IBaseFilter,(void **)&pFilter);
  if(SUCCEEDED(hr))
  {
   hr=m_pGraph->AddFilter(pFilter,L"App Transform");
   pFilter->Release();
  }
 }
 //将pTransform Filter(假设为一进一出)插入到pFilter的前面
 HRESULT CAppGraphBuilder::ConnectUpstreamof(IBaseFilter *pFilter,
 IBaseFilter *pTransform)
 {
  IPin *pPinIn=InputPinOf(pFilter);
  if(!pPinIn)
  {
   return E_FAIL;
  }
  //Get the peer output pin
  IPin *pPinOut=NULL;
  HRESULT hr=pPinIn->ConnectedTo(&pPinOut);
  if(FAILED(hr))
  {
   pPinIn->Release();
   return hr;
  }
  //Disconnect the current connection
  hr=m_pGraph->Disconnect(pPinOut);
  if(SUCCEEDED(hr))
  {
   hr=m_pGraph->Disconnect(pPinIn);
  }
  //Insert pTransform filter by connecting its input pin and output pin
  if(SUCCEEDED(hr))
  {
   IPin *pPinInXfm=InputPinOf(pTransform);
   hr=m_pGraph->Connect(pPinOut,pPinInXfm);
   pPinInXfm->Release();
  }
  if(SUCCEEDED(hr))
  {
   IPin *pPinOutXfm=OutputPinOf(pTransform);
   hr=m_pGraph->Connect(pPinOutXfm,pPinIn);
   pPinOutXfm->Release();
  }
  pPinIn->Release();
  pPinOut->Release();
  return hr;
 }

posted on 2019-10-08 11:11  201610007  阅读(258)  评论(0编辑  收藏  举报