科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC+DirectShow对视频进行图片处理之三

VC+DirectShow对视频进行图片处理之三

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

如果您使用 DirectShow 有一阵子,您一定会选择写一个类来封装 DirectShow。

作者:longway 来源:天极开发 2007年10月16日

关键字: VC DirectShow 视频 图片处理

  • 评论
  • 分享微博
  • 分享邮件
为方便使用DirectShow而写一个封装类

  如果您使用 DirectShow 有一阵子,您一定会选择写一个类来封装 DirectShow,谁也愿意只调用“PlayMovie”这些只用传入文件名就能播放的函数来播放文件,而不想每次都作一大堆初始化和使用一大堆对象,而且类可以方便的移动到不同项目中。

  我在写这个类是遇到一个问题:怎样使用自写的 Filter,先注册再使用还是不必注册直接手工载入呢?想到绿色软件是不往注册表中添加多余信息的,而且要使程序能在进行重装系统等导致注册表信息丢失的操作后仍无需重装而正常运行,因此我选择了手工方式。这样做也不难,只是模拟一遍 COM 的载入,也就是 CoCreateInstance 工作流程的模拟。我不知道高手们是怎样做的,这里只是我的做法,流程如下:用 LoadLibrary 载入VR.dll,使用 GetProcAddress 查找 GetClassObject 函数的地址,再调用 GetClassObject 得到类工厂,然后用类工厂询问并得到 Filter。

  先看一个可以从已载入的 dll 得到对象的函数:

// 定义 DllGetClassObject 函数的指针

typedef HRESULT (CALLBACK *lpDllGetClassObject)(REFCLSID,REFCLSID,void**);
HRESULT lwGetClassObject(HMODULE hLib,const CLSID& clsid,const CLSID& riid,void** ppv)
{
 // 装入和卸载dll由用户执行,以免后来忘记了卸载dll
 HRESULT hr;
 if(!hLib){
  // dll没有装载成功
  hr = E_FAIL;
  return hr;
 }
 lpDllGetClassObject lwDGCO = NULL;
 lwDGCO =(lpDllGetClassObject)GetProcAddress(hLib,"DllGetClassObject");
 if(!lwDGCO){
  // 查找函数失败
  hr = E_FAIL;
  return hr;
 }
 IClassFactory* pCF = NULL;
 hr = lwDGCO(clsid,IID_IClassFactory,(void**)&pCF);
 if(!pCF){
  // 获取类厂失败
  return hr;
 }
 hr = pCF->CreateInstance(NULL,riid,ppv);
 if(!ppv) hr = E_FAIL;
 pCF->Release();
 return hr;
}

  我在类中作了如下这些定义:

// 类成员的定义,要包含“IVRControl.h”文件

IGraphBuilder* m_pGB; // Filter Graph
IBaseFilter* m_pFVR; // 自写的 Filter
IVRControl* m_pVRControl; // 接口
HMODULE m_hLib; // dll 库的句柄

  在类的构造函数中载入 dll:

m_hLib = LoadLibrary("VR.dll"); // 载入 dll,“VR.dll”要和程序在同一目录

  之后在类的成员函数 InitDS 中做获取 Filter 等工作:

HRESULT hr;
// 创建 Filter Graph
hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IGraphBuilder,(void**)&m_pGB);
if(FAILED(hr)){
 return hr;
}

// 调用上面的函数从已载入的 dll 中获取自写的 Filter

hr = lwGetClassObject(m_hLib,CLSID_lwVideoRenderer,IID_IBaseFilter,(void**)&m_pFVR);
if(FAILED(hr)){
 return hr;
}

// 询问接口

hr = m_pFVR->QueryInterface(IID_IVRControl,(void**)&m_pVRControl);
if(FAILED(hr)){
 return hr;
}

// 把 Filter 加入 Filter Graph

hr = m_pGB->AddFilter(m_pFVR,L"VideoRenderer");
if(FAILED(hr)){
 return hr;
}

  最后在类的释构函数中卸载dll。本来我在一本2000年版的《COM 精髓》中看到要先调用 dll 的 DllCanUnloadNow 函数确定是否应卸载才实行卸载的,不过试验中,特别是使用多个类播放几个不同文件时发现就这样直接卸载就行,用 DllCanUnloadNow 作为卸载条件反而不能正确卸载。

if(m_hLib){
 // 确认成功载入了 dll
 FreeLibrary(m_hLib);// 卸载 dll
}

  以上的代码有点乱,请对照流程耐心的看一下,我已作了详细的注释,应该不难看懂。完成这些后,要播放视频文件只需 m_pGB->RenderFile(L”c:\\sample.wmv”,0); 就可以建立“Filter Chain”了,再用 m_pMC->Run(); 就可开始播放(m_pMC 为 IMediaControl对象),完全是最一般的 DirectShow 操作,摄像头控制也一样,我不多贴代码了,您可到我拙劣的程序中看。这儿要提的是接口,在上面代码中如无意外我们已经获得了 Filter 的接口,不过到目前为止这个接口只通到此 DirectShow 类中,也就是只能在此类中使用,我们还得把它导通到类外以便设置函数,它的传递代码如下,仅以 SetFun 为例:

HRESULT CDSControl::SetFun(pProcFun pPF)
{
 if(m_pVRControl){
  return m_pVRControl->SetFun(pPF);
 }
 return E_FAIL;
}

查看本文源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章