(DirectX系列09)DirectShow EDS应用编码分析

DirectX系列09DirectShow EDS应用编码分析

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

本章通过DirectX timelinetest为例子详细介绍Eds应用编码实现,其中主要包括创建事件线对象、在轨道上加入音频过度、在轨道上加入视频过度、使用控制引擎等。

创建事件线对象

这是在所有操作之前必须要做的事情,同样也贯穿这个编码过程,如下代码;

hr = CoCreateInstance(

CLSID_AMTimeline,

NULL,

CLSCTX_INPROC_SERVER,

IID_IAMTimeline,

(void**) &pTimeline

);

if(FAILED( hr )) {

Err(_T("Could not create timeline"));

return hr;

}

创建组,并标记为音频组或视频组

DirectShow 通过CreateEmptyNode来创建EDS组,并采用SetMediaType函数来标识音视频组,设置为MEDIATYPE_Video标识为视频组,设置为MEDIATYPE_Audio为音频组,如下代码;

// 创建视频组

hr = pTimeline->CreateEmptyNode( &pVideoGroupObj, TIMELINE_MAJOR_TYPE_GROUP );

CComQIPtr< IAMTimelineGroup, &IID_IAMTimelineGroup > pVideoGroup( pVideoGroupObj );

CMediaType VideoGroupType;

// all we set is the major type. The group will automatically use other defaults

VideoGroupType.SetType( &MEDIATYPE_Video );

hr = pVideoGroup->SetMediaType( &VideoGroupType );

// 创建音频组

hr = pTimeline->CreateEmptyNode( &pAudioGroupObj, TIMELINE_MAJOR_TYPE_GROUP );

CComQIPtr< IAMTimelineGroup, &IID_IAMTimelineGroup > pAudioGroup( pAudioGroupObj );

CMediaType AudioGroupType;

// all we set is the major type. The group will automatically use other defaults

AudioGroupType.SetType( &MEDIATYPE_Audio );

hr = pAudioGroup->SetMediaType( &AudioGroupType );

在轨道上加入视频过渡处理,并实现过渡子对象的设置

CComPtr< IAMTimelineObj > pTrack2Obj;

hr = pTimeline->CreateEmptyNode( &pTrack2Obj, TIMELINE_MAJOR_TYPE_TRACK );

if(FAILED( hr ))

{

Err(_T("Could not create second track"));

return hr;

}

hr = pRootComp->VTrackInsBefore( pTrack2Obj, -1 );

if(FAILED( hr ))

{

Err(_T("Could not insert second track"));

return hr;

}

TLStart = 0 * UNITS;

TLStop = 8 * UNITS;

MediaStart = 0 * UNITS;

MediaStop = 8 * UNITS;

(void)StringCchCopyW( pClipname, NUMELMS(pClipname), T2W( tBasePath ) );

(void)StringCchCatW( pClipname, NUMELMS(pClipname), L"///0" );

(void)StringCchCatW( pClipname, NUMELMS(pClipname),wszVideo2Name );

// create the timeline source

//

CComPtr<IAMTimelineObj> pSource2Obj;

hr = pTimeline->CreateEmptyNode( &pSource2Obj, TIMELINE_MAJOR_TYPE_SOURCE );

if(FAILED( hr ))

{

Err(_T("Could not create the second timeline source"));

return hr;

}

// set up source right

//

hr = pSource2Obj->SetStartStop( TLStart, TLStop );

CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource2Src( pSource2Obj );

hr |= pSource2Src->SetMediaTimes( MediaStart, MediaStop );

hr |= pSource2Src->SetMediaName( pClipname );

if(FAILED( hr ))

{

Err(_T("Could not configure second media source"));

return E_FAIL;

}

//--------------------------------------------

// tell the track about the source

//--------------------------------------------

CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack2( pTrack2Obj );

hr = pTrack2->SrcAdd( pSource2Obj );

if(FAILED( hr ))

{

Err(_T("Could not add second track"));

return hr;

}

CComQIPtr< IAMTimelineTransable, &IID_IAMTimelineTransable > pTransable( pTrack2 );

#ifdef DO_TRANSITION

REFERENCE_TIME TransStart = 0 * UNITS;

REFERENCE_TIME TransStop = 4 * UNITS;

// create the timeline effect

//

CComPtr<IAMTimelineObj> pTrackTransObj;

hr = pTimeline->CreateEmptyNode(&pTrackTransObj,

TIMELINE_MAJOR_TYPE_TRANSITION );

if(FAILED( hr ))

{

Err(_T("Could not create transition effect"));

return hr;

}

//--------------------------------------------

// set up filter right

//--------------------------------------------

// we set the CLSID of the DXT to use instead of a pointer to the

// actual object. We let the DXT have it's default properties.

//

hr = pTrackTransObj->SetSubObjectGUID( CLSID_DxtJpeg );

hr |= pTrackTransObj->SetStartStop( TransStart, TransStop );

CComQIPtr< IAMTimelineTrans, &IID_IAMTimelineTrans > pTrackTrans( pTrackTransObj );

hr |= pTransable->TransAdd( pTrackTransObj );

if(FAILED( hr ))

{

Err(_T("Could not configure transition object"));

return E_FAIL;

}

#ifdef CUTS_ONLY

//---------------------------------------------

// turn the transition into a cut by doing this

//---------------------------------------------

hr = pTrackTrans->SetCutsOnly( TRUE );

if(FAILED( hr ))

{

Err(_T("Could not SetCutsOnly to TRUE"));

return hr;

}

#endif // CUTS_ONLY

//---------------------------------------------

// create an transition on the track from B 2 A

//---------------------------------------------

TransStart = 4 * UNITS;

TransStop = 8 * UNITS;

// create the timeline effect

//

pTrackTransObj.Release( );

hr = pTimeline->CreateEmptyNode(&pTrackTransObj,

TIMELINE_MAJOR_TYPE_TRANSITION );

ASSERT( !FAILED( hr ) );

// set up filter right

//

hr = pTrackTransObj->SetSubObjectGUID( CLSID_DxtJpeg );

hr |= pTrackTransObj->SetStartStop( TransStart, TransStop );

pTrackTrans = pTrackTransObj;

hr |= pTrackTrans->SetSwapInputs( TRUE );

hr |= pTransable->TransAdd( pTrackTransObj );

ASSERT( !FAILED( hr ) );

在轨道中加入声音效果

CComPtr< IAMTimelineObj > pTrack4FxObj;

hr = pTimeline->CreateEmptyNode( &pTrack4FxObj, TIMELINE_MAJOR_TYPE_EFFECT );

ASSERT( !FAILED( hr ) );

// set up effect riht

//

hr = pTrack4FxObj->SetStartStop( TLStart, TLStop );

hr |= pTrack4FxObj->SetSubObjectGUID( CLSID_AudMixer );

ASSERT( !FAILED( hr ) );

// add the effect

//

CComQIPtr< IAMTimelineEffectable , &IID_IAMTimelineEffectable > pTrack4Fable( pTrack4 );

hr = pTrack4Fable->EffectInsBefore( pTrack4FxObj, -1 );

ASSERT( !FAILED( hr ) );

控制引擎的使用

hr = CoCreateInstance(

CLSID_RenderEngine,

NULL,

CLSCTX_INPROC_SERVER,

IID_IRenderEngine,

(void**) &pRenderEngine );

ASSERT( !FAILED( hr ) );

// tell the render engine about the timeline it should look at

//

hr = pRenderEngine->SetTimelineObject( pTimeline );

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// connect up the front end, then the back end

//--------------------------------------------

hr = pRenderEngine->ConnectFrontEnd( );

hr |= pRenderEngine->RenderOutputPins( );

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// get a bunch of pointers, then run the graph

//--------------------------------------------

hr = pRenderEngine->GetFilterGraph( &pGraph );

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

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

hr |= pGraph->QueryInterface( IID_IMediaSeeking, (void**) &pSeeking );

hr |= pGraph->QueryInterface( IID_IVideoWindow, (void**) &pVidWindow );

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// give the main window a meaningful title

//--------------------------------------------

BSTR bstrCaption;

WriteBSTR(&bstrCaption, wszTitle);

hr = pVidWindow->put_Caption(bstrCaption);

FreeBSTR(&bstrCaption);

//--------------------------------------------

// since no user interaction is allowed, remove

// system menu and maximize/minimize buttons

//--------------------------------------------

long lStyle=0;

hr = pVidWindow->get_WindowStyle(&lStyle);

lStyle &= ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);

hr = pVidWindow->put_WindowStyle(lStyle);

//--------------------------------------------

// run it

//--------------------------------------------

hr = pControl->Run( );

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// wait for it

//--------------------------------------------

long EventCode = 0;

hr = pEvent->WaitForCompletion( -1, &EventCode );

ASSERT( !FAILED( hr ) );

REFERENCE_TIME Start = 0;

#ifdef DO_RENDERRANGE

// seek the timeline back to 0

//

hr = pSeeking->SetPositions( &Start, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning );

ASSERT( !FAILED( hr ) );

hr = pRenderEngine->SetRenderRange2( 2.0, 6.0 );

ASSERT( !FAILED( hr ) );

//------------------------------------------------------

// connect up the front end, then the back end if needed

//------------------------------------------------------

hr = pRenderEngine->ConnectFrontEnd( );

ASSERT( !FAILED( hr ) );

if(hr == (HRESULT) S_WARN_OUTPUTRESET) {

hr |= pRenderEngine->RenderOutputPins( );

}

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// run it

//--------------------------------------------

hr = pControl->Run( );

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// wait for it

//--------------------------------------------

hr = pEvent->WaitForCompletion( -1, &EventCode );

ASSERT( !FAILED( hr ) );

#endif // DO_RENDERRANGE

#ifdef DO_RECONNECT

//---------------------------------------------

// make a change to the timeline, however small

//---------------------------------------------

CComPtr< IAMTimelineObj > pTransObj;

REFERENCE_TIME InOut = -1;

pTransable->GetNextTrans( &pTransObj, &InOut );

CComQIPtr< IAMTimelineTrans, &IID_IAMTimelineTrans > pTrans( pTransObj );

pTrans->SetCutsOnly( TRUE );

pTransObj.Release( );

pTrans.Release( );

hr = pTransable->GetNextTrans( &pTransObj, &InOut );

pTrans = pTransObj;

hr |= pTrans->SetCutsOnly( TRUE );

ASSERT( !FAILED( hr ) );

// seek the timeline back to 0

//

hr = pSeeking->SetPositions( &Start, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning );

ASSERT( !FAILED( hr ) );

//------------------------------------------------------

// connect up the front end, then the back end if needed

//------------------------------------------------------

hr = pRenderEngine->ConnectFrontEnd( );

if(hr == (HRESULT) S_WARN_OUTPUTRESET) {

hr |= pRenderEngine->RenderOutputPins( );

}

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// run it

//--------------------------------------------

hr = pControl->Run( );

ASSERT( !FAILED( hr ) );

//--------------------------------------------

// wait for it

//--------------------------------------------

hr = pEvent->WaitForCompletion( -1, &EventCode );

你可能感兴趣的:(show)