
字符叠加Filter之用途分析 总体意愿:在视频流指定的一个时间段内叠加一段字符,要求才能做到即时叠加。字符的 内容、字体种类、大小、颜色、叠加的位置、存在的时间都无法定制,普遍支持RGB 各种 格式输入。另外,除了支持静态字符叠加外,还规定支持其它效果的字符(包括滚动字幕, 系统时间等)叠加,并且平台设计的扩展性良好。 功能单一化:字符叠加可以在一个filter 中实现。 选择一种filter 模型:这个filter 同时有输入和输出(即在输入的视频帧上叠加完字符后再 输出到下一级filter),因此我们的filter 是一个Transform Filter。由于输入和输出的外媒类型 一致,而且输入和输出 sample 的数据大小不会变化,所以我们可以采取“就地”处理的 transform Filter。 定义输入和输出 我们的 filter 需要一个输入 Pin 和一个输出 Pin,输入 Pin 支持的媒体类型有 RGB32、 RGB24、RGB565、RGB555 等,并且输出Pin 上的外媒类型与输入Pin 保持一致。 接口定义 接口方式需要包含修改数组的内容,设置图标的诸多属性,选择图标的叠加效果,设置叠 加位置,设置字符存在的时间段等。

其他一些特殊规定 Filter 处理的 sample 是一一对应的自学directshow,而且外部不需要另外的使用线程。这是一个标准的 Transform Filter。 当我们要写一个source Filter,并且要将形成的数据“推”出去时,我们通常选择Csource, 我们的Filter 接收输入数据,经过一定的处理后要再输出数据,我们通常选取CtransformFilter (如果可以“就地”处理就选择CtransInPlaceFilter)。如果我们的Filter 同时有输入和输出, 而且它的输入Pin 上应该自己“拉”数据,则我们选取CbaseFilter,而在输入Pin 上使用工 具类CpullPin;当我们的Filter 接收输入数据后不再需要输出,我们通常选用CbaseFilter。 Filter 的父类确定了,一般Pin 的父类也就相应地确定了,Directshow SDK 提供的这种详细 应用的Filter 子类都提供了相应的Pin 类。我们可以从特殊的Pin 类中派生出我们自己的Pin 类。“字符叠加Filter”选择CtransInPlaceFilter 作为我们Filter 的父类,而且我们不用重新实 现自己的Pin Filter只是一个应用框架,一个能够支持“输入->内部处理->输出”的典型过程框架的应用 框架,最重要的是“内部处理”部分。

将应用框架和应用逻辑分离,以设计一个结构清晰, 扩展性良好的Filter 项目。 Filter 框架是指完成Filter 功能的一个必要的操作函数集。Filter 类的使用方式,包括推动一 些需要的纯虚函数,可选实现的虚函数等,以完成输入和输出Pin 上的媒体类型检查,决定 Sample 内存大小等。另外,我们在Filter 上也许需要将一些状况信息修改给应用逻辑控制对 Filter的状况转换的同时读取控制对象相应的变量(用于初始化或反初始化),以及 在数据处理时读取控制对象的数据处理函数等。 应用逻辑是指对输入数据进行处理的一套控制思路。至于数据是怎样输入的,处理完后 又是怎样输出的,这些难题都由Filter 框架负责。应用逻辑应该关心的,更多的是数据处理 的算法实现,效率改进等难题。应用逻辑控制对象通常以Filter 的一个复合成员对象的方式 出现。 以“字符叠加 Filter ”为例,我们定义一个 Filter CfilterTitleOverlay,它从CtransInPlaceFilter 类派生而来,再定义一个应用逻辑控制类为CoverlayController,作为Filter 的一个成员对象(指针)。

代码如下: Class CfilterTitleOverlay:public CtransInPlaceFilter Private:OVERLAY_TYPE mOverlayType; CoverlayController CoverlayController是最基本的控制类,为了支持多种效果的字符叠加,我们可以从这个 类派生更多的子类。 其中,CscrollController 用于滚动字幕叠加控制;CsysTimeOverlayController 用于系统时 间的叠加控制。 另外,我们还发现 Filter 类中定义了一个枚举类别 OVERLAY_TYPE 的成员变量 mOverlayType,它指示了当前Filter 使用的叠加方法。OVERLAY_TYPE 的定义如下: Typedef enum{ OT_NONE, OT_STATIC,//静态字符叠加 OT_SYSTIME,//系统时间叠加 OT_SCROLL_TOP,//滚动字幕叠加(在视频帧的顶上) OT_SCROLL_BOTTOM//滚动字幕叠加(在视频帧的底边) }OVERLAY_TYPE; 根据mOverlayType 的不同取值,我们可以建立不同的控制类对象例子。

编码实现 Filter 的编码实现包含Filter 的登录信息,Filter 上的框架函数实现,逻辑控制类实现, 自定义接口实现,属性页实现,产权保护等。 Filter 注册信息:首先为Filter 生成一个新的CLSID。如果Filter 上还实现了属性页,自 定义接口,则还必须分别为他们生成一个CLSID。方法为允许平台中的GuidGen.exe 程序, 出现图标。 {79A69932-ACAC-4609-9C06-3C0406BC2380}DEFINE_GUID(, 0x79a69932, 0xacac, 0x4609, 0x9c, 0x6, 0x3c, 0x4, 0x6, 0xbc, 0x23, 0x80); 在《name》中替换成自己设定的名字。 在GUID 字符串之前,需要加入#include,将其转换为GUID 常量。 Filter 注册信息的核对。 框架函数的实现: CreateInstance 函数的实现 实现CreateInstance 函数可以建立Filter 对象示例,代码如下: Cunknown WINAPICfilterTitleOverlay::CreateInstance(LPUNKNOWN punk,HRESULT *phr) CfilterTitleOverlay*pNewObject=new CfilterTItleOverlay(NAME(“TitleOverlay”),punk,phr); If(pNewObject==NULL) returnpNewObject; CheckInputType函数的实现 实现CheckInputType 函数可以完成输入Pin 上的媒体类别的检查,代码如下: HRESULT CfilterTitleOverlay::CheckInputType(const CmediaType* mtIn) If(*mtIn->Subtype()==MEDIASUBTYPE_RGB32||*mtIn->Subtype()==MEDIASUBTYPE_RGB24|| *mtIn->subtype()==MEDIASUBTYPE_RGB555|| *mtIn->subtype()==MEDIASUBTYPE_RGB565) ReturnNOERROR: ReturnE_INVALIDARG; Transform函数的实现 实现Transform函数可以完成字符叠加函数的读取,代码如下: HRESULT CfilterTitleOverlay::Transform(ImediaSample *pSample) //如果我们不能从输入Pin的外媒类型中获取速率参数信息则按照第一个Sample上的时间戳 //来计算 If(mNeedEstimateFrameRate) mNeedEstimateFrameRate=FALSE;REFERENCE_TIME startTime=0; REFERENCE_TIME endTime=0; Double estimated=25; If(SUCCEED(pSample->GetTime(&startTime,&endTime))) PBYTEpData=NULL; pSample->GetPointer(&pData); mOverlayController->DoTitleOverlay(pData); RetrunNOERROR: 其中mOverlayController->DoTitleOverlay(pData)是真正推动字符叠加的变量调用。
NonDelegatingQueryInterface 函数可以“暴露”Filter 支持的接口自学directshow,代码如下: STDMETHODIMP CfilterTitleOverlay::NonDelegatingQueryInterface(REFIID riid,void **ppv) CheckPointer(ppv,E_POINTER);If(riid==IID_ISpecifyPropertyPages)//属性页接口 ReturnGetInterface((IspecifyPropertyPages *)this,ppv); Elseif(riid==IID_ITitleOverlay) ReturnGetInterface((ItitleOverlay *)this,ppv); ReturnCtransInPlaceFilter::NonDelegatingQueryInterface(riid,ppv); CompleteConnect函数的实现 实现CompleteConnect 函数,可以在输入Pin 成功连接后获得外媒类型描述,代码如下: HRESULT CfilterTitleOverlay::CompleteConnect(PIN_DIRECTION direction,Ipin *pReceivePin) HRESULThr=CtransInPlaceFilter::CompleteConnect(direction,pReceivePin); If(SUCCEED(hr)&&direction==PINDIR_INPUT) Returnhr; 其中,SetInputVideoInfoToController函数将输入数据的格式修改给应用逻辑控制对象,该函 数实现代码如下: HRESULT CfilterTitleOverlay::SetInputVideoInfoToController(void) StartStreaming和StopStreaming 函数的实现 实现StartStreaming和StopStreaming函数,可以分别调用应用逻辑控制对象的相应函数, 进行初始化和反初始化,代码如下: HRESULT CfilterTitleOverlay::StartStraming() BOOLpass=mOverlayController->StartTitleOverlay(); Return pass?S_OK:E_FAIL; HRESULTCfilterTitleOverlay::StopStreaming() mOVerlayController->StopTitleOverlay();return NOERROR; 逻辑控制类推动逻辑控制类才是字符叠加应该真正推动的地方。
字符叠加原理:一般输入的每个视频 Sample(非压缩格式)都带有一帧图像数据,字 符叠加实际上就是将选定位置的图像像素值替换为数组图像的像素值。直观的看法是:将图 像帧选入GDI 的DC 中,再使用GDI 函数TextOut 和DrawText 等直接在图像帧上输出数组, 然后再取出图像帧并返回给Filter 框架。实际上,这种做法的效率不是很理想,要做到即时 叠加难度很高。 另一种方法:在内存中首先创建一个二色位图,然后在这个位图上画出字符内容。于是, 我们就得到了字符内容的一块点阵信息:比如0 表示背景,1 表示形势字符。在实际叠加的 时候,我们将图像帧指定位置的像素与数组点阵的像素位对应,如果数组点阵的像素位值为 0,则维持图像帧对应的像素值不变;如果为 1,则将图像帧对应的像素值更换为用户设定 的字符颜色值。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-121808-1.html
两个危机可同时化解
总局盯着小米电源查一段时间
伊国犯得着抱俄大腿吗