home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Editing / TimelineTest / timelinetest.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  26.4 KB  |  816 lines

  1. //------------------------------------------------------------------------------
  2. // File: TimelineTest.cpp
  3. //
  4. // Desc: DirectShow sample code - creates two video tracks, using a 
  5. //       transition from the A track to the B track, and then back again.  
  6. //       It demonstrates how to add a transition to the timeline using a 
  7. //       CLSID.
  8. //
  9. // Copyright (c) 1998-2001 Microsoft Corporation.  All rights reserved.
  10. //------------------------------------------------------------------------------
  11.  
  12.  
  13. //----------------------------------------------------------------------------
  14. // This example creates 2 (video) tracks with a transition from the A track to 
  15. // the B track and then from B back to A. It also crossfades two audio tracks 
  16. // from A to B.  This sample also demonstrates how to add a transition by CLSID 
  17. // to the timeline and how to vary volume envelope properties by the 
  18. // property setter.
  19. //
  20. // Note: Error checking is handled mostly with ASSERTs in order to keep
  21. // the sample as uncluttered as possible.  In some cases where several
  22. // related function calls are made together, the HRESULT value returned from
  23. // the functions will be bitwise OR'ed with other HRESULT values.  This value
  24. // will eventually be tested for failure using the FAILED macro.
  25. //----------------------------------------------------------------------------
  26.  
  27. #include "stdafx.h"
  28. #include <streams.h>
  29. #include <atlbase.h>
  30. #include <qedit.h>
  31. #include <dxutil.h>
  32.  
  33. #ifdef STRICT
  34. #undef STRICT
  35. #endif
  36. #include <dxutil.cpp>
  37.  
  38. //
  39. // Conditional compilation flags to enable/disable effects
  40. //
  41. //#define CUTS_ONLY
  42.  
  43. // define this to show an example of calling ConnectFrontEnd( ) 
  44. // a second time on the render engine and having it rerender
  45. // the graph
  46. #define DO_RECONNECT
  47.  
  48. // define this to do an audio crossfade
  49. #define DO_CROSSFADE
  50.  
  51. // define this to only render a portion of the full timeline
  52. #define DO_RENDERRANGE
  53.  
  54. // define this to enable transitions
  55. #define DO_TRANSITION
  56.  
  57. //
  58. // Global data
  59. //
  60.  
  61. // Use bitmaps and audio files known to install with the DirectX 8 SDK
  62. WCHAR * wszVideo1Name = L"dx5_logo.bmp";
  63. WCHAR * wszVideo2Name = L"env3.bmp";
  64. WCHAR * wszAudio1Name = L"track2.mp3";
  65. WCHAR * wszAudio2Name = L"track3.mp3";
  66. WCHAR * wszTitle = L"Timeline Test Sample";
  67.  
  68. //
  69. // Function prototypes
  70. //
  71. int TimelineTest( );
  72. void Err(TCHAR *szErr);
  73.  
  74.  
  75. int APIENTRY WinMain(HINSTANCE hInstance,
  76.                      HINSTANCE hPrevInstance,
  77.                      LPSTR     lpCmdLine,
  78.                      int       nCmdShow)
  79. {
  80.     // init the ole32 libraries
  81.     //
  82.     CoInitialize( NULL );
  83.  
  84.     //
  85.     // NOTE: There is no user interaction with this sample.
  86.     // It will run to completion and exit.
  87.     //
  88.     TimelineTest();
  89.  
  90.     CoUninitialize( );
  91.  
  92.     return 0;
  93. }
  94.  
  95.  
  96. void Err(TCHAR *szErr)
  97. {
  98.     MessageBox(NULL, szErr, TEXT("Error"), MB_ICONEXCLAMATION);
  99. }
  100.  
  101.  
  102. int TimelineTest( )
  103. {
  104.     USES_CONVERSION;
  105.     HRESULT hr;
  106.  
  107.     // use the ATL libraries to do automatic reference counting on pointers
  108.     //
  109.     CComPtr< IRenderEngine > pRenderEngine;
  110.     CComPtr< IGraphBuilder > pGraph;
  111.     CComPtr< IVideoWindow > pVidWindow;
  112.     CComPtr< IMediaEvent > pEvent;
  113.     CComPtr< IAMTimeline > pTimeline;
  114.     CComPtr< IAMTimelineObj > pVideoGroupObj;
  115.     CComPtr< IAMTimelineObj > pAudioGroupObj;
  116.     CComPtr< IMediaControl > pControl;
  117.     CComPtr< IMediaSeeking > pSeeking;
  118.  
  119.     //--------------------------------------------
  120.     // make the timeline
  121.     //--------------------------------------------
  122.  
  123.     hr = CoCreateInstance(
  124.                          CLSID_AMTimeline, 
  125.                          NULL, 
  126.                          CLSCTX_INPROC_SERVER, 
  127.                          IID_IAMTimeline, 
  128.                          (void**) &pTimeline 
  129.                          );
  130.  
  131.     if(FAILED( hr )) {
  132.         Err(_T("Could not create timeline"));
  133.         return hr;
  134.     }
  135.  
  136.     //--------------------------------------------
  137.     // make the root group/composition
  138.     //--------------------------------------------
  139.  
  140.     hr = pTimeline->CreateEmptyNode( &pVideoGroupObj, TIMELINE_MAJOR_TYPE_GROUP );
  141.     if(FAILED( hr )) 
  142.     {
  143.         Err(_T("Could not create empty node"));
  144.         return hr;
  145.     }
  146.  
  147.     CComQIPtr< IAMTimelineGroup, &IID_IAMTimelineGroup > pVideoGroup( pVideoGroupObj );
  148.     CMediaType VideoGroupType;
  149.  
  150.     // all we set is the major type. The group will automatically use other defaults
  151.     VideoGroupType.SetType( &MEDIATYPE_Video );
  152.     hr = pVideoGroup->SetMediaType( &VideoGroupType );
  153.     if(FAILED( hr )) 
  154.     {
  155.         Err(_T("Could not set media type"));
  156.         return hr;
  157.     }
  158.  
  159.     //--------------------------------------------
  160.     // add the group to the timeline
  161.     //--------------------------------------------
  162.  
  163.     hr = pTimeline->AddGroup( pVideoGroupObj );
  164.     if(FAILED( hr )) 
  165.     {
  166.         Err(_T("Could not add video group"));
  167.         return hr;
  168.     }
  169.  
  170.     //--------------------------------------------
  171.     // make a track
  172.     //--------------------------------------------
  173.  
  174.     CComPtr< IAMTimelineObj > pTrack1Obj;
  175.     hr = pTimeline->CreateEmptyNode( &pTrack1Obj, TIMELINE_MAJOR_TYPE_TRACK );
  176.     if(FAILED( hr )) 
  177.     {
  178.         Err(_T("Could not create empty track"));
  179.         return hr;
  180.     }
  181.  
  182.     //--------------------------------------------
  183.     // tell the composition about the track
  184.     //--------------------------------------------
  185.  
  186.     CComQIPtr< IAMTimelineComp, &IID_IAMTimelineComp > pRootComp( pVideoGroupObj );
  187.     hr = pRootComp->VTrackInsBefore( pTrack1Obj, -1 );
  188.     if(FAILED( hr )) 
  189.     {
  190.         Err(_T("Could not insert track"));
  191.         return hr;
  192.     }
  193.  
  194.     //--------------------------------------------
  195.     // create a source from 0 to 8 seconds
  196.     //--------------------------------------------
  197.  
  198.     REFERENCE_TIME TLStart = 0 * UNITS;
  199.     REFERENCE_TIME TLStop = 8 * UNITS;
  200.  
  201.     // you can set these if you want to other numbers, and the video will 
  202.     // speed up or slow down if the duration isn't the same as the timeline's.
  203.     REFERENCE_TIME MediaStart = 0 * UNITS;
  204.     REFERENCE_TIME MediaStop = 8 * UNITS;
  205.     WCHAR pClipname[256];
  206.     TCHAR * tBasePath = (TCHAR *) DXUtil_GetDXSDKMediaPath( );
  207.     wcscpy( pClipname, T2W( tBasePath ) );
  208.     wcscat( pClipname, L"\\" );
  209.     wcscat( pClipname, wszVideo1Name );
  210.  
  211.     // create the timeline source
  212.     //
  213.     CComPtr<IAMTimelineObj> pSource1Obj;
  214.     hr = pTimeline->CreateEmptyNode( &pSource1Obj, TIMELINE_MAJOR_TYPE_SOURCE );
  215.     if(FAILED( hr )) 
  216.     {
  217.         Err(_T("Could not create the timeline source"));
  218.         return hr;
  219.     }
  220.  
  221.     // set up source right
  222.     //
  223.     hr = pSource1Obj->SetStartStop( TLStart, TLStop );
  224.     CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource1Src( pSource1Obj );
  225.     hr |= pSource1Src->SetMediaTimes( MediaStart, MediaStop );
  226.     hr |= pSource1Src->SetMediaName( pClipname );
  227.     if(FAILED( hr )) 
  228.     {
  229.         Err(_T("Could not configure media source"));
  230.         return E_FAIL;
  231.     }
  232.  
  233.     //--------------------------------------------
  234.     // tell the track about the source
  235.     //--------------------------------------------
  236.  
  237.     CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack1( pTrack1Obj );
  238.     hr = pTrack1->SrcAdd( pSource1Obj );
  239.     if(FAILED( hr )) 
  240.     {
  241.         Err(_T("Could not add source to track"));
  242.         return hr;
  243.     }
  244.  
  245.     //--------------------------------------------
  246.     // make another track 
  247.     //--------------------------------------------
  248.  
  249.     CComPtr< IAMTimelineObj > pTrack2Obj;
  250.     hr = pTimeline->CreateEmptyNode( &pTrack2Obj, TIMELINE_MAJOR_TYPE_TRACK );
  251.     if(FAILED( hr )) 
  252.     {
  253.         Err(_T("Could not create second track"));
  254.         return hr;
  255.     }
  256.  
  257.     //--------------------------------------------
  258.     // tell the composition about the track
  259.     //--------------------------------------------
  260.  
  261.     hr = pRootComp->VTrackInsBefore( pTrack2Obj, -1 );
  262.     if(FAILED( hr )) 
  263.     {
  264.         Err(_T("Could not insert second track"));
  265.         return hr;
  266.     }
  267.  
  268.     //--------------------------------------------
  269.     // create a source for the 2nd track
  270.     //--------------------------------------------
  271.  
  272.     TLStart = 0 * UNITS;
  273.     TLStop = 8 * UNITS;
  274.     MediaStart = 0 * UNITS;
  275.     MediaStop = 8 * UNITS;
  276.     wcscpy( pClipname, T2W( tBasePath ) );
  277.     wcscat( pClipname, L"\\" );
  278.     wcscat( pClipname, wszVideo2Name );
  279.  
  280.     // create the timeline source
  281.     //
  282.     CComPtr<IAMTimelineObj> pSource2Obj;
  283.     hr = pTimeline->CreateEmptyNode( &pSource2Obj, TIMELINE_MAJOR_TYPE_SOURCE );
  284.     if(FAILED( hr )) 
  285.     {
  286.         Err(_T("Could not create the second timeline source"));
  287.         return hr;
  288.     }
  289.  
  290.     // set up source right
  291.     //
  292.     hr = pSource2Obj->SetStartStop( TLStart, TLStop );
  293.     CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource2Src( pSource2Obj );
  294.     hr |= pSource2Src->SetMediaTimes( MediaStart, MediaStop );
  295.     hr |= pSource2Src->SetMediaName( pClipname );
  296.     if(FAILED( hr )) 
  297.     {
  298.         Err(_T("Could not configure second media source"));
  299.         return E_FAIL;
  300.     }
  301.  
  302.     //--------------------------------------------
  303.     // tell the track about the source
  304.     //--------------------------------------------
  305.  
  306.     CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack2( pTrack2Obj );
  307.     hr = pTrack2->SrcAdd( pSource2Obj );
  308.     if(FAILED( hr )) 
  309.     {
  310.         Err(_T("Could not add second track"));
  311.         return hr;
  312.     }
  313.  
  314.     CComQIPtr< IAMTimelineTransable, &IID_IAMTimelineTransable > pTransable( pTrack2 );
  315.     
  316.  
  317. #ifdef DO_TRANSITION
  318.  
  319.     //---------------------------------------------
  320.     // create an transition on the track from A 2 B
  321.     //---------------------------------------------
  322.  
  323.     REFERENCE_TIME TransStart = 0 * UNITS;
  324.     REFERENCE_TIME TransStop = 4 * UNITS;
  325.  
  326.     // create the timeline effect
  327.     //
  328.     CComPtr<IAMTimelineObj> pTrackTransObj;
  329.     hr = pTimeline->CreateEmptyNode(
  330.                                    &pTrackTransObj,
  331.                                    TIMELINE_MAJOR_TYPE_TRANSITION );
  332.     if(FAILED( hr )) 
  333.     {
  334.         Err(_T("Could not create transition effect"));
  335.         return hr;
  336.     }
  337.  
  338.     //--------------------------------------------
  339.     // set up filter right
  340.     //--------------------------------------------
  341.  
  342.     // we set the CLSID of the DXT to use instead of a pointer to the
  343.     // actual object. We let the DXT have it's default properties.
  344.     //
  345.     hr = pTrackTransObj->SetSubObjectGUID( CLSID_DxtJpeg );
  346.     hr |= pTrackTransObj->SetStartStop( TransStart, TransStop );
  347.     CComQIPtr< IAMTimelineTrans, &IID_IAMTimelineTrans > pTrackTrans( pTrackTransObj );
  348.     hr |= pTransable->TransAdd( pTrackTransObj );
  349.     if(FAILED( hr )) 
  350.     {
  351.         Err(_T("Could not configure transition object"));
  352.         return E_FAIL;
  353.     }
  354.  
  355. #ifdef CUTS_ONLY 
  356.     //---------------------------------------------
  357.     // turn the transition into a cut by doing this
  358.     //---------------------------------------------
  359.  
  360.     hr = pTrackTrans->SetCutsOnly( TRUE );
  361.     if(FAILED( hr )) 
  362.     {
  363.         Err(_T("Could not SetCutsOnly to TRUE"));
  364.         return hr;
  365.     }
  366.  
  367. #endif  // CUTS_ONLY
  368.  
  369.     //---------------------------------------------
  370.     // create an transition on the track from B 2 A
  371.     //---------------------------------------------
  372.  
  373.     TransStart = 4 * UNITS;
  374.     TransStop = 8 * UNITS;
  375.  
  376.     // create the timeline effect
  377.     //
  378.     pTrackTransObj.Release( );
  379.     hr = pTimeline->CreateEmptyNode(
  380.                                    &pTrackTransObj,
  381.                                    TIMELINE_MAJOR_TYPE_TRANSITION );
  382.     ASSERT( !FAILED( hr ) );
  383.  
  384.     // set up filter right
  385.     //
  386.     hr = pTrackTransObj->SetSubObjectGUID( CLSID_DxtJpeg );            
  387.     hr |= pTrackTransObj->SetStartStop( TransStart, TransStop );
  388.     pTrackTrans = pTrackTransObj;
  389.     hr |= pTrackTrans->SetSwapInputs( TRUE );
  390.     hr |= pTransable->TransAdd( pTrackTransObj );
  391.     ASSERT( !FAILED( hr ) );
  392.  
  393.     //--------------------------------------------
  394.     // set a property on the transition
  395.     //--------------------------------------------
  396.  
  397.     CComPtr< IPropertySetter > pTransSetter;
  398.     pTransSetter.CoCreateInstance( CLSID_PropertySetter );
  399.     DEXTER_PARAM Param;
  400.     CComBSTR ParamName( "MaskNum" ); // the property name
  401.     Param.Name = ParamName;
  402.     Param.nValues = 1; // how many values we want to set
  403.     DEXTER_VALUE Value;
  404.     memset( &Value, 0, sizeof( Value ) );
  405.     VariantClear( &Value.v );
  406.     V_I4( &Value.v ) = 128; // mask number 128
  407.     V_VT( &Value.v ) = VT_I4; // integer
  408.     hr = pTransSetter->AddProp( Param, &Value );
  409.     hr |= pTrackTransObj->SetPropertySetter( pTransSetter );
  410.     ASSERT( !FAILED( hr ) );
  411.     // pTransSetter will be auto-freed by COM
  412.  
  413. #endif  // DO_TRANSITION
  414.  
  415. #ifdef CUTS_ONLY 
  416.     //---------------------------------------------
  417.     // turn the transition into a cut by doing this
  418.     //---------------------------------------------
  419.  
  420.     hr = pTrackTrans->SetCutsOnly( TRUE );
  421.     ASSERT( !FAILED( hr ) );
  422. #endif
  423.  
  424.     //--------------------------------------------
  425.     // make the root audio group/composition
  426.     //--------------------------------------------
  427.  
  428.     hr = pTimeline->CreateEmptyNode( &pAudioGroupObj, TIMELINE_MAJOR_TYPE_GROUP );
  429.     ASSERT( !FAILED( hr ) );
  430.  
  431.     CComQIPtr< IAMTimelineGroup, &IID_IAMTimelineGroup > pAudioGroup( pAudioGroupObj );
  432.     CMediaType AudioGroupType;
  433.     // all we set is the major type. The group will automatically use other defaults
  434.     AudioGroupType.SetType( &MEDIATYPE_Audio );
  435.     hr = pAudioGroup->SetMediaType( &AudioGroupType );
  436.     ASSERT( !FAILED( hr ) );
  437.  
  438.     //--------------------------------------------
  439.     // add the group to the timeline
  440.     //--------------------------------------------
  441.  
  442.     hr = pTimeline->AddGroup( pAudioGroupObj );
  443.     ASSERT( !FAILED( hr ) );
  444.  
  445.     //--------------------------------------------
  446.     // make a track
  447.     //--------------------------------------------
  448.  
  449.     CComPtr< IAMTimelineObj > pTrack3Obj;
  450.     hr = pTimeline->CreateEmptyNode( &pTrack3Obj, TIMELINE_MAJOR_TYPE_TRACK );
  451.     ASSERT( !FAILED( hr ) );
  452.  
  453.     //--------------------------------------------
  454.     // tell the composition about the track
  455.     //--------------------------------------------
  456.  
  457.     CComQIPtr< IAMTimelineComp, &IID_IAMTimelineComp > pAudioComp( pAudioGroupObj );
  458.     hr = pAudioComp->VTrackInsBefore( pTrack3Obj, -1 );
  459.     ASSERT( !FAILED( hr ) );
  460.  
  461.     //--------------------------------------------
  462.     // create a source 
  463.     //--------------------------------------------
  464.  
  465.     TLStart = 0 * UNITS;
  466.     TLStop = 6 * UNITS;
  467.     // you can set these if you want to other numbers, the video will speed up
  468.     // or slow down if the duration isn't the same at the timeline's.
  469.     MediaStart = 0 * UNITS;
  470.     MediaStop = 6 * UNITS;
  471.     wcscpy( pClipname, T2W( tBasePath ) );
  472.     wcscat( pClipname, L"\\" );
  473.     wcscat( pClipname, wszAudio1Name );
  474.  
  475.     // create the timeline source
  476.     //
  477.     CComPtr<IAMTimelineObj> pSource3Obj;
  478.     hr = pTimeline->CreateEmptyNode( &pSource3Obj, TIMELINE_MAJOR_TYPE_SOURCE );
  479.     ASSERT( !FAILED( hr ) );
  480.  
  481.     // set up source right
  482.     //
  483.     hr = pSource3Obj->SetStartStop( TLStart, TLStop );
  484.     CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource3Src( pSource3Obj );
  485.     hr |= pSource3Src->SetMediaTimes( MediaStart, MediaStop );
  486.     hr |= pSource3Src->SetMediaName( pClipname );
  487.     ASSERT( !FAILED( hr ) );
  488.  
  489.     //--------------------------------------------
  490.     // tell the track about the source
  491.     //--------------------------------------------
  492.  
  493.     CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack3( pTrack3Obj );
  494.     hr = pTrack3->SrcAdd( pSource3Obj );
  495.     ASSERT( !FAILED( hr ) );
  496.  
  497. #ifdef DO_CROSSFADE
  498.     //--------------------------------------------
  499.     // put a volume effect on the source
  500.     //--------------------------------------------
  501.  
  502.     TLStart = 4 * UNITS;
  503.     TLStop = 6 * UNITS;
  504.  
  505.     CComPtr< IAMTimelineObj > pTrack3FxObj;
  506.     hr = pTimeline->CreateEmptyNode( &pTrack3FxObj, TIMELINE_MAJOR_TYPE_EFFECT );
  507.     ASSERT( !FAILED( hr ) );
  508.  
  509.     // set up effect right
  510.     //
  511.     hr = pTrack3FxObj->SetStartStop( TLStart, TLStop );
  512.     hr |= pTrack3FxObj->SetSubObjectGUID( CLSID_AudMixer );
  513.     ASSERT( !FAILED( hr ) );
  514.  
  515.     // add the effect
  516.     //
  517.     CComQIPtr< IAMTimelineEffectable , &IID_IAMTimelineEffectable > pTrack3Fable( pTrack3 );
  518.     hr = pTrack3Fable->EffectInsBefore( pTrack3FxObj, -1 );
  519.     ASSERT( !FAILED( hr ) );
  520.  
  521.     //------------------------------------------------
  522.     // set the the volume envelope on the audio source
  523.     //------------------------------------------------
  524.  
  525.     CComPtr< IPropertySetter > pVolSetter;
  526.     pVolSetter.CoCreateInstance( CLSID_PropertySetter );
  527.     CComBSTR VolParamName( "Vol" ); // the property name
  528.     Param.Name = VolParamName;
  529.     Param.nValues = 2; // how many values we want to set
  530.  
  531.     DEXTER_VALUE AudioValue[2];
  532.     memset( &AudioValue[0], 0, sizeof( Value ) );
  533.     VariantClear( &AudioValue[0].v );
  534.     V_R8( &AudioValue[0].v ) = 1.0;
  535.     V_VT( &AudioValue[0].v ) = VT_R8;
  536.     AudioValue[0].rt = 0 * UNITS;
  537.     memset( &AudioValue[1], 0, sizeof( Value ) );
  538.     VariantClear( &AudioValue[1].v );
  539.     V_R8( &AudioValue[1].v ) = 0.0;
  540.     V_VT( &AudioValue[1].v ) = VT_R8;
  541.     AudioValue[1].rt = 2 * UNITS;
  542.     AudioValue[1].dwInterp = DEXTERF_INTERPOLATE;
  543.  
  544.     hr = pVolSetter->AddProp( Param, AudioValue );
  545.     hr |= pTrack3FxObj->SetPropertySetter( pVolSetter );
  546.     ASSERT( !FAILED( hr ) );
  547.     pVolSetter.Release( );
  548. #endif  // DO_CROSSFADE
  549.  
  550.     //--------------------------------------------
  551.     // make another track 
  552.     //--------------------------------------------
  553.  
  554.     CComPtr< IAMTimelineObj > pTrack4Obj;
  555.     hr = pTimeline->CreateEmptyNode( &pTrack4Obj, TIMELINE_MAJOR_TYPE_TRACK );
  556.     ASSERT( !FAILED( hr ) );
  557.  
  558.     //--------------------------------------------
  559.     // tell the composition about the track
  560.     //--------------------------------------------
  561.  
  562.     hr = pAudioComp->VTrackInsBefore( pTrack4Obj, -1 );
  563.     ASSERT( !FAILED( hr ) );
  564.  
  565.     //--------------------------------------------
  566.     // create a source for the 2nd track
  567.     //--------------------------------------------
  568.  
  569.     TLStart = 4 * UNITS;
  570.     TLStop = 8 * UNITS;
  571.     MediaStart = 0 * UNITS;
  572.     MediaStop = 4 * UNITS;
  573.     wcscpy( pClipname, T2W( tBasePath ) );
  574.     wcscat( pClipname, L"\\" );
  575.     wcscat( pClipname, wszAudio2Name );
  576.  
  577.     // create the timeline source
  578.     //
  579.     CComPtr<IAMTimelineObj> pSource4Obj;
  580.     hr = pTimeline->CreateEmptyNode( &pSource4Obj, TIMELINE_MAJOR_TYPE_SOURCE );
  581.     ASSERT( !FAILED( hr ) );
  582.  
  583.     // set up source right
  584.     //
  585.     hr = pSource4Obj->SetStartStop( TLStart, TLStop );
  586.     CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource4Src( pSource4Obj );
  587.     hr |= pSource4Src->SetMediaTimes( MediaStart, MediaStop );
  588.     hr |= pSource4Src->SetMediaName( pClipname );
  589.     ASSERT( !FAILED( hr ) );
  590.  
  591.     //--------------------------------------------
  592.     // tell the track about the source
  593.     //--------------------------------------------
  594.  
  595.     CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack4( pTrack4Obj );
  596.     hr = pTrack4->SrcAdd( pSource4Obj );
  597.     ASSERT( !FAILED( hr ) );
  598.  
  599. #ifdef DO_CROSSFADE
  600.     //--------------------------------------------
  601.     // put a volume effect on the source
  602.     //--------------------------------------------
  603.  
  604.     TLStart = 4 * UNITS;
  605.     TLStop = 6 * UNITS;
  606.  
  607.     CComPtr< IAMTimelineObj > pTrack4FxObj;
  608.     hr = pTimeline->CreateEmptyNode( &pTrack4FxObj, TIMELINE_MAJOR_TYPE_EFFECT );
  609.     ASSERT( !FAILED( hr ) );
  610.  
  611.     // set up effect riht
  612.     //
  613.     hr = pTrack4FxObj->SetStartStop( TLStart, TLStop );
  614.     hr |= pTrack4FxObj->SetSubObjectGUID( CLSID_AudMixer );
  615.     ASSERT( !FAILED( hr ) );
  616.  
  617.     // add the effect
  618.     //
  619.     CComQIPtr< IAMTimelineEffectable , &IID_IAMTimelineEffectable > pTrack4Fable( pTrack4 );
  620.     hr = pTrack4Fable->EffectInsBefore( pTrack4FxObj, -1 );
  621.     ASSERT( !FAILED( hr ) );
  622.  
  623.     //------------------------------------------------
  624.     // set the the volume envelope on the audio source
  625.     //------------------------------------------------
  626.  
  627.     pVolSetter.CoCreateInstance( CLSID_PropertySetter );
  628.     memset( &AudioValue[0], 0, sizeof( Value ) );
  629.     VariantClear( &AudioValue[0].v );
  630.     V_R8( &AudioValue[0].v ) = 0.0;
  631.     V_VT( &AudioValue[0].v ) = VT_R8;
  632.     AudioValue[0].rt = 0 * UNITS;
  633.     memset( &AudioValue[1], 0, sizeof( Value ) );
  634.     VariantClear( &AudioValue[1].v );
  635.     V_R8( &AudioValue[1].v ) = 1.0;
  636.     V_VT( &AudioValue[1].v ) = VT_R8;
  637.     AudioValue[1].rt = 2 * UNITS;
  638.     AudioValue[1].dwInterp = DEXTERF_INTERPOLATE;
  639.  
  640.     hr = pVolSetter->AddProp( Param, AudioValue );
  641.     hr |= pTrack4FxObj->SetPropertySetter( pVolSetter );
  642.     ASSERT( !FAILED( hr ) );
  643.     // pVolSetter will be auto-freed by COM
  644. #endif  // DO_CROSSFADE
  645.     
  646.     //----------------------------------------------
  647.     // make sure files are in their correct location
  648.     //----------------------------------------------
  649.     
  650.     hr = pTimeline->ValidateSourceNames( 
  651.         SFN_VALIDATEF_CHECK | SFN_VALIDATEF_POPUP | SFN_VALIDATEF_REPLACE, 
  652.         NULL, 
  653.         0 );
  654.     ASSERT( !FAILED( hr ) );
  655.  
  656.     //--------------------------------------------
  657.     // create the render engine
  658.     //--------------------------------------------
  659.  
  660.     hr = CoCreateInstance(
  661.                          CLSID_RenderEngine,
  662.                          NULL,
  663.                          CLSCTX_INPROC_SERVER,
  664.                          IID_IRenderEngine,
  665.                          (void**) &pRenderEngine );
  666.     ASSERT( !FAILED( hr ) );
  667.  
  668.     // tell the render engine about the timeline it should look at
  669.     //
  670.     hr = pRenderEngine->SetTimelineObject( pTimeline );
  671.     ASSERT( !FAILED( hr ) );
  672.  
  673.     //--------------------------------------------
  674.     // connect up the front end, then the back end
  675.     //--------------------------------------------
  676.  
  677.     hr = pRenderEngine->ConnectFrontEnd( );
  678.     hr |= pRenderEngine->RenderOutputPins( );
  679.     ASSERT( !FAILED( hr ) );
  680.  
  681.     //--------------------------------------------
  682.     // get a bunch of pointers, then run the graph
  683.     //--------------------------------------------
  684.  
  685.     hr = pRenderEngine->GetFilterGraph( &pGraph );
  686.     hr |= pGraph->QueryInterface( IID_IMediaEvent, (void**) &pEvent );
  687.     hr |= pGraph->QueryInterface( IID_IMediaControl, (void**) &pControl );
  688.     hr |= pGraph->QueryInterface( IID_IMediaSeeking, (void**) &pSeeking );
  689.     hr |= pGraph->QueryInterface( IID_IVideoWindow, (void**) &pVidWindow );
  690.     ASSERT( !FAILED( hr ) );
  691.  
  692.     //--------------------------------------------
  693.     // give the main window a meaningful title
  694.     //--------------------------------------------
  695.  
  696.     BSTR bstrCaption;
  697.     WriteBSTR(&bstrCaption, wszTitle);
  698.     hr = pVidWindow->put_Caption(bstrCaption);
  699.     FreeBSTR(&bstrCaption);
  700.  
  701.     //--------------------------------------------
  702.     // since no user interaction is allowed, remove
  703.     // system menu and maximize/minimize buttons
  704.     //--------------------------------------------
  705.     long lStyle=0;
  706.     hr = pVidWindow->get_WindowStyle(&lStyle);
  707.     lStyle &= ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
  708.     hr = pVidWindow->put_WindowStyle(lStyle);
  709.  
  710.     //--------------------------------------------
  711.     // run it
  712.     //--------------------------------------------
  713.  
  714.     hr = pControl->Run( );
  715.     ASSERT( !FAILED( hr ) );
  716.  
  717.     //--------------------------------------------
  718.     // wait for it
  719.     //--------------------------------------------
  720.  
  721.     long EventCode = 0;
  722.     hr = pEvent->WaitForCompletion( -1, &EventCode );
  723.     ASSERT( !FAILED( hr ) );
  724.  
  725.     REFERENCE_TIME Start = 0;
  726.  
  727. #ifdef DO_RENDERRANGE
  728.  
  729.     // seek the timeline back to 0
  730.     //
  731.     hr = pSeeking->SetPositions( &Start, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning );
  732.     ASSERT( !FAILED( hr ) );
  733.  
  734.     hr = pRenderEngine->SetRenderRange2( 2.0, 6.0 );
  735.     ASSERT( !FAILED( hr ) );
  736.  
  737.     //------------------------------------------------------
  738.     // connect up the front end, then the back end if needed
  739.     //------------------------------------------------------
  740.  
  741.     hr = pRenderEngine->ConnectFrontEnd( );
  742.     ASSERT( !FAILED( hr ) );
  743.     if(hr == S_WARN_OUTPUTRESET) {
  744.         hr |= pRenderEngine->RenderOutputPins( );
  745.     }
  746.     ASSERT( !FAILED( hr ) );
  747.  
  748.     //--------------------------------------------
  749.     // run it
  750.     //--------------------------------------------
  751.  
  752.     hr = pControl->Run( );
  753.     ASSERT( !FAILED( hr ) );
  754.  
  755.     //--------------------------------------------
  756.     // wait for it
  757.     //--------------------------------------------
  758.  
  759.     hr = pEvent->WaitForCompletion( -1, &EventCode );
  760.     ASSERT( !FAILED( hr ) );
  761. #endif  // DO_RENDERRANGE
  762.  
  763. #ifdef DO_RECONNECT 
  764.  
  765.     //---------------------------------------------
  766.     // make a change to the timeline, however small
  767.     //---------------------------------------------
  768.  
  769.     CComPtr< IAMTimelineObj > pTransObj;
  770.     REFERENCE_TIME InOut = -1;
  771.     pTransable->GetNextTrans( &pTransObj, &InOut );
  772.     CComQIPtr< IAMTimelineTrans, &IID_IAMTimelineTrans > pTrans( pTransObj );
  773.     pTrans->SetCutsOnly( TRUE );
  774.     pTransObj.Release( );
  775.     pTrans.Release( );
  776.     hr = pTransable->GetNextTrans( &pTransObj, &InOut );
  777.     pTrans = pTransObj;
  778.     hr |= pTrans->SetCutsOnly( TRUE );
  779.     ASSERT( !FAILED( hr ) );
  780.  
  781.     // seek the timeline back to 0
  782.     //
  783.     hr = pSeeking->SetPositions( &Start, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning );
  784.     ASSERT( !FAILED( hr ) );
  785.  
  786.     //------------------------------------------------------
  787.     // connect up the front end, then the back end if needed
  788.     //------------------------------------------------------
  789.  
  790.     hr = pRenderEngine->ConnectFrontEnd( );
  791.     if(hr == S_WARN_OUTPUTRESET) {
  792.         hr |= pRenderEngine->RenderOutputPins( );
  793.     }
  794.     ASSERT( !FAILED( hr ) );
  795.  
  796.     //--------------------------------------------
  797.     // run it
  798.     //--------------------------------------------
  799.  
  800.     hr = pControl->Run( );
  801.     ASSERT( !FAILED( hr ) );
  802.  
  803.     //--------------------------------------------
  804.     // wait for it
  805.     //--------------------------------------------
  806.  
  807.     hr = pEvent->WaitForCompletion( -1, &EventCode );
  808.     ASSERT( !FAILED( hr ) );
  809. #endif  // DO_RECONNECT
  810.  
  811.     return 0;
  812. }
  813.  
  814.  
  815.  
  816.