分享
 
 
 

基于DirectShow非线性编辑DES

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

基于DirectShow非线性编辑DES

作者:freepublic

下载源代码

关键词Timeline,Virtual Track,Transition,Audio Group和Video Group

摘要

本文详细阐述了基于DirectShow核心框架的非线性编辑的基本原理,并提供了一个编辑的源代码,演示如何拼接两个音视频文件,实现视频过渡效果,并预览。

编译环境WindowsXP,VC6.0+sp5,DX9 SDK.

技术原理

DES (DirectShow Editing

Services),是一套基于DirectShow核心框架的编程接口。DES的出现,简化了视频编辑任务,弥补了DirectShow对于媒体文件非线性编辑支持的先天性不足。但是,就技术本身而言,DES并没有超越DirectShow

Filter架构,而只是DirectShow Filter的一种增强应用。我们可以从下图中了解到DES在我们整个多媒体处理应用中的位置。

下面,我们举个例子来看一下DES能够给我们带来些什么。假如我们现在有三个文件A、B和C,使用这三个文件做成一个合成的文件。我们想取A的4秒钟的内容,紧接着取B的10秒钟的内容,再紧接着C的5秒钟的内容。如果仅仅是这样,我们直接使用DirectShow

Filter是不难实现的。(一般情况下,应用程序级会维持各个文件的编辑信息,由应用程序根据这些信息动态创建/控制功能单一的Filter

Graph,以顺序对各个文件进行处理。)但是,如果我们的"创意"是随时改变的,我们现在想让C在B之前出现,或者我们想取A的不同位置的10秒钟内容,或者我们想给整个合成的文件加上一段美妙的背景音乐。如果我们仍然直接使用DirectShow

Filter去实现,情况就变得很复杂了。然而,对于DES,这真的是小Case!(将所有的编辑信息以DES提供的接口告诉DES,其它的如Filter

Graph的创建/控制输出,就完全交给DES来负责吧!这时候,DES创建的Filter

Graph带有各个Source输出的控制功能,一般比较复杂。)

如果我们使用DES,我们还可以得到如下的便利:

1. 基于时间线(Timeline)的结构以及Track的概念,使得多媒体文件的组织、编辑变得直观而高效;

2. 支持即时的预览;

3. 视频编辑项目支持XML文档的形式保存;

4. 支持对视频/音频的效果处理,以及视频之间切换的过渡处理;

5. 可以直接使用DES提供的100多种SMPTE过渡效果,以及MS IE自带的各种Transform、Transition组件;

6. 支持通过色调、亮度、RGB值或者alpha值进行图像的合成;

7. 自动对源文件输出的视频帧率、音频的采样率进行调整,直接支持视频的缩放。

接下去,我们来看一下DES的结构(Timeline模型),如下图所示:

这是一个树形结构。在这棵树中,音视频文件是叶结点,称作为Source;一个或多个Source组成一个Track,每个Track都有统一的媒体格式输出;Track的集合称作为Composition,每个Composition可以对其所有的Composition或Track进行各种复杂的编辑;顶级的Composition或Track就组成了Group;每个Group输出单一格式的媒体流,所有的Group组成一个Timeline,

Timeline表示一个视频编辑的项目,它是这棵树的根节点。一个Timeline项目必须至少包含一个Group,最典型的情况一般包含两个Group:Audio

Group和Video Group。

下面,我们来看一个典型的基于Timeline的Source Track编排。如下图:

图中,箭头方向即是Timeline的方向。这个Timeline由两个Group组成,每个Group中包含两个Source

Track。在Group中,Track是有优先级的(Track

0具有最低的优先级,依次类推)。运行时,总是输出高优先级的Track中的Source内容。如果此时高优先级的Track中没有Source输出,则让低优先级的Track中的Source输出。如上图中Video

Group的输出顺序为Source A->Source C->Source B。而对于Audio

Group,它的所有Track的输出只是简单的合成。

我们再看一个典型的Track之间加入了Transition的Timeline结构。如下图:

图中,Video Group中是两个Track以及Track上几个Source的编排;Rendered

video中表示这个Group最终输出的效果。我们可以看到,在Track 1上有一个Transition,表示这个时间段上从Track

0过渡到Track1的效果。一般,Transition位于高优先级的Track上。Transition也是有方向的,默认是从低优先级的Track过渡到高优先级的Track。当然,我们也可以改变Transition的方向。如下图所示,第一个Transition是从Track

0到Track 1,第二个Transition是从Track 1到Track 0。

值得注意的是,DES使用的Transition采用了叫做DirectX Transform

Object的技术。任何两输入一输出的DirectX Transform

Object都可以用作Transition。遗憾的是,微软现在的DirectX

SDK不再支持这种组件的开发。我们能够使用的,只有DES本身提供的几种效果,还有就是Microsoft Internet

Explorer自带的效果。DES使用的Effect情况类似,只不过DES Effect是单输入单输出的DirectX Transform

Object。

讲到这里,我们已经对DES结构有了一个初步的了解。我们需要回过去再看一看这个Timeline树结构。我们会发现,Group下面一般都有一个Composition,而随后的图例中,我们看到一般Group下直接嵌入的是Track。那么,Composition有什么用呢?熟悉《设计模式》的人很容易就明白了,微软采用的就是对象结构型模式的其中一种叫Composite(组合)的模式。Composition可以包装几个Track(这几个Track之间可能是包含Transition的),组成一个Virtual

Track,并且与其他普通的Track接口保持一致。我们完全可以把这个Virtual

Track与普通的Track一样操作,进而很方便地进行更加复杂、丰富的效果编辑

我提供了一个把两个.wmv文件进行编辑的源代码,有两个Track,为了简便,只是提供了视频的Transition,音频的Transition也是同样的道理,只不过需要多建一个Audio

Group。程序编译需要安装DX9 SDK。目前上载系统有问题,无法上传源代码,以后补上。以下只主要源代码。

链接需要strmiids.lib库;

void CDesTestDlg::OnStart()

{

// 创建空时间线.

IAMTimeline *pTL = NULL;

CoInitialize(NULL);

CoCreateInstance(CLSID_AMTimeline, NULL, CLSCTX_INPROC_SERVER, IID_IAMTimeline, (void**)&pTL);

// GROUP: Add a video group to the timeline.

IAMTimelineGroup *pGroup = NULL;

IAMTimelineObj *pGroupObj = NULL;

pTL->CreateEmptyNode(&pGroupObj, TIMELINE_MAJOR_TYPE_GROUP);

pGroupObj->QueryInterface(IID_IAMTimelineGroup, (void **)&pGroup);

// Set the group media type. This example sets the type to "video" and

// lets DES pick the default settings. For a more detailed example,

// see "Setting the Group Media Type."

AM_MEDIA_TYPE mtGroup;

ZeroMemory(&mtGroup, sizeof(AM_MEDIA_TYPE));

mtGroup.majortype = MEDIATYPE_Video;

pGroup->SetMediaType(&mtGroup);

pTL->AddGroup(pGroupObj);

pGroupObj->Release();

// TRACK: Add two track to the group.

IAMTimelineObj *pTrackObj1,*pTrackObj2;

IAMTimelineTrack *pTrack1,*pTrack2;

IAMTimelineComp *pComp1 = NULL;//,*pComp2 = NULL;

pTL->CreateEmptyNode(&pTrackObj1, TIMELINE_MAJOR_TYPE_TRACK);

pGroup->QueryInterface(IID_IAMTimelineComp, (void **)&pComp1);

pComp1->VTrackInsBefore(pTrackObj1, -1);

pTrackObj1->QueryInterface(IID_IAMTimelineTrack, (void **)&pTrack1);

pTL->CreateEmptyNode(&pTrackObj2, TIMELINE_MAJOR_TYPE_TRACK);

pGroup->QueryInterface(IID_IAMTimelineComp, (void **)&pComp1);

pComp1->VTrackInsBefore(pTrackObj2, -1);

pTrackObj2->QueryInterface(IID_IAMTimelineTrack, (void **)&pTrack2);

pTrackObj1->Release();

pTrackObj2->Release();

pComp1->Release();

pGroup->Release();

// SOURCE: Add two source to the track.

IAMTimelineSrc *pSource1 = NULL,*pSource2 = NULL;

IAMTimelineObj *pSourceObj1,*pSourceObj2;

pTL->CreateEmptyNode(&pSourceObj1, TIMELINE_MAJOR_TYPE_SOURCE);

pSourceObj1->QueryInterface(IID_IAMTimelineSrc, (void **)&pSource1);

pTL->CreateEmptyNode(&pSourceObj2, TIMELINE_MAJOR_TYPE_SOURCE);

pSourceObj2->QueryInterface(IID_IAMTimelineSrc, (void **)&pSource2);

// Set the times and the file name.

pSourceObj1->SetStartStop(0, 100000000);

pSourceObj2->SetStartStop(50000000, 100000000);

BSTR bstrFile1 = SysAllocString(OLESTR("news.WMV"));

BSTR bstrFile2 = SysAllocString(OLESTR("vos.wmv"));

pSource1->SetMediaName(bstrFile1);

pSource2->SetMediaName(bstrFile2);

SysFreeString(bstrFile1);

SysFreeString(bstrFile2);

//设置基于媒体本身的开始和结束时间

pSource1->SetMediaTimes(00000000, 100000000);

pSource2->SetMediaTimes(50000000, 100000000);

pTrack1->SrcAdd(pSourceObj1);

pTrack2->SrcAdd(pSourceObj2);

pSourceObj1->Release();

pSourceObj2->Release();

pSource1->Release();

pSource2->Release();

pTrack1->Release();

pTrack2->Release();

// Create the transition object.

IAMTimelineObj *pTransObj = NULL;

HRESULT hr = pTL->CreateEmptyNode(&pTransObj, TIMELINE_MAJOR_TYPE_TRANSITION);

// Set the subobject.

hr = pTransObj->SetSubObjectGUID(CLSID_DxtJpeg); // SMPTE Wipe

// Set the start and stop times.

hr = pTransObj->SetStartStop(50000000, 100000000);

// Insert the transition object into the timeline.

IAMTimelineTransable *pTransable = NULL;

hr = pTrack2->QueryInterface(IID_IAMTimelineTransable, (void **)&pTransable);

hr = pTransable->TransAdd(pTransObj);

IPropertySetter *pProp; // Property setter

hr = CoCreateInstance(CLSID_PropertySetter, NULL, CLSCTX_INPROC_SERVER,

IID_IPropertySetter, (void**) &pProp);

// Error checking is omitted for clarity...

DEXTER_PARAM param;

DEXTER_VALUE *pValue = (DEXTER_VALUE*)CoTaskMemAlloc(sizeof(DEXTER_VALUE));

// Initialize the parameter.

param.Name = SysAllocString(L"MaskNum");

param.dispID = 0;

param.nValues = 1;

// Initialize the value.

pValue->v.vt = VT_BSTR;

pValue->v.bstrVal =SysAllocString(L"129"); //六角星

pValue->rt = 0;

pValue->dwInterp = DEXTERF_JUMP;

pProp->AddProp(param, pValue);

// Free allocated resources.

SysFreeString(param.Name);

VariantClear(&(pValue->v));

CoTaskMemFree(pValue);

// Set the property on the transition.

pTransObj->SetPropertySetter(pProp);

pProp->Release();

pTransable->Release();

pTransObj->Release();

// Preview the timeline.

IRenderEngine *pRenderEngine = NULL;

CoCreateInstance(CLSID_RenderEngine, NULL, CLSCTX_INPROC_SERVER,

IID_IRenderEngine, (void**) &pRenderEngine);

PreviewTL(pTL, pRenderEngine);

// Clean up.

pRenderEngine->ScrapIt();

pRenderEngine->Release();

pTL->Release();

CoUninitialize();

}

// 预览时间线.

void PreviewTL(IAMTimeline *pTL, IRenderEngine *pRender)

{

IGraphBuilder *pGraph = NULL;

IMediaControl *pControl = NULL;

IMediaEvent *pEvent = NULL;

// Build the graph.

pRender->SetTimelineObject(pTL);

pRender->ConnectFrontEnd( );

pRender->RenderOutputPins( );

// Run the graph.

pRender->GetFilterGraph(&pGraph);

pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);

pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

pControl->Run();

long evCode;

pEvent->WaitForCompletion(INFINITE, &evCode);

pControl->Stop();

// Clean up.

pEvent->Release();

pControl->Release();

pGraph->Release();

}

最后,希望认识一些对MPEG-4感兴趣的同仁,互相学习和交流。

My MSN:freepublic@hotmail.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有