home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / directshow / editing / xtltest / xmltltst.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  38.8 KB  |  1,422 lines

  1. //------------------------------------------------------------------------------
  2. // File: XMLTlTst.cpp
  3. //
  4. // Desc: DirectShow sample code - test utility for building timelines from
  5. //       .XTL files.
  6. //
  7. // Copyright (c) 1999 - 2000, Microsoft Corporation.  All rights reserved.
  8. //------------------------------------------------------------------------------
  9.  
  10. //
  11. // This sample demonstrates the following:
  12. // 
  13. // - Using IXml2Dex to load timelines from and save to .XTL files 
  14. // - Adding Windows Media (ASF) support to Editing applications
  15. // - Using IAMErrorLog to display error messages
  16. // - Preview of DES timelines (IAMTimeLine, IRenderEngine)
  17. // - Traversing the timeline nodes
  18. //
  19.  
  20. #include <windows.h>
  21. #include <streams.h>
  22. #include <stdio.h>
  23. #include <atlbase.h>
  24. #include <qedit.h>
  25.  
  26. extern CComModule _Module;
  27. #include <atlimpl.cpp>
  28.  
  29. //
  30. // NOTE:
  31. //
  32. // In order to write ASF files using this program, you need to obtain
  33. // a Windows Media Format SDK Certificate (WMStub.lib), link to it, 
  34. // and define USE_WMF_CERT below. 
  35. //
  36. // See the Windows Media Format SDK documentation for more information.
  37. //
  38. // The SDK download page is located at 
  39. // http://msdn.microsoft.com/workshop/imedia/windowsmedia/sdk/wmsdk.asp, 
  40. // with links to the SDK itself and information for obtaining a certificate.
  41. //
  42. // #define USE_WMF_CERT
  43. // 
  44.  
  45. #ifdef USE_WMF_CERT
  46.  
  47. #include <wmsdk.h>
  48. #include <dshowasf.h>
  49.  
  50.  
  51. // Note: this object is a SEMI-COM object, and can only be created statically.
  52. class CKeyProvider : public IServiceProvider {
  53. public:
  54.     STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
  55.     STDMETHODIMP_(ULONG) AddRef() { return 2; }
  56.     STDMETHODIMP_(ULONG) Release() { return 1; }
  57.  
  58.     // IServiceProvider
  59.     STDMETHODIMP QueryService(REFIID siid, REFIID riid, void **ppv);
  60.     
  61. };
  62.  
  63. CKeyProvider g_prov; // note, must stay in scope while graph is alive
  64.  
  65. #endif // USE_WMF_CERT
  66.  
  67.  
  68. class CErrorReporter : public IAMErrorLog
  69. {
  70.     // IAMErrorLog
  71.     STDMETHODIMP LogError( long Severity, BSTR ErrorString, LONG ErrorCode, 
  72.                            HRESULT hresult, VARIANT * pExtraInfo );
  73.  
  74. public:
  75.  
  76.     // SEMI COM
  77.     STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
  78.     {
  79.         if (riid == IID_IAMErrorLog || riid == IID_IUnknown) {
  80.             *ppv = (void *) static_cast<IAMErrorLog *>(this);
  81.             return NOERROR;
  82.         }    
  83.         return E_NOINTERFACE;
  84.     }
  85.     STDMETHODIMP_(ULONG) AddRef() { return 2; }
  86.     STDMETHODIMP_(ULONG) Release() { return 1; }
  87. };
  88.  
  89.  
  90. //
  91. // Declarations for helper functions defined below
  92. //
  93. IPin * GetPin( IBaseFilter * pFilter, int PinNum, PIN_DIRECTION pd );
  94.  
  95. void TurnOffPreviewMode( IAMTimeline * pTimeline );
  96.  
  97. HRESULT GetFirstSourceOnTimeline(
  98.     IAMTimeline *pTimeline, GUID MajorType,
  99.     IAMTimelineGroup ** ppGroup, IAMTimelineSrc ** ppSource );
  100.     
  101. HRESULT GetSourceVideoType(WCHAR *wszFilename, AM_MEDIA_TYPE *pmt);
  102.  
  103. HRESULT GetDestinationASFFormat(
  104.     AM_MEDIA_TYPE **ppmt,
  105.     int iProfile );
  106.  
  107. #ifdef USE_WMF_CERT
  108. HRESULT MapProfileIdToProfile(
  109.     int iProfile, IWMProfile **ppProfile);
  110. #endif
  111.  
  112. void ListWMSDKProfiles();
  113. BOOL IsAsfExtension( WCHAR * Filename );
  114.  
  115. HRESULT ConnectOutputFile(
  116.     IRenderEngine * pEngine, WCHAR * Filename
  117. #ifdef USE_WMF_CERT
  118.     , int iProfile
  119. #endif
  120.     );
  121.  
  122.  
  123. //
  124. // Main program code
  125. //
  126. int __cdecl main(int argc, char *argv[])
  127. {
  128.     CErrorReporter pLog; // note, must stay in scope while graph is alive
  129.     HRESULT hr = 0;
  130.  
  131.     ++argv; // skip the app name
  132.     --argc;
  133.  
  134.     int Ret = 0;
  135.  
  136.     char **&ppArg = argv;
  137.  
  138.     int i = 1;
  139.     BOOL fNoRender = FALSE;
  140.     BOOL fDynamic = FALSE;
  141.     BOOL fRecomp = FALSE;
  142.     BOOL fWriteIt = FALSE;
  143.     int nWriteArg = -1;
  144.     BOOL fWriteGrf = FALSE;
  145.     int nWriteGrfArg = -1;
  146.     int nInputFileArg = -1;
  147.     BOOL fWriteXtl = FALSE;
  148.     int nWriteXtlArg = -1;
  149.     double RenderStart = -1.0;
  150.     double RenderStop = -1.0;
  151.     BOOL fNoClock = FALSE;
  152. #ifdef USE_WMF_CERT
  153.     int iASFProfile = -1;
  154. #endif
  155.  
  156.     // find which switches we've set. Every time we process a switch,
  157.     // we pull it off the stack
  158.     //
  159.     for( int arg = 0 ; arg < argc ; arg++ )
  160.     {
  161.         if( !ppArg[arg] ) continue;
  162.  
  163.         // found the input .xtl file specified
  164.         //
  165.         if( ppArg[arg][0] != '/' )
  166.         {
  167.             nInputFileArg = arg;
  168.             continue;
  169.         }
  170.  
  171.         if (ppArg[arg][1] == 'N' || ppArg[arg][1] == 'n') {
  172.             fNoRender = TRUE;
  173.             continue;
  174.         }
  175.  
  176.         if (ppArg[arg][1] == 'D' || ppArg[arg][1] == 'd') {
  177.             fDynamic = TRUE;
  178.             continue;
  179.         }
  180.  
  181.         if (ppArg[arg][1] == 'C' || ppArg[arg][1] == 'c') {
  182.             fNoClock = TRUE;
  183.             continue;
  184.         }
  185.  
  186.         if (ppArg[arg][1] == 'R' || ppArg[arg][1] == 'r') {
  187.             fRecomp = TRUE;
  188.             continue;
  189.         }
  190.         if (ppArg[arg][1] == 'W' || ppArg[arg][1] == 'w') {
  191.             fWriteIt = TRUE;
  192.             nWriteArg = arg + 1;
  193.             arg++; // advance beyond the extra arg
  194.             continue;
  195.         }
  196.         if (ppArg[arg][1] == 'G' || ppArg[arg][1] == 'g') {
  197.             fWriteGrf = TRUE;
  198.             nWriteGrfArg = arg + 1;
  199.             arg++; // advance beyond the extra arg
  200.             continue;
  201.         }
  202.         if (ppArg[arg][1] == 'X' || ppArg[arg][1] == 'x') {
  203.             fWriteXtl = TRUE;
  204.             nWriteXtlArg = arg + 1;
  205.             arg++; // advance beyond the extra arg
  206.             continue;
  207.         }
  208.  
  209. #ifdef USE_WMF_CERT        
  210.         if (ppArg[arg][1] == 'P' || ppArg[arg][1] == 'p') {
  211.             arg++;
  212.             if (arg >= argc || (ppArg[arg][0] < '0' || ppArg[arg][0] > '9')) {
  213.                 ListWMSDKProfiles();
  214.                 return -1;
  215.             }
  216.  
  217.             iASFProfile = atoiA(ppArg[arg]);
  218.             printf("Using WMSDK profile #%d\r\n", iASFProfile);
  219.             continue;
  220.         }
  221. #endif // USE_WMF_CERT
  222.         
  223.         if( ppArg[arg][1] == '[' ) {
  224.             // need to pull doubles out of the string
  225.             //
  226.             char * p = &ppArg[arg][2];
  227.             for( unsigned long k = 0 ; k < strlen( p ) ; k++ )
  228.             {
  229.                 if( p[k] == '-' )
  230.                 {
  231.                     break;
  232.                 }
  233.             }
  234.             if( p[k] != '-' )
  235.             {
  236.                 printf( "forgot the '-' between doubles\r\n" );
  237.                 return -1;
  238.             }
  239.             for( unsigned long j = 0 ; j < strlen( p ) ; j++ )
  240.             {
  241.                 if( p[j] == ']' )
  242.                 {
  243.                     break;
  244.                 }
  245.             }
  246.             if( p[j] != ']' )
  247.             {
  248.                 printf( "forgot the ']' \r\n" );
  249.                 return -1;
  250.             }
  251.             
  252.             // set it to zero so atof will work
  253.             //
  254.             p[k] = 0;
  255.             p[j] = 0;
  256.  
  257.             // get the float
  258.             //
  259.             RenderStart = atof( p );
  260.  
  261.             // get the next float
  262.             //
  263.             p = &p[k+1];
  264.  
  265.             RenderStop = atof( p );
  266.             continue;
  267.         }
  268.  
  269.  
  270.         printf("unrecognized switch: %s\n\n", ppArg[arg]);
  271.         nInputFileArg = -1;
  272.         break;
  273.     }
  274.     
  275.     long argucount = 0;
  276.  
  277.     if( argc < 1 || nInputFileArg == -1 ) {
  278.         printf("Usage:     [various switches] input.xtl\r\n");
  279.         printf("           /N  - No preview, just connect it up\r\n");
  280.         printf("           /G output.grf - Output a GRF file\r\n");
  281.         printf("           /X output.xtl - Output an XTL file\r\n");
  282.         printf("           /R  - Connect the graph with smart recompression turned on\r\n");
  283.         printf("           /W <filename> - Render the clip to file. (It may take a while)\r\n" );
  284.         printf("           /D  - Dynamic connections on\r\n");
  285.         printf("           /[double-double] - set the render range start/stop times\r\n" );
  286.         printf("           /C  - No clock. Run as fast as you can\r\n" );
  287. #ifdef USE_WMF_CERT        
  288.         printf("           /P [number] - Choose an ASF compression profile\r\n" );
  289.         printf("           /P without a number - list available profiles\r\n" );
  290. #endif // USE_WMF_CERT
  291.         return -1;
  292.     }
  293.  
  294.     USES_CONVERSION;
  295.     WCHAR *wszFileInput = A2W(ppArg[nInputFileArg]);
  296.  
  297.     CComPtr< IRenderEngine > pRenderEngine;
  298.     CComPtr< IAMTimeline > pTimeline;
  299.     CComPtr< IXml2Dex > pXml;
  300.  
  301.  
  302.     do
  303.     {
  304.         hr = CoInitialize( NULL );
  305.  
  306.         hr = CoCreateInstance( 
  307.             __uuidof(AMTimeline), 
  308.             NULL, 
  309.             CLSCTX_INPROC_SERVER, 
  310.             __uuidof(IAMTimeline), 
  311.             (void**) &pTimeline
  312.             );
  313.  
  314.         if (FAILED(hr)) {
  315.             printf("Failed to create timeline, error = %x\r\n", hr);
  316.             Ret = -1;
  317.             break;
  318.         }
  319.  
  320.         CComQIPtr< IAMSetErrorLog, &IID_IAMSetErrorLog > pTimelineLog( pTimeline );
  321.         if( pTimelineLog )
  322.         {
  323.             pTimelineLog->put_ErrorLog( &pLog );
  324.         }
  325.  
  326.         hr = CoCreateInstance( 
  327.             __uuidof(Xml2Dex), 
  328.             NULL, 
  329.             CLSCTX_INPROC_SERVER, 
  330.             __uuidof(IXml2Dex), 
  331.             (void**) &pXml
  332.             );
  333.     
  334.         if (FAILED(hr)) {
  335.             printf("QEDIT not registered properly\r\n");
  336.             Ret = -1;
  337.             break;
  338.         }
  339.  
  340.         
  341.         hr = pXml->ReadXMLFile(pTimeline, wszFileInput);
  342.         printf("ReadXMLFile('%ls') returned %x\r\n", wszFileInput, hr);
  343.         if (FAILED(hr)) {
  344.             Ret = -1;
  345.             break;
  346.         }
  347.  
  348.  
  349.         // validate sources
  350.         //
  351.         HANDLE WaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  352.  
  353.         long Flags =
  354.             SFN_VALIDATEF_CHECK |
  355.             SFN_VALIDATEF_POPUP | 
  356.             // SFN_VALIDATEF_TELLME |
  357.             SFN_VALIDATEF_REPLACE |
  358.             SFN_VALIDATEF_USELOCAL |
  359.             0;
  360.         
  361.         hr = pTimeline->ValidateSourceNames( Flags, NULL, (LONG_PTR) WaitEvent );
  362.         if( hr == NOERROR )
  363.         {
  364.             WaitForSingleObject( WaitEvent, INFINITE );
  365.         }
  366.         CloseHandle( WaitEvent );
  367.  
  368.         // create a render engine
  369.         //
  370.         if( fRecomp )
  371.         {
  372.             hr = CoCreateInstance( 
  373.                 __uuidof(SmartRenderEngine),
  374.                 NULL,
  375.                 CLSCTX_INPROC_SERVER,
  376.                 __uuidof(IRenderEngine),
  377.                 (void**) &pRenderEngine );
  378.  
  379.             TurnOffPreviewMode( pTimeline );
  380.         
  381. #ifdef USE_WMF_CERT
  382.             // if we're doing smart recompression then the AMTimeline object will 
  383.             // need a way to get our key, so we SetSite on the AMTimeline object here.
  384.             // Note that the pRenderEngine gets the key a little later than this.
  385.             if( SUCCEEDED( hr ) )
  386.             {
  387.                 CComQIPtr< IObjectWithSite, &IID_IObjectWithSite > pOWS( pTimeline );
  388.                 ASSERT( pOWS );
  389.                 if( pOWS )
  390.                 {            
  391.                     pOWS->SetSite((IUnknown *) (IServiceProvider *) &g_prov);
  392.                 }                
  393.             }
  394.  
  395. #endif // USE_WMF_CERT
  396.  
  397.             SCompFmt0 scompFmt;
  398.             ZeroMemory(&scompFmt, sizeof(scompFmt));
  399.             // scompFmt.nFormatId initialized to 0;
  400.             
  401.             // use the compression type of the first input video in
  402.             // the project (note this can change the height/width of
  403.             // the group)
  404.  
  405.             CComPtr<IAMTimelineGroup> pGroup;
  406.             CComPtr<IAMTimelineSrc> pSource;
  407.             hr = GetFirstSourceOnTimeline( pTimeline, MEDIATYPE_Video, &pGroup, &pSource);
  408.  
  409.  
  410. #ifdef USE_WMF_CERT
  411.  
  412.             // smart recompression works differently for ASF than it
  413.             // does for AVI. ASF compression needs to be configured by
  414.             // profile id rather than compressor and format block. We
  415.             // cannot recover the profile used to author an ASF file,
  416.             // so the caller is required to provide us the right
  417.             // profile id. We ask the WMSDK for the media type
  418.             // corresponding to the profile.
  419.             
  420.             WCHAR *wszFileTmp = A2W(ppArg[nWriteArg]);
  421.             if( IsAsfExtension( wszFileTmp ) )
  422.             {
  423.                 AM_MEDIA_TYPE *pmt;
  424.                 hr = GetDestinationASFFormat(
  425.                     &pmt, 
  426.                     iASFProfile);
  427.                 if(SUCCEEDED(hr)) {
  428.                     CopyMediaType(&scompFmt.MediaType, pmt);
  429.                     DeleteMediaType(pmt);
  430.                 }
  431.             }
  432.             else
  433. #endif // USE_WMF_CERT
  434.             {
  435.                 CComBSTR Filename;
  436.                 if(SUCCEEDED(hr)) {
  437.                     hr = pSource->GetMediaName(&Filename);
  438.                 }
  439.                 if(SUCCEEDED(hr)) {
  440.                     hr = GetSourceVideoType(Filename, &scompFmt.MediaType);
  441.                 }
  442.             }
  443.             
  444.             if(SUCCEEDED(hr)) {
  445.                 hr = pGroup->SetSmartRecompressFormat( (long*) &scompFmt );
  446.                 FreeMediaType(scompFmt.MediaType);
  447.             }
  448.         }
  449.         else
  450.         {
  451.             hr = CoCreateInstance( 
  452.                 __uuidof(RenderEngine),
  453.                 NULL,
  454.                 CLSCTX_INPROC_SERVER,
  455.                 __uuidof(IRenderEngine),
  456.                 (void**) &pRenderEngine );
  457.  
  458.         }
  459.         if (FAILED(hr)) {
  460.             printf("Failed to create render engine, error = %x\r\n", hr);
  461.             Ret = -1;
  462.             break;
  463.         }
  464.  
  465. #ifdef USE_WMF_CERT
  466.  
  467.         //
  468.         // give the RenderEngine a key to support ASF
  469.         //
  470.         {
  471.             CComQIPtr< IObjectWithSite, &IID_IObjectWithSite > pOWS( pRenderEngine );
  472.             ASSERT( pOWS );
  473.             if( pOWS )
  474.             {        
  475.                 pOWS->SetSite((IUnknown *) (IServiceProvider *) &g_prov);
  476.             }            
  477.         }
  478. #endif // USE_WMF_CERT
  479.  
  480.         long gRenderMedLocFlags = 0 |
  481.             //        SFN_VALIDATEF_POPUP | 
  482.             //        SFN_VALIDATEF_TELLME |
  483.             //        SFN_VALIDATEF_VERBOSE | 
  484.             //        SFN_VALIDATEF_USELOCAL |
  485.             0;
  486.         
  487.         pRenderEngine->SetSourceNameValidation( NULL, NULL, gRenderMedLocFlags );
  488.  
  489.         // set it's timeline
  490.         //
  491.         hr = pRenderEngine->SetTimelineObject( pTimeline );
  492.         if (FAILED(hr)) {
  493.             printf("Failed to set timeline object, error = %x\r\n", hr);
  494.             Ret = -1;
  495.             break;
  496.         }
  497.  
  498.         // set dynamicness
  499.         //
  500.         if (fDynamic) {
  501.             pRenderEngine->SetDynamicReconnectLevel(CONNECTF_DYNAMIC_SOURCES);
  502.             printf("DYNAMIC ON\r\n");
  503.         } else {
  504.             pRenderEngine->SetDynamicReconnectLevel(CONNECTF_DYNAMIC_NONE);
  505.             printf("DYNAMIC OFF\r\n");
  506.         }
  507.  
  508.         // set the renderrange, if there is one
  509.         //
  510.         if( RenderStart != -1.0 && RenderStop != -1.0 )
  511.         {
  512.             pRenderEngine->SetRenderRange2( RenderStart, RenderStop );
  513.         }
  514.  
  515.         
  516.        
  517.         // connect up first half
  518.         //
  519.         hr = pRenderEngine->ConnectFrontEnd( );
  520.  
  521.         if( FAILED( hr ) )
  522.         {
  523.             printf("ConnectFrontEnd returned bomb code of %x\r\n", hr);
  524.             Ret = -1;
  525.             break;
  526.         }
  527.  
  528.  
  529.  
  530.         // get this now, because other calls will need it
  531.         //
  532.         CComPtr< IGraphBuilder > pGraph;
  533.         hr = pRenderEngine->GetFilterGraph( &pGraph );
  534.  
  535.         if (FAILED(hr)) {
  536.             printf("Couldn't get graph!  hr = %x", hr);
  537.             break;
  538.         }
  539.  
  540.         // if we didn't want to write the file to disk, may as well render it
  541.         //
  542.         if( !fWriteIt )
  543.         {
  544.             hr = pRenderEngine->RenderOutputPins( );
  545.  
  546.  
  547.             if (FAILED(hr)) 
  548.             {
  549.                 printf("RenderOutputPins returned bomb code of %x\r\n", hr);
  550.                 Ret = -1;
  551.                 break;
  552.             }
  553.  
  554.             if( fNoClock )
  555.             {
  556.                 CComQIPtr< IMediaFilter, &IID_IMediaFilter > pMFGraph( pGraph );
  557.                 if( pMFGraph )
  558.                 {
  559.                     pMFGraph->SetSyncSource( NULL );
  560.                 }
  561.             }
  562.         }
  563.         else
  564.         {
  565.             TurnOffPreviewMode( pTimeline );
  566.             WCHAR *wszFileTmp = A2W(ppArg[nWriteArg]);
  567.  
  568.             hr = ConnectOutputFile(pRenderEngine, wszFileTmp
  569. #ifdef USE_WMF_CERT
  570.                                    , iASFProfile
  571. #endif
  572.                                    );
  573.                                    
  574.             printf( "ConnectOutputFile returned %x\r\n", hr );
  575.             if( FAILED( hr ) )
  576.             {
  577.                 fNoRender = TRUE;
  578.             }
  579.         }
  580.  
  581.         // write out GRF files
  582.         //
  583.         if( fWriteGrf )
  584.         {
  585.             WCHAR *wszFileTmp = A2W(ppArg[nWriteGrfArg]);
  586.             hr = pXml->WriteGrfFile(pGraph, wszFileTmp);
  587.             printf("WriteGrfFile('%ls') returned %x\r\n", wszFileTmp, hr);
  588.         }
  589.         if( fWriteXtl )
  590.         {
  591.             WCHAR *wszFileTmp = A2W(ppArg[nWriteXtlArg]);
  592.             hr = pXml->WriteXMLFile(pTimeline, wszFileTmp);
  593.             printf("WriteXtlFile('%ls') returned %x\r\n", wszFileTmp, hr);
  594.         }
  595.  
  596.         if (!fNoRender) {
  597.             CComQIPtr< IMediaEvent, &IID_IMediaEvent > pEvent( pGraph );
  598.             CComQIPtr< IMediaControl, &IID_IMediaControl > pControl( pGraph );
  599.             hr = pControl->Run( );
  600.             if (FAILED(hr)) {
  601.                 printf("Failed to run the graph, error = %x\r\n", hr);
  602.                 Ret = -1;
  603.                 break;
  604.             }
  605.  
  606.  
  607.             HANDLE hEvent;
  608.  
  609.             if( !pEvent ) {
  610.                 // unexpected error
  611.                 Ret = -1;
  612.             }
  613.  
  614.             hr = pEvent->GetEventHandle((OAEVENT *)&hEvent);
  615.             if(FAILED(hr)) {
  616.                 // unexpected error
  617.                 Ret = -1;
  618.             }
  619.  
  620.             // wait for completion and dispatch messages for any windows
  621.             // created on our thread.
  622.             for(;;)
  623.             {
  624.                 while(MsgWaitForMultipleObjects(
  625.                     1,
  626.                     &hEvent,
  627.                     FALSE,
  628.                     INFINITE,
  629.                     QS_ALLINPUT) != WAIT_OBJECT_0)
  630.                 {
  631.                     MSG Message;
  632.  
  633.                     while (PeekMessage(&Message, NULL, 0, 0, TRUE))
  634.                     {
  635.                         TranslateMessage(&Message);
  636.                         DispatchMessage(&Message);
  637.                     }
  638.                 }
  639.  
  640.                 // event signaled. see if we're done.
  641.  
  642.                 LONG levCode;
  643.                 LONG_PTR lp1, lp2;
  644.  
  645.                 if(pEvent->GetEvent(&levCode, &lp1, &lp2, 0) == S_OK)
  646.                 {
  647.                     EXECUTE_ASSERT(SUCCEEDED(
  648.                         pEvent->FreeEventParams(levCode, lp1, lp2)));
  649.                 
  650.                     if(levCode == EC_COMPLETE || levCode == EC_ERRORABORT ||
  651.                        levCode == EC_USERABORT)
  652.                     {
  653.                         break;
  654.                     }
  655.                 }
  656.             }
  657.             
  658.             hr = pControl->Stop( );
  659.  
  660.             
  661.         }
  662.     } while(0); 
  663.  
  664.     pRenderEngine.Release( );
  665.     pXml.Release( );
  666.     if (pTimeline)
  667.     {
  668.         hr = pTimeline->ClearAllGroups();
  669.         pTimeline.Release( );
  670.     }
  671.  
  672.     CoUninitialize( );
  673.  
  674.     
  675.     return Ret;
  676. }
  677.  
  678. //
  679. // helper function to traverse a timline and return the first source
  680. // 
  681.  
  682. HRESULT GetFirstSourceOnTimeline(
  683.     IAMTimeline *pTimeline, GUID MajorType,
  684.     IAMTimelineGroup ** ppGroup, IAMTimelineSrc ** ppSource )
  685. {
  686.     *ppGroup = 0;
  687.     *ppSource = 0;
  688.     
  689.     for( long g = 0 ;; g++ )
  690.     {
  691.         // locate group of right media type (audio / video)
  692.         CComPtr< IAMTimelineObj > pGroupObj;
  693.         HRESULT hr = pTimeline->GetGroup( &pGroupObj, g );
  694.         if(FAILED(hr)) {
  695.             break;
  696.         }
  697.         CComQIPtr< IAMTimelineGroup, &IID_IAMTimelineGroup > pGroup( pGroupObj );
  698.  
  699.         CMediaType GroupType;
  700.         pGroup->GetMediaType( &GroupType );
  701.         if( GroupType.majortype != MajorType ) {
  702.             continue;
  703.         }
  704.  
  705.         // found the right group, go through each track in it
  706.  
  707.         long TrackCount = 0;
  708.         long Layers = 0;
  709.         pTimeline->GetCountOfType( g, &TrackCount, &Layers, TIMELINE_MAJOR_TYPE_TRACK );
  710.     
  711.         if( TrackCount < 1 )
  712.         {
  713.             continue;
  714.         }
  715.  
  716.         CComQIPtr< IAMTimelineComp, &IID_IAMTimelineComp > pGroupComp( pGroupObj );
  717.  
  718.         for( int CurrentLayer = 0 ; CurrentLayer < Layers ; CurrentLayer++ )
  719.         {
  720.             // get the layer itself
  721.             //
  722.             CComPtr< IAMTimelineObj > pLayer;
  723.             hr = pGroupComp->GetRecursiveLayerOfType( &pLayer, CurrentLayer, TIMELINE_MAJOR_TYPE_TRACK );
  724.  
  725.             // ask if the layer is muted
  726.             //
  727.             BOOL LayerMuted = FALSE;
  728.             pLayer->GetMuted( &LayerMuted );
  729.             if( LayerMuted )
  730.             {
  731.                 // don't look at this layer
  732.                 //
  733.                 continue; // skip this layer, don't worry about grid
  734.             }
  735.  
  736.             CComQIPtr< IAMTimelineTrack, &IID_IAMTimelineTrack > pTrack( pLayer );
  737.             if( !pTrack )
  738.             {
  739.                 continue;
  740.             }
  741.  
  742.             REFERENCE_TIME InOut = 0;
  743.             while( 1 )
  744.             {
  745.                 // get the next source on this layer, given a time.
  746.                 //
  747.                 CComPtr< IAMTimelineObj > pSourceObj;
  748.                 hr = pTrack->GetNextSrc( &pSourceObj, &InOut );
  749.                 ASSERT( !FAILED( hr ) );
  750.                 if( hr != NOERROR )
  751.                 {
  752.                     // all done with sources
  753.                     //
  754.                     break;
  755.                 }
  756.  
  757.                 CComQIPtr< IAMTimelineSrc, &IID_IAMTimelineSrc > pSource( pSourceObj );
  758.                 ASSERT( pSource );
  759.                 if( !pSource )
  760.                 {
  761.                     // this one failed, so look at the next
  762.                     //
  763.                     continue; // sources
  764.                 }
  765.  
  766.                 // ask if the source is muted
  767.                 //
  768.                 BOOL SourceMuted = FALSE;
  769.                 pSourceObj->GetMuted( &SourceMuted );
  770.                 if( SourceMuted )
  771.                 {
  772.                     // don't look at this source
  773.                     //
  774.                     continue; // sources
  775.                 }
  776.  
  777.                 *ppSource = pSource;
  778.                 pSource.p->AddRef();
  779.                 *ppGroup = pGroup;
  780.                 pGroup.p->AddRef();
  781.  
  782.                 return S_OK;
  783.  
  784.             } // while sources
  785.  
  786.  
  787.         } // while currentlayer
  788.  
  789.     } // for all groups
  790.  
  791.     return VFW_E_NOT_FOUND;
  792. }
  793.  
  794. void TurnOffPreviewMode( IAMTimeline * pTimeline )
  795. {
  796.     long Groups = 0;
  797.     pTimeline->GetGroupCount( &Groups );
  798.     for( int i = 0 ; i < Groups ; i++ )
  799.     {
  800.         CComPtr< IAMTimelineObj > pGroupObj;
  801.         pTimeline->GetGroup( &pGroupObj, i );
  802.         CComQIPtr< IAMTimelineGroup, &IID_IAMTimelineGroup > pGroup( pGroupObj );
  803.         pGroup->SetPreviewMode( FALSE );
  804.     }
  805. }
  806.  
  807. //
  808. // uses the media detector to retrieve mediatype of a clip
  809. // 
  810. HRESULT GetSourceVideoType(WCHAR *wszFilename, AM_MEDIA_TYPE *pmt)
  811. {
  812.     CComPtr< IMediaDet > pDet;
  813.     HRESULT hr = CoCreateInstance( CLSID_MediaDet,
  814.                            NULL,
  815.                            CLSCTX_INPROC_SERVER,
  816.                            IID_IMediaDet,
  817.                            (void**) &pDet );
  818.     if( FAILED( hr ) ) {
  819.         return hr;
  820.     }
  821.  
  822. #ifdef USE_WMF_CERT
  823.  
  824.     //
  825.     // set the site provider on the MediaDet object to allowed keyed apps
  826.     // to use ASF decoder
  827.     //
  828.     CComQIPtr< IObjectWithSite, &IID_IObjectWithSite > pOWS( pDet );
  829.     if( pOWS )
  830.     {
  831.         pOWS->SetSite( (IServiceProvider *) &g_prov );
  832.     }
  833.  
  834. #endif // USE_WMF_CERT
  835.  
  836.     hr = pDet->put_Filename( wszFilename );
  837.     if( FAILED( hr ) )
  838.     {
  839.         return hr;
  840.     }
  841.  
  842.     // go through and find the video stream type
  843.     //
  844.     long Streams = 0;
  845.     long VideoStream = -1;
  846.     hr = pDet->get_OutputStreams( &Streams );
  847.     for( int i = 0 ; i < Streams ; i++ )
  848.     {
  849.         pDet->put_CurrentStream( i );
  850.         GUID Major = GUID_NULL;
  851.         pDet->get_StreamType( &Major );
  852.         if( Major == MEDIATYPE_Video )
  853.         {
  854.             VideoStream = i;
  855.             break;
  856.         }
  857.     }
  858.     if( VideoStream == -1 )
  859.     {
  860.         return VFW_E_INVALIDMEDIATYPE;
  861.     }
  862.  
  863.     hr = pDet->get_StreamMediaType( pmt );
  864.     return hr;
  865. }
  866.  
  867.  
  868. #ifdef USE_WMF_CERT
  869.  
  870. // ------------------------------------------------------------------------
  871. // CKeyProvider methods
  872. // 
  873.  
  874. HRESULT CKeyProvider::QueryInterface(REFIID riid, void ** ppv)
  875. {
  876.     if (riid == IID_IServiceProvider || riid == IID_IUnknown) {
  877.         *ppv = (void *) static_cast<IServiceProvider *>(this);
  878.         return NOERROR;
  879.     }    
  880.     return E_NOINTERFACE;
  881. }
  882.  
  883.  
  884. STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void **ppv)
  885. {
  886.     if (siid == __uuidof(IWMReader) && riid == IID_IUnknown) {
  887.     
  888.         IUnknown *punkCert;
  889.  
  890.         HRESULT hr = WMCreateCertificate( &punkCert );
  891.         if (SUCCEEDED(hr)) {
  892.             *ppv = (void *) punkCert;
  893.         }
  894.         return hr;
  895.     }
  896.     return E_NOINTERFACE;
  897. }
  898.  
  899. #endif // USE_WMF_CERT
  900.  
  901. // ------------------------------------------------------------------------
  902. // CErrorReporter methods
  903. // 
  904.  
  905. STDMETHODIMP CErrorReporter::LogError( long Severity, BSTR ErrorString, LONG ErrorCode, HRESULT hresult, VARIANT * pExtraInfo )
  906. {
  907.     USES_CONVERSION;
  908.     printf( "Error %d (HRESULT %x)\r\n", ErrorCode, hresult);
  909.     char * t = W2A( ErrorString );
  910.     printf( t );
  911.     printf( "\r\n" );
  912.  
  913. #ifdef DEBUG
  914.     OutputDebugStringA( t );
  915.     OutputDebugString( TEXT("\r\n") );
  916. #endif // DEBUG
  917.  
  918.     // look at variant
  919.     //
  920.     if( pExtraInfo )
  921.     {
  922.         if( pExtraInfo->vt == VT_BSTR )
  923.         {
  924.             printf( "Extra Info:%ls\r\n", pExtraInfo->bstrVal);
  925.         } else if( pExtraInfo->vt == VT_I4 ) {
  926.             printf( "Extra Info: %d\r\n", (int)pExtraInfo->lVal );
  927.         } else if( pExtraInfo->vt == VT_R8 ) {
  928.             printf( "Extra Info: %d/100\r\n",
  929.                     (int)(V_R8(pExtraInfo) * 100));
  930.         }
  931.     }
  932.     return hresult;
  933. }
  934.  
  935. #ifdef USE_WMF_CERT
  936.  
  937. // list formats Windows Media Format SDK supports.
  938. // 
  939. void ListWMSDKProfiles()
  940. {
  941.     USES_CONVERSION;
  942.     
  943.     int wextent = 0 ;
  944.     int Loop = 0 ;
  945.     SIZE extent ;
  946.     DWORD cProfiles = 0 ;
  947.  
  948.     printf("Standard system profiles:\n");
  949.     
  950.     CComPtr <IWMProfileManager> pIWMProfileManager;
  951.  
  952.     HRESULT hr = WMCreateProfileManager( &pIWMProfileManager );
  953.     if( FAILED( hr ) ) {   
  954.         return; // error
  955.     }        
  956.  
  957.     IWMProfileManager2* pIPM2;
  958.     hr = pIWMProfileManager->QueryInterface( IID_IWMProfileManager2,
  959.                                              ( void ** )&pIPM2 );
  960.     if(FAILED(hr)) {
  961.         return;
  962.     }
  963.     // we only use 7_0 profiles
  964.     hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
  965.     pIPM2->Release();
  966.     
  967.     if(FAILED(hr)) {
  968.         return;
  969.     }
  970.         
  971.     hr = pIWMProfileManager->GetSystemProfileCount(  &cProfiles );
  972.     if( FAILED( hr ) )
  973.     {
  974.         return;
  975.     }
  976.         
  977.     //    
  978.     // now load the profile strings
  979.     //    
  980.     LRESULT ix;
  981.     DWORD cchName, cchDescription;
  982.     for (int i = 0; i < (int)cProfiles; ++i) {
  983.         CComPtr <IWMProfile> pIWMProfile;
  984.         
  985.         hr = pIWMProfileManager->LoadSystemProfile( i, &pIWMProfile );
  986.         if( FAILED( hr ) )
  987.             return;
  988.             
  989.         hr = pIWMProfile->GetName( NULL, &cchName );
  990.         if( FAILED( hr ) )
  991.             return;
  992.             
  993.         WCHAR *wszProfile = new WCHAR[ cchName ];
  994.         if( NULL == wszProfile )
  995.             return;
  996.             
  997.         hr = pIWMProfile->GetName( wszProfile, &cchName );
  998.         if( FAILED( hr ) )
  999.             return;
  1000.         
  1001.         hr = pIWMProfile->GetDescription( NULL, &cchDescription );
  1002.         if( FAILED( hr ) )
  1003.             return;
  1004.             
  1005.         WCHAR *wszDescription = new WCHAR[ cchDescription ];
  1006.         if( NULL == wszDescription )
  1007.             return;
  1008.             
  1009.         
  1010.         hr = pIWMProfile->GetDescription( wszDescription, &cchDescription );
  1011.         if( FAILED( hr ) )
  1012.             return;
  1013.         
  1014.  
  1015.         printf("  %3d:  %ls\n", i, wszProfile);
  1016.         
  1017.         delete[] wszProfile;
  1018.         delete[] wszDescription;
  1019.     }
  1020.  
  1021.     printf("\r\n Use /p [#] to choose the profile you want\r\n"); 
  1022. }
  1023. #endif // USE_WMF_CERT
  1024.  
  1025. // 
  1026. // helper function to return Nth input pin or output pin on a
  1027. // filter. pin is addref'd
  1028. // 
  1029. IPin * GetPin( IBaseFilter * pFilter, int PinNum, PIN_DIRECTION pd )
  1030. {
  1031.     CComPtr<IEnumPins> pEnum;
  1032.     HRESULT hr = pFilter->EnumPins( &pEnum );
  1033.     if(SUCCEEDED(hr))
  1034.     {
  1035.         ULONG cFetched;
  1036.         IPin * pPin;
  1037.         while(pEnum->Next( 1, &pPin, &cFetched) == S_OK)
  1038.         {
  1039.             PIN_DIRECTION pd2;
  1040.             pPin->QueryDirection( &pd2 );
  1041.             if( pd2 == pd )
  1042.             {
  1043.                 if( PinNum == 0 )
  1044.                 {
  1045.                     // return addref'd pin
  1046.                     return pPin;
  1047.                 }
  1048.                 PinNum--;
  1049.             }
  1050.  
  1051.             pPin->Release();
  1052.         }
  1053.     }
  1054.  
  1055.     return NULL;
  1056. }
  1057.  
  1058. //
  1059. // Configure the graph to write to an AVI file (or ASF or .WAV)
  1060. //
  1061.  
  1062. HRESULT ConnectOutputFile(
  1063.     IRenderEngine * pEngine, WCHAR * Filename
  1064. #ifdef USE_WMF_CERT
  1065.     , int iProfile
  1066. #endif
  1067.     )
  1068. {
  1069.     CComPtr< ICaptureGraphBuilder2 > pBuilder;
  1070.     HRESULT hr = CoCreateInstance(
  1071.         CLSID_CaptureGraphBuilder2,
  1072.         NULL,
  1073.         CLSCTX_INPROC_SERVER,
  1074.         IID_ICaptureGraphBuilder2,
  1075.         (void**) &pBuilder );
  1076.     if( FAILED( hr ) )
  1077.     {
  1078.         return hr;
  1079.     }
  1080.  
  1081.     CComPtr< IAMTimeline > pTimeline;
  1082.     hr = pEngine->GetTimelineObject( &pTimeline );
  1083.     if( FAILED( hr ) )
  1084.     {
  1085.         return hr;
  1086.     }
  1087.  
  1088.     CComPtr< IGraphBuilder > pGraph;
  1089.     hr = pEngine->GetFilterGraph( &pGraph );
  1090.     if( FAILED( hr ) )
  1091.     {
  1092.         return hr;
  1093.     }
  1094.  
  1095.     long Groups = 0;
  1096.     pTimeline->GetGroupCount( &Groups );
  1097.     if( !Groups )
  1098.     {
  1099.         return E_INVALIDARG;
  1100.     }
  1101.  
  1102.     CComPtr< IBaseFilter > pMux;
  1103.     CComPtr< IFileSinkFilter > pWriter;
  1104.  
  1105.     hr = pBuilder->SetFiltergraph( pGraph );
  1106.     if( FAILED( hr ) )
  1107.     {
  1108.         return hr;
  1109.     }
  1110.  
  1111.  
  1112.     bool fConnectManually = false;
  1113.     GUID guid = MEDIASUBTYPE_Avi;
  1114.  
  1115.     // determine which writer to use based on file extension
  1116.     if (lstrlenW(Filename) > 4)
  1117.     {
  1118.         WCHAR *pExt = Filename + lstrlenW(Filename) - 3;
  1119.  
  1120. #ifdef USE_WMF_CERT
  1121.         if(IsAsfExtension(pExt))
  1122.         {
  1123.             guid =  CLSID_WMAsfWriter;
  1124.         }
  1125. #endif // USE_WMF_CERT
  1126.         if (lstrcmpiW(pExt, L"wav") == 0)
  1127.         {
  1128.             fConnectManually = true;
  1129.             
  1130.             // creation of the wav writer filter SDK sample
  1131.             //
  1132.             // .wav files need to be special-cased here because the
  1133.             // capture graph builder doesn't know about the wav writer
  1134.             // filter.
  1135.             // 
  1136.             // {3C78B8E2-6C4D-11d1-ADE2-0000F8754B99}
  1137.             const CLSID CLSID_WavDest = {
  1138.                 0x3C78B8E2,0x6C4D,0x11D1,{0xAD,0xE2,0x00,0x00,0xF8,0x75,0x4B,0x99}
  1139.             };
  1140.  
  1141.             hr = CoCreateInstance(
  1142.                 CLSID_WavDest,
  1143.                 NULL,
  1144.                 CLSCTX_INPROC_SERVER,
  1145.                 IID_IBaseFilter,
  1146.                 (void**) &pMux );
  1147.             if( SUCCEEDED( hr ) )
  1148.             {
  1149.                 hr = pGraph->AddFilter( pMux, L"Wave Mux" );
  1150.             }
  1151.  
  1152.             if( SUCCEEDED( hr ) )
  1153.             {
  1154.                 hr = CoCreateInstance(
  1155.                     CLSID_FileWriter,
  1156.                     NULL,
  1157.                     CLSCTX_INPROC_SERVER,
  1158.                     IID_IFileSinkFilter,
  1159.                     (void**) &pWriter );
  1160.             }
  1161.             if( SUCCEEDED( hr ) )
  1162.             {
  1163.                 hr = pWriter->SetFileName( Filename, NULL );
  1164.             }
  1165.             if( SUCCEEDED( hr ) )
  1166.             {
  1167.                 CComQIPtr< IBaseFilter, &IID_IBaseFilter > pWriterBase( pWriter );
  1168.                 hr = pGraph->AddFilter( pWriterBase, L"Writer" );
  1169.             }
  1170.         }
  1171.     }
  1172.  
  1173.     if(FAILED(hr)) {
  1174.         return hr;
  1175.     }
  1176.  
  1177.     if(!fConnectManually)
  1178.     {
  1179.         hr = pBuilder->SetOutputFileName(
  1180.             &guid, Filename, &pMux, &pWriter );
  1181.     }
  1182.     if( FAILED( hr ) )
  1183.     {
  1184.         return hr;
  1185.     }
  1186.  
  1187.     CComQIPtr<IConfigInterleaving, &IID_IConfigInterleaving> pConfigInterleaving(pMux);
  1188.     if(pConfigInterleaving) {
  1189.         pConfigInterleaving->put_Mode(INTERLEAVE_FULL);
  1190.     }
  1191.     CComQIPtr<IFileSinkFilter2, &IID_IFileSinkFilter2> pCfgFw(pWriter);
  1192.     if(pCfgFw) {
  1193.         pCfgFw->SetMode(AM_FILE_OVERWRITE);
  1194.     }
  1195.      
  1196. #ifdef USE_WMF_CERT
  1197.     CComQIPtr<IConfigAsfWriter, &IID_IConfigAsfWriter> pConfigAsfWriter(pMux);
  1198.     if(pConfigAsfWriter && iProfile >= 0)
  1199.     {
  1200.         CComPtr<IWMProfile> pProfile;
  1201.         hr = MapProfileIdToProfile(iProfile, &pProfile);
  1202.         if(FAILED(hr)) {
  1203.             return hr;
  1204.         }
  1205.  
  1206.         // note that the ASF writer will not run if the number of streams
  1207.         // does not match the profile.
  1208.         hr = pConfigAsfWriter->ConfigureFilterUsingProfile(pProfile);
  1209.         if(FAILED(hr)) {
  1210.             return hr;
  1211.         }
  1212.     }
  1213. #endif
  1214.  
  1215.     for( int g = 0 ; g < Groups ; g++ )
  1216.     {
  1217.         CComPtr< IPin > pPin;
  1218.         hr = pEngine->GetGroupOutputPin( g, &pPin );
  1219.         if( FAILED( hr ) )
  1220.         {
  1221.             return hr;
  1222.         }
  1223.  
  1224.         // connect pin to the mux
  1225.         //
  1226.         hr = pBuilder->RenderStream( NULL, NULL, pPin, NULL, pMux );
  1227.         if( FAILED( hr ) )
  1228.         {
  1229.             return hr;
  1230.         }
  1231.     }
  1232.  
  1233.     if( fConnectManually )
  1234.     {
  1235.         // connect the mux to the writer. the wav mux refuses to
  1236.         // connect its output pin until its input pin is
  1237.         // connected. Otherwise this could be done earlier.
  1238.         //
  1239.         CComQIPtr< IBaseFilter, &IID_IBaseFilter > pWriterBase( pWriter );
  1240.         CComPtr<IPin> pMuxOut, pWriterIn;
  1241.         pMuxOut.p = GetPin( pMux, 0, PINDIR_OUTPUT );
  1242.         pWriterIn.p = GetPin( pWriterBase, 0, PINDIR_INPUT );
  1243.         if(!pMuxOut || !pWriterIn) {
  1244.             return E_UNEXPECTED;
  1245.         }
  1246.         hr = pGraph->Connect( pMuxOut, pWriterIn );
  1247.     }
  1248.  
  1249.     return hr;
  1250. }
  1251.  
  1252. BOOL IsAsfExtension( WCHAR *Filename )
  1253. {
  1254.     if (lstrlenW(Filename) >= 3)
  1255.     {
  1256.         WCHAR *pExt = Filename + lstrlenW(Filename) - 3;
  1257.  
  1258.         if(lstrcmpiW(pExt, L"asf") == 0 ||
  1259.            lstrcmpiW(pExt, L"wma") == 0 ||
  1260.            lstrcmpiW(pExt, L"wmv") == 0)
  1261.         {
  1262.             return TRUE;
  1263.         }
  1264.     }
  1265.     return FALSE;
  1266. }
  1267.  
  1268. //
  1269. // Get the mediatype for a particular ASF profile. it does this using
  1270. // the DirectShow components that use the WMSDK rather than through
  1271. // the WMSDK directly.
  1272. //
  1273.  
  1274. #ifdef USE_WMF_CERT
  1275.  
  1276. HRESULT GetDestinationASFFormat(
  1277.     AM_MEDIA_TYPE **ppmt,
  1278.     int iProfile
  1279.     )
  1280. {
  1281.     *ppmt = 0;
  1282.     
  1283.     CComPtr< IConfigAsfWriter > pWriter;
  1284.     HRESULT hr = CoCreateInstance(
  1285.         CLSID_WMAsfWriter,
  1286.         NULL,
  1287.         CLSCTX_INPROC_SERVER,
  1288.         IID_IConfigAsfWriter,
  1289.         (void **)&pWriter);
  1290.     if(FAILED(hr)) {
  1291.         return hr;
  1292.     }
  1293.  
  1294.     CComQIPtr<IBaseFilter,&IID_IBaseFilter> pwf(pWriter);
  1295.     if(!pWriter) {
  1296.         return E_UNEXPECTED;
  1297.     }
  1298.  
  1299.     // we have to add the ASF writer to a dummy graph in order for the
  1300.     // calls to work.
  1301.     CComPtr< IGraphBuilder > pBuilder;
  1302.     hr = CoCreateInstance(
  1303.         CLSID_FilterGraph,
  1304.         NULL,
  1305.         CLSCTX_INPROC_SERVER,
  1306.         IID_IGraphBuilder,
  1307.         (void**) &pBuilder );
  1308.     if( FAILED( hr ) )
  1309.     {
  1310.         return hr;
  1311.     }
  1312.  
  1313.     //
  1314.     // give the graph a key to support ASF
  1315.     //
  1316.     {
  1317.         CComQIPtr< IObjectWithSite, &IID_IObjectWithSite > pOWS( pBuilder );
  1318.         ASSERT( pOWS );
  1319.         if( pOWS )
  1320.         {        
  1321.             pOWS->SetSite((IUnknown *) (IServiceProvider *) &g_prov);
  1322.         }            
  1323.     }
  1324.  
  1325.     hr = pBuilder->AddFilter(pwf, 0);
  1326.     if(FAILED(hr)) {
  1327.         return hr;
  1328.     }
  1329.  
  1330.     // we use profile id -1 to indicate no profile was set.
  1331.     if (iProfile >= 0)
  1332.     {
  1333.         CComPtr<IWMProfile> pProfile;
  1334.         hr = MapProfileIdToProfile(iProfile, &pProfile);
  1335.         if(FAILED(hr)) {
  1336.             return hr;
  1337.         }
  1338.         hr = pWriter->ConfigureFilterUsingProfile(pProfile);
  1339.         if(FAILED(hr)) {
  1340.             return hr;
  1341.         }
  1342.     }
  1343.  
  1344.     CComPtr<IEnumPins> pEnumPins;
  1345.     hr = pwf->EnumPins( &pEnumPins );
  1346.     if(FAILED(hr)) {
  1347.         return hr;
  1348.     }
  1349.     
  1350.     // get destination video format from ASF writer using IAMStreamConfig::GetFormat on
  1351.     // its input pins
  1352.     int iPins = 0;
  1353.     ULONG ul = 0;
  1354.     CComPtr < IPin > pWriterInputPin; // we only expect to find input pins
  1355.     while( S_OK == pEnumPins->Next( 1, &pWriterInputPin, &ul ) )
  1356.     {
  1357. #ifdef DEBUG
  1358.         {
  1359.             PIN_DIRECTION pd;
  1360.             pWriterInputPin->QueryDirection( &pd );
  1361.             ASSERT( PINDIR_OUTPUT != pd );
  1362.         }
  1363. #endif
  1364.         CComQIPtr <IAMStreamConfig, &IID_IAMStreamConfig> pStreamConfig( pWriterInputPin);
  1365.         if( !pStreamConfig ) {
  1366.             return E_UNEXPECTED;
  1367.         }
  1368.         pWriterInputPin.Release();
  1369.  
  1370.         AM_MEDIA_TYPE *pmt2;
  1371.         hr = pStreamConfig->GetFormat( &pmt2 );
  1372.         if( SUCCEEDED( hr ) )
  1373.         {
  1374.             if(pmt2->majortype != MEDIATYPE_Video) {
  1375.                 DeleteMediaType(pmt2);
  1376.                 continue;
  1377.             }
  1378.             *ppmt = pmt2; // caller needs to delete
  1379.             return S_OK;
  1380.         }
  1381.     }
  1382.  
  1383.     return E_FAIL;
  1384. }
  1385.  
  1386.  
  1387. HRESULT MapProfileIdToProfile(
  1388.     int iProfile, IWMProfile **ppProfile)
  1389. {
  1390.     *ppProfile = 0;
  1391.     
  1392.     CComPtr <IWMProfileManager> pIWMProfileManager;
  1393.     HRESULT hr = WMCreateProfileManager( &pIWMProfileManager );
  1394.     if(FAILED(hr)) {
  1395.         return hr;
  1396.     }
  1397.  
  1398.     // we only use 7_0 profiles
  1399.     CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);
  1400.     if(!pIWMProfileManager) {
  1401.         return E_UNEXPECTED;
  1402.     }
  1403.     hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
  1404.     if(FAILED(hr)) {
  1405.         return hr;
  1406.     }
  1407.  
  1408.     DWORD cProfiles;
  1409.     hr = pIWMProfileManager->GetSystemProfileCount(  &cProfiles );
  1410.     if(FAILED(hr)) {
  1411.         return hr;
  1412.     }
  1413.     if( (DWORD)iProfile >= cProfiles ) {
  1414.         printf("Invalid profile: %d\n", iProfile);
  1415.         return E_INVALIDARG;
  1416.     }
  1417.  
  1418.     return pIWMProfileManager->LoadSystemProfile( iProfile, ppProfile );
  1419. }
  1420.  
  1421. #endif // USE_WMF_CERT
  1422.