本文分析一下《DirectShow开发指南》中的一个典型的Transform Filter的例子:字幕叠加(FilterTitleOverlay)。通过分析该例子,我们可以学习到DirectShow Transform Filter 开发的方式。

直接打开项目工程(我这里是VC2010),看到项目的结构如下图所示:

先看一下运行的结果:

注意,DirectShow的Filter是不可以直接运行进行调试的。一般情况下需要借助于Graphedit.exe这个程序进行调试。当然这不是绝对的,也可以用graph-studio-next这样的开源程序。

选择右键点击工程->属性->调试->命令。在栏中输入Graphedit.exe的路径,如图所示

这样就可以调试Filter了。

拖入一个文件"五月天 咸鱼.mp4",然后插入本工程的Filter,如图所示。

播放视频,效果如图,可见左上角显示出 "Hello, DirectShow!" 的字样。

看完了结果,就要开始分析代码了~

回顾一下工程结构图:

先看一下CFilterTitleOverlay.h(已经在重要的地方加了注释):

//
// CFilterTitleOverlay.h
// #ifndef __H_CFilterTitleOverlay__
#define __H_CFilterTitleOverlay__ #include "ITitleOverlay.h"
#include "COverlayController.h"
#include "OverlayDefs.h" class CFilterTitleOverlay : public CTransInPlaceFilter
, public ISpecifyPropertyPages
, public ITitleOverlay
{
private:
OVERLAY_TYPE mOverlayType;
COverlayController * mOverlayController; CCritSec mITitleOverlaySync;
BOOL mNeedEstimateFrameRate; private:
CFilterTitleOverlay(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);
~CFilterTitleOverlay(); HRESULT SetInputVideoInfoToController(void);
void ReleaseOverlayController(void);
void SideEffectOverlayTypeChanged(void); public:
static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
//说明必须重写NonDelegatingQueryInterface
DECLARE_IUNKNOWN;
// Basic COM - used here to reveal our own interfaces
//暴露接口,使外部程序可以QueryInterface,关键!
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); // check if you can support mtIn
virtual HRESULT CheckInputType(const CMediaType* mtIn); // PURE
//必须重写的核心函数
virtual HRESULT Transform(IMediaSample *pSample); // PURE // Delegating methods
virtual HRESULT CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin);
virtual HRESULT StartStreaming();
virtual HRESULT StopStreaming(); // --- ISpecifyPropertyPages ---
STDMETHODIMP GetPages(CAUUID *pPages); // --- ITitleOverlay methods ---
//都是接口函数
STDMETHODIMP put_TitleOverlayType(long inOverlayType);
STDMETHODIMP get_TitleOverlayType(long * outOverlayType);
STDMETHODIMP put_TitleOverlayStyle(int inUsingCover);
STDMETHODIMP get_TitleOverlayStyle(int * outUsingCover);
STDMETHODIMP put_Title(const char * inTitle, int inLength);
STDMETHODIMP get_Title(char * outBuffer, int * outLength);
STDMETHODIMP put_TitleColor(BYTE inR, BYTE inG, BYTE inB);
STDMETHODIMP get_TitleColor(BYTE * outR, BYTE * outG, BYTE * outB);
STDMETHODIMP put_TitleStartPosition(POINT inStartPos);
STDMETHODIMP get_TitleStartPosition(POINT * outStartPos);
STDMETHODIMP put_TitleFont(LOGFONT inFont);
STDMETHODIMP get_TitleFont(LOGFONT * outFont);
STDMETHODIMP put_TitleDuration(double inStart, double inEnd);
STDMETHODIMP get_TitleDuration(double * outStart, double * outEnd);
}; #endif // __H_CFilterTitleOverlay__

CFilterTitleOverlay继承了CTransInPlaceFilter,意味着Transform()函数输入和输出的数据位于同一块内存中。

以下几个函数是必须有的:

CreateInstance():创建Filter
NonDelegatingQueryInterface():暴露接口,使外部程序可以QueryInterface
CheckInputType():检查输入类型
Transform():核心处理函数(字幕叠加)

另外还包含了ITitleOverlay中的函数put_TitleOverlayType()等等一大堆。

下面看一下CFilterTitleOverlay.cpp吧,先列出注册信息部分:

//唯一标识符
// {E3FB4BFE-8E5C-4aec-8162-7DA55BE486A1}
DEFINE_GUID(CLSID_HQTitleOverlay,
0xe3fb4bfe, 0x8e5c, 0x4aec, 0x81, 0x62, 0x7d, 0xa5, 0x5b, 0xe4, 0x86, 0xa1); // {E70FE57A-19AA-4a4c-B39A-408D49D73851}
DEFINE_GUID(CLSID_HQTitleOverlayProp,
0xe70fe57a, 0x19aa, 0x4a4c, 0xb3, 0x9a, 0x40, 0x8d, 0x49, 0xd7, 0x38, 0x51); //
// setup data
//
//注册时候的信息
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
&MEDIATYPE_NULL, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
//注册时候的信息
const AMOVIESETUP_PIN psudPins[] =
{
{
L"Input", // String pin name
FALSE, // Is it rendered
FALSE, // Is it an output
FALSE, // Allowed none
FALSE, // Allowed many
&CLSID_NULL, // Connects to filter
L"Output", // Connects to pin
1, // Number of types
&sudPinTypes }, // The pin details
{ L"Output", // String pin name
FALSE, // Is it rendered
TRUE, // Is it an output
FALSE, // Allowed none
FALSE, // Allowed many
&CLSID_NULL, // Connects to filter
L"Input", // Connects to pin
1, // Number of types
&sudPinTypes // The pin details
}
}; //注册时候的信息
const AMOVIESETUP_FILTER sudFilter =
{
&CLSID_HQTitleOverlay, // Filter CLSID
L"HQ Title Overlay Std.", // Filter name
MERIT_DO_NOT_USE, // Its merit
2, // Number of pins
psudPins // Pin details
}; // List of class IDs and creator functions for the class factory. This
// provides the link between the OLE entry point in the DLL and an object
// being created. The class factory will call the static CreateInstance
//注意g_Templates名称是固定的
CFactoryTemplate g_Templates[] =
{
{
L"HQ Title Overlay Std.",
&CLSID_HQTitleOverlay,
CFilterTitleOverlay::CreateInstance,
NULL,
&sudFilter
},
{
L"HQ Title Overlay Property Page",
&CLSID_HQTitleOverlayProp,
CTitleOverlayProp::CreateInstance
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

这一部分并不属于CFilterTitleOverlay这个类。主要是DirectShow Filter的一些注册信息。其结构是非常固定的。

再来看看CFilterTitleOverlay中函数实现部分(只列了几个函数,不然内容太多= =):

CreateInstance():

//
// CreateInstance
//
// Override CClassFactory method.
// Provide the way for COM to create a CNullInPlace object
//
//创建
CUnknown * WINAPI CFilterTitleOverlay::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
{
#if 1
//防伪??!!
char szCreatorPath[256], szCreatorName[256];
::strcpy(szCreatorPath, "");
::strcpy(szCreatorName, "");
HMODULE hModule = ::GetModuleHandle(NULL);
::GetModuleFileName(hModule, szCreatorPath, 256);
char * backSlash = ::strrchr(szCreatorPath, '\\');
if (backSlash)
{
strcpy(szCreatorName, backSlash);
}
::_strlwr(szCreatorName);
// Please specify your app name with lowercase
// 检查调用该Filter的程序
// 一开始调试不了,就卡在这了 = =
if (::strstr(szCreatorName, "graphedit") == NULL &&
::strstr(szCreatorName, "ourapp") == NULL)
{
*phr = E_FAIL;
return NULL;
}
#endif
//通过New对象的方法
CFilterTitleOverlay *pNewObject = new CFilterTitleOverlay(NAME("TitleOverlay"), punk, phr);
if (pNewObject == NULL)
{
*phr = E_OUTOFMEMORY;
}
return pNewObject;
}

NonDelegatingQueryInterface():

//
// Basic COM - used here to reveal our own interfaces
//暴露接口,使外部程序可以QueryInterface,关键!
STDMETHODIMP CFilterTitleOverlay::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
{
CheckPointer(ppv, E_POINTER);
//根据不同的REFIID,获得不同的接口指针
if (riid == IID_ISpecifyPropertyPages)
{
return GetInterface((ISpecifyPropertyPages *) this, ppv);
}
else if (riid == IID_ITitleOverlay)
{
return GetInterface((ITitleOverlay *) this, ppv);
}
else
{
//不是以上的REFIID的话,调用父类的
return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);
}
} // NonDelegatingQueryInterface

CheckInputType():

// Only RGB 32/24/565/555 supported
HRESULT CFilterTitleOverlay::CheckInputType(const CMediaType* mtIn)
{
// Dynamic format change will never be allowed!
if (IsStopped() && *mtIn->Type() == MEDIATYPE_Video)
{
if (*mtIn->Subtype() == MEDIASUBTYPE_RGB32 ||
*mtIn->Subtype() == MEDIASUBTYPE_RGB24 ||
*mtIn->Subtype() == MEDIASUBTYPE_RGB555 ||
*mtIn->Subtype() == MEDIASUBTYPE_RGB565)
{
return NOERROR;
}
}
return E_INVALIDARG;
}

Transform():

HRESULT CFilterTitleOverlay::Transform(IMediaSample *pSample)
{
// If we cann't read frame rate info from input pin's connection media type,
// We estimate it from the first sample's time stamp!
if (mNeedEstimateFrameRate)
{
mNeedEstimateFrameRate = FALSE;
REFERENCE_TIME startTime = 0;
REFERENCE_TIME endTime = 0;
double estimated = 25;
if (SUCCEEDED(pSample->GetTime(&startTime, &endTime)))
{
estimated = 1.0 * UNITS / (endTime - startTime);
}
mOverlayController->SetEstimatedFrameRate(estimated);
} if (mOverlayType != OT_NONE)
{
//PBYTE是unsigned char
PBYTE pData = NULL;
//获取IMediaSample中的数据
pSample->GetPointer(&pData);
//叠加
mOverlayController->DoTitleOverlay(pData);
} return NOERROR;
}

下面列出实现ITitleOverlay接口的函数的实现,就列了一个。

STDMETHODIMP CFilterTitleOverlay::get_Title(char * outBuffer, int * outLength)
{
CAutoLock lockit(&mITitleOverlaySync);
*outLength = mOverlayController->GetTitle(outBuffer);
return NOERROR;
}

暂且分析到这里。

书上提供的代码有误,这是经过修改后,添加了注释的代码:

http://download.csdn.net/detail/leixiaohua1020/6371819

DirectShow Filter 开发典型例子分析 ——字幕叠加 (FilterTitleOverlay)1的更多相关文章

  1. Apache Mina原理及典型例子分析

    Apache Mina ,一个高性能 Java 异步并发网络通讯框架.利用 Mina 可以高效地完成以下任务: TCP/IP 和 UDP/IP 通讯 串口通讯 VM 间的管道通讯 SSL/TLS JX ...

  2. DirectShow Filter的开发实践

    一.介绍 摄像头图像采集处理在业界有着多种成熟的方案.从老的DirectShow.Grabber技术,到新的Windows Media Foundation框架,网络上都有着丰富的参考资料.OpenC ...

  3. 最简单的基于FFmpeg的AVfilter例子(水印叠加)

    ===================================================== 最简单的基于FFmpeg的AVfilter例子系列文章: 最简单的基于FFmpeg的AVfi ...

  4. Anaconda安装Graphviz, mac下Graphviz安装, pcharm中调用pycharm, Graphviz典型例子

    mac下的Graphviz安装及使用 2017年10月13日 13:30:07 阅读数:7495 一.安装 Graphviz http://www.graphviz.org/ mac用户建议直接用ho ...

  5. GIS应用|快速开发REST空间分析服务

    随着计算机的快速发展,GIS已经在各大领域得到应用,和我们的生活息息相关, 但是基于GIS几大厂商搭建服务,都会有一定的门槛,尤其是需要server,成本高,难度大,这里介绍一种在线GIS云平台,帮你 ...

  6. 主窗体里面打开子窗体&&打印饼图《Delphi 6数据库开发典型实例》--图表的绘制

    \Delphi 6数据库开发典型实例\图表的绘制 1.在主窗体里面打开子窗体:ShowForm(Tfrm_Print); procedure Tfrm_Main.ShowForm(AFormClass ...

  7. [Oracle] SQL*Loader 详细使用教程(5)- 典型例子

    本文介绍SQL*Loader在实际使用过程中经常用到的典型例子. 1. 表中的列比数据文件的列要少怎么办? 假设一个csv的文件如下: a1,a2,a3,a4 b1,b2,b3,b4 c1,c2,c3 ...

  8. HBase基本知识介绍及典型案例分析

    本次分享的内容主要分为以下五点: HBase基本知识: HBase读写流程: RowKey设计要点: HBase生态介绍: HBase典型案例分析. 首先我们简单介绍一下 HBase 是什么. HBa ...

  9. 通过例子分析MVVM

    通过一个简单的计数器例子分析MVVM. 代码 demo2.html <!DOCTYPE html> <html lang="en"> <head> ...

随机推荐

  1. 网站开发常用jQuery插件总结(七)背景插件backstretch

    一.backstretch插件功能 优化网站外观.主要用于设置页面背景图片,也可以设置html元素的背景图片.背景图片可以设置多张,在间隔时间内循环显示. 注 但是在设置背景图片时,如果图片过大,网站 ...

  2. eclipse中DDMS的LOGcat只有一列level

    拷贝来源:http://www.cnblogs.com/kobe8/p/4620785.html http://stackoverflow.com/questions/25010393/eclipse ...

  3. 黑马程序员-------.net基础知识一

    一 初识.net  .net是一种多语言的编程平台,可以用多达几十种的语言来进行开发,而C#就是基于.net平台的其中一种开发语言. 它的特点是: ⒈多平台:该系统可以在广泛的计算机上运行,包括从服务 ...

  4. bootstrap-datepicker 日期拾取器

    最近开发的项目界面用的是bootstrap的框架,发现开源的东西真的很多,慢慢的我会记录到上面来 地址  http://www.bootcss.com/p/bootstrap-datetimepick ...

  5. myeclipse启动项目时报:An internal error occurred during: "Launching TestSpring on Tomcat 7.x". java.lang.NullPointerException 解决方法

    如果出现了上述的错误按照如下的3个步骤解决: 1.首先关闭MyEclipse工作空间. 2.然后删除工作空间下的 “/.metadata/.plugins/org.eclipse.core.runti ...

  6. 转:如何制作一个定制的 PHP 基础 Docker 镜像(一)

    原文来自于:http://open.daocloud.io/ru-he-zhi-zuo-yi-ge-ding-zhi-de-php-ji-chu-docker-jing-xiang/ 目标:准备一个定 ...

  7. Google java编程技术规范

    不遵循规范的程序猿,不是好的coder. 学习java有一段时间了,一直想找java编程技术规范来学习一下,幸而网络资源丰富,各路玩家乐于分享,省去了好多麻烦,姑且算站在网友的肩上,砥砺前行. /** ...

  8. delphi xe5 android sample

    安装xe5以后demo存放的路径在  C:\users\Public\Documents\RAD Studio\12.0\Samples 另外易博龙在sourceforget上也有 svn地址为:sv ...

  9. MATLAB conv2卷积的实现

    MATLAB conv2卷积的实现 二维卷积的算法原理比较简单,参考任意一本数字信号处理的书籍,而matlab的conv2函数的滤波有个形状参数,用下面的一张图很能说明问题: 这里给出一种最原始的实现 ...

  10. js 介绍

    createjs 工作内容:html5游戏开发岗位要求:1. 熟悉HTML5特性, 掌握canvas开发技能;2.能独立的搭建出易扩展,高效,强壮,通用的前端底层框架;3.熟悉常用的JS开发框架或工具 ...