Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
816 lines
26 KiB
C++
816 lines
26 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: TimelineTest.cpp
|
|
//
|
|
// Desc: DirectShow sample code - creates two video tracks, using a
|
|
// transition from the A track to the B track, and then back again.
|
|
// It demonstrates how to add a transition to the timeline using a
|
|
// CLSID.
|
|
//
|
|
// Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This example creates 2 (video) tracks with a transition from the A track to
|
|
// the B track and then from B back to A. It also crossfades two audio tracks
|
|
// from A to B. This sample also demonstrates how to add a transition by CLSID
|
|
// to the timeline and how to vary volume envelope properties by the
|
|
// property setter.
|
|
//
|
|
// Note: Error checking is handled mostly with ASSERTs in order to keep
|
|
// the sample as uncluttered as possible. In some cases where several
|
|
// related function calls are made together, the HRESULT value returned from
|
|
// the functions will be bitwise OR'ed with other HRESULT values. This value
|
|
// will eventually be tested for failure using the FAILED macro.
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include <streams.h>
|
|
#include <atlbase.h>
|
|
#include <qedit.h>
|
|
#include <dxutil.h>
|
|
|
|
#ifdef STRICT
|
|
#undef STRICT
|
|
#endif
|
|
#include <dxutil.cpp>
|
|
|
|
//
|
|
// Conditional compilation flags to enable/disable effects
|
|
//
|
|
//#define CUTS_ONLY
|
|
|
|
// define this to show an example of calling ConnectFrontEnd( )
|
|
// a second time on the render engine and having it rerender
|
|
// the graph
|
|
#define DO_RECONNECT
|
|
|
|
// define this to do an audio crossfade
|
|
#define DO_CROSSFADE
|
|
|
|
// define this to only render a portion of the full timeline
|
|
#define DO_RENDERRANGE
|
|
|
|
// define this to enable transitions
|
|
#define DO_TRANSITION
|
|
|
|
//
|
|
// Global data
|
|
//
|
|
|
|
// Use bitmaps and audio files known to install with the DirectX 8 SDK
|
|
WCHAR * wszVideo1Name = L"dx5_logo.bmp";
|
|
WCHAR * wszVideo2Name = L"env3.bmp";
|
|
WCHAR * wszAudio1Name = L"track2.mp3";
|
|
WCHAR * wszAudio2Name = L"track3.mp3";
|
|
WCHAR * wszTitle = L"Timeline Test Sample";
|
|
|
|
//
|
|
// Function prototypes
|
|
//
|
|
int TimelineTest( );
|
|
void Err(TCHAR *szErr);
|
|
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
// init the ole32 libraries
|
|
//
|
|
CoInitialize( NULL );
|
|
|
|
//
|
|
// NOTE: There is no user interaction with this sample.
|
|
// It will run to completion and exit.
|
|
//
|
|
TimelineTest();
|
|
|
|
CoUninitialize( );
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void Err(TCHAR *szErr)
|
|
{
|
|
MessageBox(NULL, szErr, TEXT("Error"), MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
|
|
int TimelineTest( )
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
// use the ATL libraries to do automatic reference counting on pointers
|
|
//
|
|
CComPtr< IRenderEngine > pRenderEngine;
|
|
CComPtr< IGraphBuilder > pGraph;
|
|
CComPtr< IVideoWindow > pVidWindow;
|
|
CComPtr< IMediaEvent > pEvent;
|
|
CComPtr< IAMTimeline > pTimeline;
|
|
CComPtr< IAMTimelineObj > pVideoGroupObj;
|
|
CComPtr< IAMTimelineObj > pAudioGroupObj;
|
|
CComPtr< IMediaControl > pControl;
|
|
CComPtr< IMediaSeeking > pSeeking;
|
|
|
|
//--------------------------------------------
|
|
// make the timeline
|
|
//--------------------------------------------
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_AMTimeline,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IAMTimeline,
|
|
(void**) &pTimeline
|
|
);
|
|
|
|
if(FAILED( hr )) {
|
|
Err(_T("Could not create timeline"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// make the root group/composition
|
|
//--------------------------------------------
|
|
|
|
hr = pTimeline->CreateEmptyNode( &pVideoGroupObj, TIMELINE_MAJOR_TYPE_GROUP );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not create empty node"));
|
|
return hr;
|
|
}
|
|
|
|
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 );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not set media type"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// add the group to the timeline
|
|
//--------------------------------------------
|
|
|
|
hr = pTimeline->AddGroup( pVideoGroupObj );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not add video group"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// make a track
|
|
//--------------------------------------------
|
|
|
|
CComPtr< IAMTimelineObj > pTrack1Obj;
|
|
hr = pTimeline->CreateEmptyNode( &pTrack1Obj, TIMELINE_MAJOR_TYPE_TRACK );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not create empty track"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// tell the composition about the track
|
|
//--------------------------------------------
|
|
|
|
CComQIPtr< IAMTimelineComp, &IID_IAMTimelineComp > pRootComp( pVideoGroupObj );
|
|
hr = pRootComp->VTrackInsBefore( pTrack1Obj, -1 );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not insert track"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// create a source from 0 to 8 seconds
|
|
//--------------------------------------------
|
|
|
|
REFERENCE_TIME TLStart = 0 * UNITS;
|
|
REFERENCE_TIME TLStop = 8 * UNITS;
|
|
|
|
// you can set these if you want to other numbers, and the video will
|
|
// speed up or slow down if the duration isn't the same as the timeline's.
|
|
REFERENCE_TIME MediaStart = 0 * UNITS;
|
|
REFERENCE_TIME MediaStop = 8 * UNITS;
|
|
WCHAR pClipname[256];
|
|
TCHAR * tBasePath = (TCHAR *) DXUtil_GetDXSDKMediaPath( );
|
|
wcscpy( pClipname, T2W( tBasePath ) );
|
|
wcscat( pClipname, L"\\" );
|
|
wcscat( pClipname, wszVideo1Name );
|
|
|
|
// create the timeline source
|
|
//
|
|
CComPtr<IAMTimelineObj> pSource1Obj;
|
|
hr = pTimeline->CreateEmptyNode( &pSource1Obj, TIMELINE_MAJOR_TYPE_SOURCE );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not create the timeline source"));
|
|
return hr;
|
|
}
|
|
|
|
// set up source right
|
|
//
|
|
hr = pSource1Obj->SetStartStop( TLStart, TLStop );
|
|
CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource1Src( pSource1Obj );
|
|
hr |= pSource1Src->SetMediaTimes( MediaStart, MediaStop );
|
|
hr |= pSource1Src->SetMediaName( pClipname );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not configure media source"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// tell the track about the source
|
|
//--------------------------------------------
|
|
|
|
CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack1( pTrack1Obj );
|
|
hr = pTrack1->SrcAdd( pSource1Obj );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not add source to track"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// make another track
|
|
//--------------------------------------------
|
|
|
|
CComPtr< IAMTimelineObj > pTrack2Obj;
|
|
hr = pTimeline->CreateEmptyNode( &pTrack2Obj, TIMELINE_MAJOR_TYPE_TRACK );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not create second track"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// tell the composition about the track
|
|
//--------------------------------------------
|
|
|
|
hr = pRootComp->VTrackInsBefore( pTrack2Obj, -1 );
|
|
if(FAILED( hr ))
|
|
{
|
|
Err(_T("Could not insert second track"));
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// create a source for the 2nd track
|
|
//--------------------------------------------
|
|
|
|
TLStart = 0 * UNITS;
|
|
TLStop = 8 * UNITS;
|
|
MediaStart = 0 * UNITS;
|
|
MediaStop = 8 * UNITS;
|
|
wcscpy( pClipname, T2W( tBasePath ) );
|
|
wcscat( pClipname, L"\\" );
|
|
wcscat( 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
|
|
|
|
//---------------------------------------------
|
|
// create an transition on the track from A 2 B
|
|
//---------------------------------------------
|
|
|
|
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 ) );
|
|
|
|
//--------------------------------------------
|
|
// set a property on the transition
|
|
//--------------------------------------------
|
|
|
|
CComPtr< IPropertySetter > pTransSetter;
|
|
pTransSetter.CoCreateInstance( CLSID_PropertySetter );
|
|
DEXTER_PARAM Param;
|
|
CComBSTR ParamName( "MaskNum" ); // the property name
|
|
Param.Name = ParamName;
|
|
Param.nValues = 1; // how many values we want to set
|
|
DEXTER_VALUE Value;
|
|
memset( &Value, 0, sizeof( Value ) );
|
|
VariantClear( &Value.v );
|
|
V_I4( &Value.v ) = 128; // mask number 128
|
|
V_VT( &Value.v ) = VT_I4; // integer
|
|
hr = pTransSetter->AddProp( Param, &Value );
|
|
hr |= pTrackTransObj->SetPropertySetter( pTransSetter );
|
|
ASSERT( !FAILED( hr ) );
|
|
// pTransSetter will be auto-freed by COM
|
|
|
|
#endif // DO_TRANSITION
|
|
|
|
#ifdef CUTS_ONLY
|
|
//---------------------------------------------
|
|
// turn the transition into a cut by doing this
|
|
//---------------------------------------------
|
|
|
|
hr = pTrackTrans->SetCutsOnly( TRUE );
|
|
ASSERT( !FAILED( hr ) );
|
|
#endif
|
|
|
|
//--------------------------------------------
|
|
// make the root audio group/composition
|
|
//--------------------------------------------
|
|
|
|
hr = pTimeline->CreateEmptyNode( &pAudioGroupObj, TIMELINE_MAJOR_TYPE_GROUP );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
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 );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// add the group to the timeline
|
|
//--------------------------------------------
|
|
|
|
hr = pTimeline->AddGroup( pAudioGroupObj );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// make a track
|
|
//--------------------------------------------
|
|
|
|
CComPtr< IAMTimelineObj > pTrack3Obj;
|
|
hr = pTimeline->CreateEmptyNode( &pTrack3Obj, TIMELINE_MAJOR_TYPE_TRACK );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// tell the composition about the track
|
|
//--------------------------------------------
|
|
|
|
CComQIPtr< IAMTimelineComp, &IID_IAMTimelineComp > pAudioComp( pAudioGroupObj );
|
|
hr = pAudioComp->VTrackInsBefore( pTrack3Obj, -1 );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// create a source
|
|
//--------------------------------------------
|
|
|
|
TLStart = 0 * UNITS;
|
|
TLStop = 6 * UNITS;
|
|
// you can set these if you want to other numbers, the video will speed up
|
|
// or slow down if the duration isn't the same at the timeline's.
|
|
MediaStart = 0 * UNITS;
|
|
MediaStop = 6 * UNITS;
|
|
wcscpy( pClipname, T2W( tBasePath ) );
|
|
wcscat( pClipname, L"\\" );
|
|
wcscat( pClipname, wszAudio1Name );
|
|
|
|
// create the timeline source
|
|
//
|
|
CComPtr<IAMTimelineObj> pSource3Obj;
|
|
hr = pTimeline->CreateEmptyNode( &pSource3Obj, TIMELINE_MAJOR_TYPE_SOURCE );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
// set up source right
|
|
//
|
|
hr = pSource3Obj->SetStartStop( TLStart, TLStop );
|
|
CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource3Src( pSource3Obj );
|
|
hr |= pSource3Src->SetMediaTimes( MediaStart, MediaStop );
|
|
hr |= pSource3Src->SetMediaName( pClipname );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// tell the track about the source
|
|
//--------------------------------------------
|
|
|
|
CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack3( pTrack3Obj );
|
|
hr = pTrack3->SrcAdd( pSource3Obj );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
#ifdef DO_CROSSFADE
|
|
//--------------------------------------------
|
|
// put a volume effect on the source
|
|
//--------------------------------------------
|
|
|
|
TLStart = 4 * UNITS;
|
|
TLStop = 6 * UNITS;
|
|
|
|
CComPtr< IAMTimelineObj > pTrack3FxObj;
|
|
hr = pTimeline->CreateEmptyNode( &pTrack3FxObj, TIMELINE_MAJOR_TYPE_EFFECT );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
// set up effect right
|
|
//
|
|
hr = pTrack3FxObj->SetStartStop( TLStart, TLStop );
|
|
hr |= pTrack3FxObj->SetSubObjectGUID( CLSID_AudMixer );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
// add the effect
|
|
//
|
|
CComQIPtr< IAMTimelineEffectable , &IID_IAMTimelineEffectable > pTrack3Fable( pTrack3 );
|
|
hr = pTrack3Fable->EffectInsBefore( pTrack3FxObj, -1 );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//------------------------------------------------
|
|
// set the the volume envelope on the audio source
|
|
//------------------------------------------------
|
|
|
|
CComPtr< IPropertySetter > pVolSetter;
|
|
pVolSetter.CoCreateInstance( CLSID_PropertySetter );
|
|
CComBSTR VolParamName( "Vol" ); // the property name
|
|
Param.Name = VolParamName;
|
|
Param.nValues = 2; // how many values we want to set
|
|
|
|
DEXTER_VALUE AudioValue[2];
|
|
memset( &AudioValue[0], 0, sizeof( Value ) );
|
|
VariantClear( &AudioValue[0].v );
|
|
V_R8( &AudioValue[0].v ) = 1.0;
|
|
V_VT( &AudioValue[0].v ) = VT_R8;
|
|
AudioValue[0].rt = 0 * UNITS;
|
|
memset( &AudioValue[1], 0, sizeof( Value ) );
|
|
VariantClear( &AudioValue[1].v );
|
|
V_R8( &AudioValue[1].v ) = 0.0;
|
|
V_VT( &AudioValue[1].v ) = VT_R8;
|
|
AudioValue[1].rt = 2 * UNITS;
|
|
AudioValue[1].dwInterp = DEXTERF_INTERPOLATE;
|
|
|
|
hr = pVolSetter->AddProp( Param, AudioValue );
|
|
hr |= pTrack3FxObj->SetPropertySetter( pVolSetter );
|
|
ASSERT( !FAILED( hr ) );
|
|
pVolSetter.Release( );
|
|
#endif // DO_CROSSFADE
|
|
|
|
//--------------------------------------------
|
|
// make another track
|
|
//--------------------------------------------
|
|
|
|
CComPtr< IAMTimelineObj > pTrack4Obj;
|
|
hr = pTimeline->CreateEmptyNode( &pTrack4Obj, TIMELINE_MAJOR_TYPE_TRACK );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// tell the composition about the track
|
|
//--------------------------------------------
|
|
|
|
hr = pAudioComp->VTrackInsBefore( pTrack4Obj, -1 );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// create a source for the 2nd track
|
|
//--------------------------------------------
|
|
|
|
TLStart = 4 * UNITS;
|
|
TLStop = 8 * UNITS;
|
|
MediaStart = 0 * UNITS;
|
|
MediaStop = 4 * UNITS;
|
|
wcscpy( pClipname, T2W( tBasePath ) );
|
|
wcscat( pClipname, L"\\" );
|
|
wcscat( pClipname, wszAudio2Name );
|
|
|
|
// create the timeline source
|
|
//
|
|
CComPtr<IAMTimelineObj> pSource4Obj;
|
|
hr = pTimeline->CreateEmptyNode( &pSource4Obj, TIMELINE_MAJOR_TYPE_SOURCE );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
// set up source right
|
|
//
|
|
hr = pSource4Obj->SetStartStop( TLStart, TLStop );
|
|
CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource4Src( pSource4Obj );
|
|
hr |= pSource4Src->SetMediaTimes( MediaStart, MediaStop );
|
|
hr |= pSource4Src->SetMediaName( pClipname );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// tell the track about the source
|
|
//--------------------------------------------
|
|
|
|
CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack4( pTrack4Obj );
|
|
hr = pTrack4->SrcAdd( pSource4Obj );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
#ifdef DO_CROSSFADE
|
|
//--------------------------------------------
|
|
// put a volume effect on the source
|
|
//--------------------------------------------
|
|
|
|
TLStart = 4 * UNITS;
|
|
TLStop = 6 * UNITS;
|
|
|
|
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 ) );
|
|
|
|
//------------------------------------------------
|
|
// set the the volume envelope on the audio source
|
|
//------------------------------------------------
|
|
|
|
pVolSetter.CoCreateInstance( CLSID_PropertySetter );
|
|
memset( &AudioValue[0], 0, sizeof( Value ) );
|
|
VariantClear( &AudioValue[0].v );
|
|
V_R8( &AudioValue[0].v ) = 0.0;
|
|
V_VT( &AudioValue[0].v ) = VT_R8;
|
|
AudioValue[0].rt = 0 * UNITS;
|
|
memset( &AudioValue[1], 0, sizeof( Value ) );
|
|
VariantClear( &AudioValue[1].v );
|
|
V_R8( &AudioValue[1].v ) = 1.0;
|
|
V_VT( &AudioValue[1].v ) = VT_R8;
|
|
AudioValue[1].rt = 2 * UNITS;
|
|
AudioValue[1].dwInterp = DEXTERF_INTERPOLATE;
|
|
|
|
hr = pVolSetter->AddProp( Param, AudioValue );
|
|
hr |= pTrack4FxObj->SetPropertySetter( pVolSetter );
|
|
ASSERT( !FAILED( hr ) );
|
|
// pVolSetter will be auto-freed by COM
|
|
#endif // DO_CROSSFADE
|
|
|
|
//----------------------------------------------
|
|
// make sure files are in their correct location
|
|
//----------------------------------------------
|
|
|
|
hr = pTimeline->ValidateSourceNames(
|
|
SFN_VALIDATEF_CHECK | SFN_VALIDATEF_POPUP | SFN_VALIDATEF_REPLACE,
|
|
NULL,
|
|
0 );
|
|
ASSERT( !FAILED( hr ) );
|
|
|
|
//--------------------------------------------
|
|
// create the render engine
|
|
//--------------------------------------------
|
|
|
|
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 == 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 == 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_RECONNECT
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|