`
tibaloga
  • 浏览: 870508 次
文章分类
社区版块
存档分类
最新评论

基于DirectShow/DES的MPEG-2音视频编辑软件的实现方案

 
阅读更多

引言

1994年欧洲制定的数字视频广播(DVB)标准和1996年美国联邦通信委员会(FCC)的先进电视制式委员会(ATSC)地面广播电视标准,在视频部分都采用了MPEG-2 标准。我国的CATV 数字网,也采用DVB 标准。MPEG-2 标准的出现,大大推动了数字视频业务的发展。越来越多的节目交换是以MPEG-2压缩方式进行的,使演播室制作涉及大量对MPEG编码压缩节目的处理,如非线性编辑涉及的不同节目间的切换、剪切和串编、在画面上加字幕、台标、实现淡入淡出等。其中节目剪切和串编是实现其他编辑功能的基础,因此实现节目剪切和串编功能更加重要。

本文针对MPEG-2 音视频,采用DirectShow(微软公司提供的在Windows 平台上进行流媒体处理的开发包)的DirectShow编辑业务(DES,DirectShow Editing Services)来实现MPEG-2音视频节目的剪切和串编。DES作为DirectShow的增强应用,简化了原本烦琐的视频编辑,弥补了非线性编辑应用软件的空白,可方便地进行音视频编辑,因此用它来编辑MPEG-2音视频文件不失为一个行之有效的方法。

DES 简介

时间线模型
DES的内部结构模型,是一个基于时间线(Timeline)的模型,它提出了一个时间线和轨道的概念,将所有的多媒体编辑组织到一个虚拟的时间线之上,实际上代表了最终的音视频剪辑作品。而对于程序员来说,这些时间线和轨道同一般的通信(COM)接口一样,都是一个个的纯虚类,可以通过继承、派生和添加必要的函数,来实现编辑操作。图1给出了DES的时间线内部模型。

这是一个树形结构,在这棵树中,音视频文件是叶结点,称作为媒体源(Source);一个或多个Source组成一个轨道(Track),每个Track都有统一的媒体格式输出;Track的集合Express总线回传给CPU。CPU或者将数据通过PCI总线传输给I/O板卡转换成基带信号输出,或者再回送到软件编解码器编码成DV格式的数据并通过1394总线输出。

相对于基于专门硬件的非编系统,基于CPU+GPU软件架构的非编系统完全摆脱了对硬件板卡的依赖,突破了专用硬 件结构的局限,利用通用的硬件系统资源实现了高性能的视频编辑和处理。

在性能方面,目前基于CPU+GPU的主流非编系统已经可以轻松实现4~6层三维特技的实时输出,远远超越了目前基 于专用板卡的主流非编系统。

在可扩展性方面,由于系统完全采取软件架构,一方面通过提高计算机平台的配置来获得更高的硬件性能,从而直接提高非编系统的性能;另一方面,通过软件模块的添加和升级,可以支持更多的编辑格式、获得更多的特技效果。

在稳定性方面,由于抛弃了专用的硬件板卡,改用结构简单的I/O板卡实现基带信号输出,系统故障率、功耗、发热量等都大大下降,稳定性则大大提高。通过进一步优化系统硬件结构,选用设计更成熟和安全的品牌图形工作站,同时将I/O板卡作进一步的模块拆分,将模拟处理电路从板卡中拆分出来作为一个独立供电、独立散热的接口盒,可使非编系统实现工作站和服务器级的安全性和稳定性,从而大大降低维护成本,提高设备利用率。

在成本方面,目前基于CPU+GPU的非编系统,其缺点主要是对计算机系统的配置要求高,计算机平台上的成本投入高昂,但由于没有专用板卡上的成本投入,总体成本并没有增加。由于计算机技术快速发展和性价比不断提高,基于CPU+GPU的非编系统在性能不断提高的同时总体成本呈下降趋势。


称作为集合(Composition),每个Composition可以对其所有的Composition 或Track 进行各种复杂的编辑;顶级的Composition或Track就组成了组(Group);每个Group输出单一格式的媒体流,所有的Group组成一个时间线(Timeline),Timeline表示一个视频编辑的项目,它是这棵树的根节点。一个Timeline项目必须至少包含一个Group,最典型的情况一般包含两个Group: 音频组(Audio Group)和视频组(VideoGroup)。

图2所示的是一个典型的基于时间线的媒体轨道图,箭头方向即是时间线的方向。这个时间线由两个组组成,每个组中包含两个媒体源轨道(SourceTrack)。在视频组中,轨道是有优先级的(轨道0具有最低的优先级,依次类推)。运行时,总是输出高优先级的轨道中的媒体源内容。如果此时高优先级的轨道中没有媒体源输出,则让低优先级的轨道中的媒体源输出。如图1中视频组的输出顺序为媒体源A→媒体源C→媒体源B。而对于音频组,它的所有轨道的输出只是简单的合成。我们利用时间线的这一原理,将媒体素材挨个赋予到相应的媒体源上去,随后将媒体源组织到不同优先级 别的轨道上,最终在时间线模型的组织下输出我们所需要的合成节目。这也就是MPEG-2 音视频编辑功能的核心模型。

时间概念
DES中大致有3种时间:
(1) 时间线时间(Timeline Time):相对于整个时间线项目的时间;
(2) 媒体时间(Media Time):相对于媒体源的时间,比如媒体源是一个文件,那么媒体时间实际上是指相对于文件开头的位置时间;
(3) 父对象时间(Parent Time):相对于时间线中已编排的某个对象的时间。

设计方案

设计方案如下:首先要完成播放MPEG-2音视频文件的功能,在浏览的过程中对需要的音视频片断的编入点和编出点作标记。其次要完成可对编辑好的音视频预览的功能,如果编辑结果比较满意,要将其保存到文件中。剪切时,仅需对播放中的文件设置入出点,按保存按钮即可边预览边保存;串编时,依次打开要编辑的文件,设置入出点,然后再按预览或保存按钮即可。

实现过程

用DirectShow实现播放功能非常方便。该功能模块主要是由GetCurrentPosition()函数得到编入点和编出点的时间,为后面的编辑提供媒体起始时间。下面主要介绍用DES进行预览和保存的实现方法。

时间线的构建
用DES实现剪辑后的预览或保存功能首先必须构建时间线模型。首先调用了系统提供的一个虚接口(虚接口的含义是:该接口包含许多未被定义的函数方法,它只提供了一个面向应用层的接口)。这个虚接口,称为IAMTimeline。我们要做的事情就是,遵循图1中时间线的结构定义自己所需要的属性和函数,并且建立出我们的时间线对象。最基本的属性包括有图1中所提到的组(Group),集合(Composition),轨道(Track)和媒体源(Source)。

(1) 首先创建一个时间线对象
IAMTimeline*pTL=NULL;
hr=CoCreatelnstance(CLSID_IAMTimeline,NULL,CLSCTX_INPROC_SERVER,IID IAMTimeline,(void* *)&pTL);
这时,我们面对的是一个空的时间线框架,接下来所作的是根据自己的需要为我们的“树形”时间线结构填上“枝 叶”。

(2) 接下来使用接口方法IAMTimeline::CreateEmptyNode创建各种DES 对象。包括:IAMTimelineGroup(视频组pVideoGroup,音频组pAudioGroup)、IAMTimelineComp(视频pVideoComp,音频pAuioComp)、IAMTimelineTrack(视频pVideoTrack,音频pAuioTrack)、IAMTimelineSrc(视频pVideoSrc,音频pAuioSrc)。
以下示例均为视频组代码,音频组与视频组类似。
IAMTimelineGroup *pVideoGroup=NULL;
IAMTimelineObj *pVideoGroupObj=NULL;
pTL → CreateEmptyNode(&pVideoGroupObj,TIMELINE_MAJOR_TYPE_GROUP);
pGroupObj→Querylnterface(IID_IAMTimelineGroup,(void **)&pVideoGroup);
调用IAMTimeline::CreateEmptyNode成功后,我们可以得到一个IAMTimelineObj接口指针。也就是说,每个我们创造的DES对象上都实现了IAMTimelineObj接口。

(3) 接着在组中加入轨道
pVideoComp→VTracklnsBefore(pVideoTrackObj, -1);
pVideoTrackObj→Querylnterface(IID_IAMTimelineTrack,(void **)&pVideoTrack)。

(4) 这是最关键的一步,设置媒体源的剪切时间和其在时间线上的时间,然后将其放到相应的轨道上。串编情况下,笔者设计了一个类记录该媒体源的文件名、片断长度、编入点和编出点,并用模版类CArray管理该类。
"class CFileInfo
" {
"public:
" CString filename;
" LONGLONG ClipLen;
" LONGLONG Outdot;
" LONGLONG Indot;
" CFileInfo();
" virtual ~CFileInfo();
" } ;
"CArrayFileArray
" for (i=1; i<=FileArray.GetSize();i++)
" {
"FileArray[0].ClipLen = 0;
hr=pVideoSrcObj→SetStartStop(FileArray[i-1].ClipLen,FileArray[i-1].ClipLen+FileArray[i].ClipLen);//设置时间线时间
hr=pVideoSrcObj→SetMediaTimes(FileArray[i].Indot,FileArray[i].Outdot );//设置媒体源时间
hr=pVideoSrcObj → SetMediaName(T2W(FileArray[i].filename));//设置媒体源文件名
hr=pVideoTrack→SrcAdd(pVideoSrcObj);//将媒体源添加到相应的轨道上
FileArray[i].ClipLen=FileArray[i-1].ClipLen+FileArray[i].ClipLen;//下一个媒体源的时间线起点时间是前一个媒体源时间线的终点时间。
" }

预览功能的实现
创建好时间线后,创建基本渲染引擎IRenderEngine,它的作用是通过已经建立好的时间线构建滤波器图(FilterGraph)供预览或者输出文件。所以,我们需把时间线的信息传递给它。接下来的过程很简单了,调用ConnectFrontEnd连接时间线部分所建立的滤波器(F i l t e r ),调用RenderOutputPins。至此,滤波器图已成功建立,只要调用IMediaControl接口的Run()函数即可进行预览了。
IRenderEngine *pRenderEngine = NULL;
hr=CoCreatelnstance(CLSID_RenderEngine, NULL,CLSCTX_INPROC_SERVER,IID_IRenderEngine, (void**)&pRenderEngine); //创建基本渲染引擎
hr=pRender→SetTimelineObject(pTL); //确定要渲染的时间线
hr=pRenderEngine→ConnectFrontEnd( );//构建graph的前端
hr=pRenderEngine→RenderOutputPins( );//将前端出来的引脚根据媒体类型分别连接到音视频渲染器,完成graph的构建
IGraphBuilder *pGraph=NULL;
IMediaControl *pControl=NULL;
hr=pRender→GetFilterGraph(&pGraph);
hr=pGraph→QueryInterface(IID_IMediaControl, (void **)&pControl);
hr=pControl→Run();//运行Filter Graph。

保存功能实现
创建好时间线和前端后,前端输出的是非压缩的音频流和视频流,而我们要保存的是压缩数据,所以必须向滤波器图中加入MPEG-2音频编码器和视频编码器以及复用器。

第一步,将视频编码器、音频编码器和复用器以及文件写入程序滤波器加入到滤波器图中
hr=AddFilterByCLSID(pGraph,LSID_VIDEO_ENCODER,L"mpeg video encoder",&pVideoEncoder);
第二步,得到组的个数及输出引脚指针,根据引脚的媒体类型将其连接到相应的编码器上。
long NumGroups;
pTL->GetGroupCount(&NumGroups);
IPin *pPin;
"for (i = 0; i < NumGroups; i++)
" {
" if (pRenderEngine->GetGroupOutputPin(i, &pPin)== S_OK)
" {
" hr=GetMediaType(pPin);
" if (hr==TRUE) // 返回值为TRUE,则引脚输出的是视频流
" ConnectFilters(pGraph,pPin,pVideoEncoder,TRUE);
" else
" ConnectFilters(pGraph,pPin,pAudioEncoder,TRUE);
" }
" }
第三步,将视频编码器和音频编码器滤波器连接到复用器滤波器上
hr=ConnectFilters(pGraph,pVideoEncoder,pMux,TRUE);
hr=ConnectFilters(pGraph,pAudioEncoder,pMux,TRUE);
第四步,连接复用器和文件写入程序滤波器
hr=ConnectFilters(pGraph,pMux,pfilewriter,TRUE);
第五步,创建MPEG输出文件IFileSinkFilter *pSin= 0;pfilewriter→QueryInterface(IID_IFileSinkFilter,(void**)&pSink);
pSink→SetFileName(T2W(strSaveFile), NULL);
最后调用IMediaControl接口的Run()函数即可进行保存了。

测试效果

实现MPEG-2 音视频剪辑的界面如图3 所示。列表框显示了待编辑的文件列表,双击文件名即可显示该文件的第一图3 MPEG-2 音视频剪辑界面帧,点击播放按钮可实现对本地文件的回放。点击入点按钮可设置要剪切文件的入点,点击出点按钮后,将先暂停播放并得到剪切终止点。依次对多个文件进行出入点设置后点击预览按钮后,回放的画面流畅,无马赛克现象,无明显延时。点击保存按钮可保存串编结果,保存后的MPEG-2音视频流,用暴风影音等软件对该文件进行回放,回放的画面流畅,质量令人满意。

结束语

音视频剪辑,无论是对电视台的节目编辑制作,还是对一般的家庭用户,都具有很大的吸引力。因此,视频剪辑功能的实用化、普及化具有很强的现实意义。采用DES可使时间线管理、特技合成更加方便可靠,同时DES采用插件方式,可以有很多支持微软DirectX的第三方插件使用,使软件更易于扩展,为用户提供更多的选择。DES使得程序的模块化更强,有利于软件的开发,同时在不断升级过程中,更可以方便地集成新的功能。当然,这种视频编辑的方法也存在着它的局限性,即编辑的精度较传统的硬件实现方法低,不适合应用于精度要求很高的编辑,这也是该软件实现视频编辑的一个缺陷。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics