home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Misc / ASFCopy / asfcopy.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  18.8 KB  |  739 lines

  1. //------------------------------------------------------------------------------
  2. // File: ASFCopy.cpp
  3. //
  4. // Desc: DirectShow sample code - ASF copy.
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9.  
  10. #include <streams.h>
  11.  
  12. // Disable warning C4268, which is generated within <wmsdk.h>
  13. #pragma warning(disable:4268)
  14. #include <wmsdk.h>
  15. #pragma warning(default:4268)
  16.  
  17. #include <atlbase.h>
  18. #include <atlimpl.cpp>
  19. #include <stdio.h>
  20.  
  21. #include <dshowasf.h>
  22.  
  23. //
  24. // Build warning to remind developers of the dependency on the 
  25. // Windows Media Format SDK libraries, which do not ship with
  26. // the DirectX SDK.
  27. //
  28. #pragma message("NOTE: To link and run this sample, you must install the Windows Media Format SDK.")
  29. #pragma message("After signing a license agreement with Microsoft, you will receive a")
  30. #pragma message("unique version of WMStub.LIB, which should be added to this VC++ project.")
  31. #pragma message("Without this library, you will receive linker errors for the following:")
  32. #pragma message("       WMCreateCertificate")
  33. #pragma message("You must also add WMVCore.LIB to the linker settings to resolve the following:")
  34. #pragma message("       WMCreateProfileManager")
  35.  
  36. // Global data
  37. BOOL fVerbose = FALSE;
  38.  
  39. // Function prototypes
  40. HRESULT MapProfileIdToProfile(int iProfile, IWMProfile **ppProfile);
  41.  
  42.  
  43.  
  44. class CKeyProvider : public IServiceProvider
  45. {
  46.     public:
  47.         //
  48.         // IUnknown interface
  49.         //
  50.         STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
  51.         STDMETHODIMP_(ULONG) AddRef();
  52.         STDMETHODIMP_(ULONG) Release();
  53.  
  54.         CKeyProvider();
  55.  
  56.         // IServiceProvider
  57.         STDMETHODIMP QueryService(REFIID siid, REFIID riid, void **ppv);
  58.  
  59.     private:
  60.         ULONG m_cRef;
  61. };
  62.  
  63. CKeyProvider::CKeyProvider() : m_cRef(0)
  64. {
  65. }
  66.  
  67. //////////////////////////////////////////////////////////////////////////
  68. //
  69. // IUnknown methods
  70. //
  71. //////////////////////////////////////////////////////////////////////////
  72.  
  73. ULONG CKeyProvider::AddRef()
  74. {
  75.     return ++m_cRef;
  76. }
  77.  
  78. ULONG CKeyProvider::Release()
  79. {
  80.     ASSERT(m_cRef > 0);
  81.  
  82.     m_cRef--;
  83.  
  84.     if(m_cRef == 0)
  85.     {
  86.         delete this;
  87.  
  88.         // don't return m_cRef, because the object doesn't exist anymore
  89.         return((ULONG) 0);
  90.     }
  91.  
  92.     return(m_cRef);
  93. }
  94.  
  95. //
  96. // QueryInterface
  97. //
  98. // We only support IUnknown and IServiceProvider
  99. //
  100. HRESULT CKeyProvider::QueryInterface(REFIID riid, void ** ppv)
  101. {
  102.     if(riid == IID_IServiceProvider || riid == IID_IUnknown)
  103.     {
  104.         *ppv = (void *) static_cast<IServiceProvider *>(this);
  105.         AddRef();
  106.         return NOERROR;
  107.     }
  108.  
  109.     return E_NOINTERFACE;
  110. }
  111.  
  112. STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void **ppv)
  113. {
  114.     if(siid == __uuidof(IWMReader) && riid == IID_IUnknown)
  115.     {
  116.         IUnknown *punkCert;
  117.  
  118.         HRESULT hr = WMCreateCertificate(&punkCert);
  119.  
  120.         if(SUCCEEDED(hr))
  121.             *ppv = (void *) punkCert;
  122.         else
  123.             printf("CKeyProvider::QueryService failed to create certificate!  hr=0x%x\n", hr);
  124.     
  125.         return hr;
  126.     }
  127.  
  128.     return E_NOINTERFACE;
  129. }
  130.  
  131.  
  132.  
  133. HRESULT FindPinOnFilter( IBaseFilter * pFilter, PIN_DIRECTION PinDir,
  134.                         DWORD dwPin, BOOL fConnected, IPin ** ppPin )
  135. {
  136.     HRESULT            hr = S_OK;
  137.     IEnumPins *        pEnumPin = NULL;
  138.     IPin *            pConnectedPin = NULL;
  139.     PIN_DIRECTION    PinDirection;
  140.     ULONG            ulFetched;
  141.     DWORD            nFound = 0;
  142.  
  143.     ASSERT( pFilter != NULL );
  144.     *ppPin = NULL;
  145.  
  146.     hr = pFilter->EnumPins( &pEnumPin );
  147.     if(SUCCEEDED(hr))
  148.     {
  149.         while ( S_OK == ( hr = pEnumPin->Next( 1L, ppPin, &ulFetched ) ) )
  150.         {
  151.             hr = (*ppPin)->ConnectedTo( &pConnectedPin );
  152.             if (pConnectedPin)
  153.             {
  154.                 pConnectedPin->Release();
  155.                 pConnectedPin = NULL;
  156.             }
  157.             if ( ( ( VFW_E_NOT_CONNECTED == hr ) && !fConnected ) ||
  158.                  ( ( S_OK                == hr ) &&  fConnected ) )
  159.             {
  160.                 hr = (*ppPin)->QueryDirection( &PinDirection );
  161.                 if ( ( S_OK == hr ) && ( PinDirection == PinDir ) )
  162.                 {
  163.                     if ( nFound == dwPin ) break;
  164.                     nFound++;
  165.                 }
  166.             }
  167.             (*ppPin)->Release();
  168.         }
  169.     }
  170.     pEnumPin->Release();
  171.     return hr;
  172. } // FindPinOnFilter
  173.  
  174.  
  175. HRESULT GetPin(IBaseFilter *pFilter, DWORD dwPin, IPin **ppPin)
  176. {
  177.     IEnumPins *pins;
  178.  
  179.     *ppPin = NULL;
  180.     HRESULT hr = pFilter->EnumPins(&pins);
  181.     if(FAILED(hr))
  182.     {
  183.         DbgLog((LOG_ERROR,1,TEXT("EnumPins failed!  (%x)\n"), hr));
  184.         return hr;
  185.     }
  186.  
  187.     if(dwPin > 0)
  188.     {
  189.         hr = pins->Skip(dwPin);
  190.         if(FAILED(hr))
  191.         {
  192.             DbgLog((LOG_ERROR,1,TEXT("Skip(%d) failed!  (%x)\n"), dwPin, hr));
  193.             pins->Release();
  194.             return hr;
  195.         }
  196.  
  197.         if(hr == S_FALSE)
  198.         {
  199.             DbgLog((LOG_ERROR,1,TEXT("Skip(%d) ran out of pins!\n"), dwPin));
  200.             pins->Release();
  201.             return hr;
  202.         }
  203.     }
  204.  
  205.     DWORD n;
  206.     hr = pins->Next(1, ppPin, &n);
  207.  
  208.     if(FAILED(hr))
  209.     {
  210.         DbgLog((LOG_ERROR,1,TEXT("Next() failed!  (%x)\n"), hr));
  211.     }
  212.  
  213.     if(hr == S_FALSE)
  214.     {
  215.         DbgLog((LOG_ERROR,1,TEXT("Next() ran out of pins!  \n")));
  216.         pins->Release();
  217.         return hr;
  218.     }
  219.  
  220.     pins->Release();
  221.     return hr;
  222. }
  223.  
  224.  
  225. void ListProfiles()
  226. {
  227.     USES_CONVERSION;
  228.  
  229.     int wextent = 0, Loop = 0;
  230.     DWORD cProfiles = 0;
  231.     DWORD cchName, cchDescription;
  232.     CComPtr <IWMProfileManager> pIWMProfileManager;
  233.  
  234.     printf("Standard system profiles:\n");
  235.  
  236.     HRESULT hr = WMCreateProfileManager(&pIWMProfileManager);
  237.     if(FAILED(hr))
  238.     {
  239.         printf("ListProfiles: Failed to create profile manager!  hr=0x%x\n", hr);
  240.         return; // error
  241.     }
  242.  
  243.     CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);
  244.     if(!pIPM2) 
  245.     {
  246.         printf("ListProfiles: Failed to QI IWMProfileManager2!  hr=0x%x\n", hr);
  247.         return;
  248.     }
  249.  
  250.     // we only use 7_0 profiles
  251.     hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
  252.     if(FAILED(hr)) 
  253.     {
  254.         printf("ListProfiles: Failed to set system profile version!  hr=0x%x\n", hr);
  255.         return;
  256.     }
  257.  
  258.     hr = pIWMProfileManager->GetSystemProfileCount(&cProfiles);
  259.     if(FAILED(hr))
  260.     {
  261.         printf("ListProfiles: Failed to get system profile count!  hr=0x%x\n", hr);
  262.         return;
  263.     }
  264.  
  265.     // Load the profile strings
  266.     for(int i = 0; i < (int)cProfiles; ++i)
  267.     {
  268.         CComPtr <IWMProfile> pIWMProfile;
  269.  
  270.         hr = pIWMProfileManager->LoadSystemProfile(i, &pIWMProfile);
  271.         if(FAILED(hr))
  272.         {
  273.             printf("ListProfiles: Failed to load system profile!  hr=0x%x\n", hr);
  274.             return;
  275.         }
  276.  
  277.         // How large is the profile name?
  278.         hr = pIWMProfile->GetName(NULL, &cchName);
  279.         if(FAILED(hr))
  280.         {
  281.             printf("ListProfiles: Failed to read profile name size!  hr=0x%x\n", hr);
  282.             return;
  283.         }
  284.  
  285.         WCHAR *wszProfile = new WCHAR[ cchName + 1 ];
  286.         if(NULL == wszProfile)
  287.             return;
  288.  
  289.         hr = pIWMProfile->GetName(wszProfile, &cchName);
  290.         if(FAILED(hr))
  291.         {
  292.             printf("ListProfiles: Failed to read profile name!  hr=0x%x\n", hr);
  293.             return;
  294.         }
  295.  
  296.         // How large is the description?
  297.         hr = pIWMProfile->GetDescription(NULL, &cchDescription);
  298.         if(FAILED(hr))
  299.         {
  300.             printf("ListProfiles: Failed to read profile description size!  hr=0x%x\n", hr);
  301.             return;
  302.         }
  303.  
  304.         WCHAR *wszDescription = new WCHAR[ cchDescription + 1 ];
  305.         if(NULL == wszDescription)
  306.             return;
  307.  
  308.         hr = pIWMProfile->GetDescription(wszDescription, &cchDescription);
  309.         if(FAILED(hr))
  310.         {
  311.             printf("ListProfiles: Failed to read profile description!  hr=0x%x\n", hr);
  312.             return;
  313.         }
  314.  
  315.         // Display the profile name and description
  316.         if (fVerbose)
  317.             printf("  %3d:  %ls \n[%ls]\n\n", i, wszProfile, wszDescription);
  318.         else
  319.             printf("  %3d:  %ls\n", i, wszProfile);
  320.  
  321.         delete[] wszProfile;
  322.         delete[] wszDescription;
  323.     }
  324. }
  325.  
  326.  
  327. //=======================
  328. // CreateFilterGraph
  329. //=======================
  330.  
  331. HRESULT CreateFilterGraph(IGraphBuilder **pGraph)
  332. {
  333.     HRESULT hr;
  334.  
  335.     hr = CoCreateInstance(CLSID_FilterGraph, // get the graph object
  336.         NULL,
  337.         CLSCTX_INPROC_SERVER,
  338.         IID_IGraphBuilder,
  339.         (void **) pGraph);
  340.  
  341.     if(FAILED(hr))
  342.     {
  343.         printf("CreateFilterGraph: Failed to create graph!  hr=0x%x\n", hr);
  344.         *pGraph = NULL;
  345.         return hr;
  346.     }
  347.  
  348.     return S_OK;
  349. }
  350.  
  351.  
  352. HRESULT CreateFilter(REFCLSID clsid, IBaseFilter **ppFilter)
  353. {
  354.     HRESULT hr;
  355.  
  356.     hr = CoCreateInstance(clsid,
  357.         NULL,
  358.         CLSCTX_INPROC_SERVER,
  359.         IID_IBaseFilter,
  360.         (void **) ppFilter);
  361.  
  362.     if(FAILED(hr))
  363.     {
  364.         printf("CreateFilter: Failed to create filter!  hr=0x%x\n", hr);
  365.         *ppFilter = NULL;
  366.         return hr;
  367.     }
  368.  
  369.     return S_OK;
  370. }
  371.  
  372.  
  373. HRESULT SetNoClock(IFilterGraph *graph)
  374. {
  375.     // Keep a useless clock from being instantiated....
  376.     IMediaFilter *graphF;
  377.     HRESULT hr = graph->QueryInterface(IID_IMediaFilter, (void **) &graphF);
  378.  
  379.     if(SUCCEEDED(hr))
  380.     {
  381.         hr = graphF->SetSyncSource(NULL);
  382.         if (FAILED(hr))
  383.             printf("SetNoClock: Failed to set sync source!  hr=0x%x\n", hr);
  384.  
  385.         graphF->Release();
  386.     }
  387.     else
  388.     {
  389.         printf("SetNoClock: Failed to QI for media filter!  hr=0x%x\n", hr);
  390.     }
  391.  
  392.     return hr;
  393. }
  394.  
  395.  
  396. HRESULT MapProfileIdToProfile(int iProfile, IWMProfile **ppProfile)
  397. {
  398.     DWORD cProfiles;
  399.  
  400.     *ppProfile = 0;
  401.     
  402.     CComPtr <IWMProfileManager> pIWMProfileManager;
  403.     HRESULT hr = WMCreateProfileManager( &pIWMProfileManager );
  404.     if(FAILED(hr)) 
  405.     {
  406.         printf("MapProfile: Failed to create profile manager!  hr=0x%x\n", hr);
  407.         return hr;
  408.     }
  409.  
  410.     // We only use 7_0 profiles
  411.     CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);
  412.     if(!pIPM2) 
  413.     {
  414.         printf("MapProfile: Failed to QI IWMProfileManager2!\n");
  415.         return E_UNEXPECTED;
  416.     }
  417.  
  418.     hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
  419.     if(FAILED(hr))
  420.     {
  421.         printf("MapProfile: Failed to set system profile version!  hr=0x%x\n", hr);
  422.         return hr;
  423.     }
  424.  
  425.     hr = pIWMProfileManager->GetSystemProfileCount( &cProfiles );
  426.     if(FAILED(hr))
  427.     {
  428.         printf("MapProfile: Failed to get system profile count!  hr=0x%x\n", hr);
  429.         return hr;
  430.     }
  431.  
  432.     // Invalid profile requested?
  433.     if( (DWORD)iProfile >= cProfiles ) 
  434.     {
  435.         printf("Invalid profile: %d\n", iProfile);
  436.         return E_INVALIDARG;
  437.     }
  438.  
  439.     return (pIWMProfileManager->LoadSystemProfile( iProfile, ppProfile ));
  440. }
  441.  
  442.  
  443. void WaitForCompletion( IGraphBuilder *pGraph )
  444. {
  445.     HRESULT hr;
  446.     LONG lEvCode = 0;
  447.     IMediaEvent *pEvent;
  448.  
  449.     pGraph->QueryInterface(IID_IMediaEvent, (void **) &pEvent);
  450.  
  451.     printf("Waiting for completion...\n  This could take several minutes, "
  452.            "depending on file size and selected profile.\n");
  453.     do
  454.     {
  455.         MSG Message;
  456.  
  457.         while(PeekMessage(&Message, NULL, 0, 0, TRUE))
  458.         {
  459.             TranslateMessage(&Message);
  460.             DispatchMessage(&Message);
  461.         }
  462.  
  463.         hr = pEvent->WaitForCompletion(10, &lEvCode);
  464.  
  465.     } while(lEvCode == 0);
  466.  
  467.     pEvent->Release();
  468. }
  469.  
  470.  
  471. HRESULT CopyASF(int argc, char *argv[])
  472. {
  473.     HRESULT hr;    
  474.     WCHAR SourceFile[256], TargetFile[256];
  475.     BOOL fListProfiles = TRUE;
  476.     DWORD dwProfile=0;
  477.     int i = 1;
  478.  
  479.     // Parse command line options
  480.     while(i < argc && (argv[i][0] == '-' || argv[i][0] == '/'))
  481.     {
  482.         // options
  483.         if(lstrcmpiA(argv[i] + 1, "v") == 0)
  484.         {
  485.             fVerbose = TRUE;
  486.             printf("Verbose mode enabled.\n");
  487.         }
  488.         else if((i+1 < argc) && lstrcmpiA(argv[i] + 1, "p") == 0)
  489.         {
  490.             fListProfiles = FALSE;
  491.             dwProfile = atoiA(argv[i+1]);
  492.             i++;  // skip two args here
  493.         } 
  494.  
  495.         i++;
  496.     }
  497.  
  498.     // List profiles only?
  499.     if(fListProfiles)
  500.     {
  501.         printf("Usage: asfcopy [/v] /p profnum file1 [ file2 ...] target\n\n");
  502.  
  503.         HRESULT hr = CoInitialize(NULL);
  504.         ListProfiles();
  505.         CoUninitialize();
  506.         return -1;
  507.     }
  508.  
  509.     // Fail with usage information if improper number of arguments
  510.     if(argc < i+2)
  511.     {
  512.         printf("Usage: asfcopy [/v] /p profnum file1 [ file2 ...] target\n");
  513.         return -1;
  514.     }
  515.  
  516.  
  517.     CComPtr <IGraphBuilder> pGraph;
  518.     CComPtr <IObjectWithSite> pObjectWithSite;
  519.     CComPtr <IBaseFilter> pMux;
  520.     CComPtr <IBaseFilter> pWriter;
  521.     CComPtr <IFileSinkFilter> pFS;
  522.     CComPtr <IConfigInterleaving> pConfigInterleaving;
  523.     CComPtr <IConfigAsfWriter> pConfigAsfWriter;
  524.     CComPtr <IMediaControl> pGraphC;
  525.  
  526.     // Convert target filename
  527.     MultiByteToWideChar(CP_ACP, 0, argv[argc - 1], -1, TargetFile, 256);
  528.  
  529.     hr = CreateFilterGraph(&pGraph);
  530.     if(FAILED(hr))
  531.     {
  532.         printf("Couldn't create filter graph! hr=0x%x", hr);
  533.         return hr;
  534.     }
  535.  
  536.     CKeyProvider prov;
  537.     prov.AddRef();  // Don't let COM try to free our static object
  538.  
  539.     // Give the graph a pointer to us for callbacks & QueryService
  540.     hr = pGraph->QueryInterface(IID_IObjectWithSite, (void**)&pObjectWithSite);
  541.     if(SUCCEEDED(hr))
  542.     {
  543.         hr = pObjectWithSite->SetSite((IUnknown *) (IServiceProvider *) &prov);
  544.         if(FAILED(hr))
  545.         {
  546.             printf("Failed to set service provider!  hr=0x%x\n", hr);
  547.             return hr;
  548.         }
  549.     }
  550.  
  551.     hr = CreateFilter(CLSID_WMAsfWriter, &pMux);
  552.     if(FAILED(hr))
  553.     {
  554.         printf("Failed to create WMAsfWriter filter!  hr=0x%x\n", hr);
  555.         return hr;
  556.     }
  557.  
  558.     hr = pMux->QueryInterface(IID_IFileSinkFilter, (void **) &pFS);
  559.     if(FAILED(hr))
  560.     {
  561.         // We need a writer also
  562.         hr = CreateFilter(CLSID_FileWriter, &pWriter);
  563.         if(FAILED(hr))
  564.         {
  565.             printf("Failed to create FileWriter filter!  hr=0x%x\n", hr);
  566.             return hr;
  567.         }
  568.         else
  569.         {
  570.             hr = pWriter->QueryInterface(IID_IFileSinkFilter, (void **) &pFS);
  571.             if(FAILED(hr))
  572.             {
  573.                 printf("Failed to create QI IFileSinkFilter!  hr=0x%x\n", hr);
  574.                 return hr;
  575.             }
  576.         }
  577.     }
  578.  
  579.     hr = pFS->SetFileName(TargetFile, NULL);
  580.     if(FAILED(hr))
  581.     {
  582.         printf("Failed to set target filename!  hr=0x%x\n", hr);
  583.         return hr;
  584.     }
  585.  
  586.     hr = pGraph->AddFilter(pMux, L"Mux");
  587.     if(FAILED(hr))
  588.     {
  589.         printf("Failed to add Mux filter to graph!  hr=0x%x\n", hr);
  590.         return hr;
  591.     }
  592.  
  593.     // Set interleaving mode to FULL
  594.     // !!! ASF won't support this, but that's okay
  595.     hr = pMux->QueryInterface(IID_IConfigInterleaving, (void **) &pConfigInterleaving);
  596.     if(SUCCEEDED(hr))
  597.     {
  598.         printf("Setting interleaving mode to INTERLEAVE_FULL\r\n");
  599.         hr = pConfigInterleaving->put_Mode(INTERLEAVE_FULL);
  600.     }
  601.  
  602.     // !!! We should only require a profile if we're using a filter which needs it
  603.     hr = pMux->QueryInterface(IID_IConfigAsfWriter, (void **) &pConfigAsfWriter);
  604.     if(SUCCEEDED(hr))
  605.     {
  606.         if (fVerbose)
  607.             printf("Setting profile to %d\r\n", dwProfile);
  608.  
  609.         CComPtr<IWMProfile> pProfile;
  610.  
  611.         hr = MapProfileIdToProfile(dwProfile, &pProfile);
  612.         if(FAILED(hr)) {
  613.             printf("Failed to map profile ID!  hr=0x%x\n", hr);
  614.             return hr;
  615.         }
  616.  
  617.         // Note that the ASF writer will not run if the number of streams
  618.         // does not match the profile.
  619.         hr = pConfigAsfWriter->ConfigureFilterUsingProfile(pProfile);
  620.         if(FAILED(hr)) {
  621.             printf("Failed to configure filter to use profile!  hr=0x%x\n", hr);
  622.             return hr;
  623.         }       
  624.     }
  625.     else
  626.     {
  627.         printf("Failed to QI for IConfigAsfWriter!  hr=0x%x\n", hr);
  628.         return hr;
  629.     }
  630.  
  631.     // Connect writer filter if needed
  632.     if(pWriter)
  633.     {
  634.         IPin *pMuxOut, *pWriterIn;
  635.         hr = pGraph->AddFilter(pWriter, L"Writer");
  636.         if(FAILED(hr))
  637.         {
  638.             printf("Failed to add FileWriter filter to graph!  hr=0x%x\n", hr);
  639.             return hr;
  640.         }
  641.  
  642.         // Look for the first unconnected output pin
  643.         hr = FindPinOnFilter(pMux, PINDIR_OUTPUT, 0, FALSE, &pMuxOut);
  644.         if(FAILED(hr))
  645.         {
  646.             printf("Failed to find output pin on Mux!  hr=0x%x\n", hr);
  647.             return hr;
  648.         }
  649.         // Find the first connected pin
  650.         hr = FindPinOnFilter(pWriter, PINDIR_INPUT, 0, FALSE, &pWriterIn);
  651.         if(FAILED(hr))
  652.         {
  653.             printf("Failed to find input pin on FileWriter!  hr=0x%x\n", hr);
  654.             pMuxOut->Release();
  655.             return hr;
  656.         }
  657.  
  658.         hr = pGraph->ConnectDirect(pMuxOut, pWriterIn, NULL);
  659.         pMuxOut->Release(); 
  660.         pWriterIn->Release();
  661.         if(FAILED(hr))
  662.         {
  663.             printf("Failed to connect Mux to FileWriter!  hr=0x%x\n", hr);
  664.             return hr;
  665.         }
  666.  
  667.         if(fVerbose)
  668.             printf("Connected Mux and writer, hr = 0x%x\n", hr);
  669.     }
  670.  
  671.     // Set sync source to NULL to speed processing
  672.     SetNoClock(pGraph);
  673.  
  674.     // Render all source files listed on the command line
  675.     while(i < argc - 1)
  676.     {
  677.         MultiByteToWideChar(CP_ACP, 0, argv[i], -1,
  678.             SourceFile, 256);
  679.  
  680.         printf("Copying %ls to %ls\n", SourceFile, TargetFile);
  681.  
  682.         hr = pGraph->RenderFile(SourceFile, NULL);
  683.         if(FAILED(hr))
  684.             printf("Failed to render source file %s!  hr=0x%x\n", argv[i], hr);
  685.         else if (fVerbose)
  686.             printf("RenderFile('%ls') returned hr=0x%x\n", SourceFile, hr);
  687.  
  688.         ++i;
  689.     }
  690.  
  691.     // Run the graph
  692.     hr = pGraph->QueryInterface(IID_IMediaControl, (void **) &pGraphC);
  693.     if(FAILED(hr))
  694.     {
  695.         printf("Failed to QI for IMediaControl!  hr=0x%x\n", hr);
  696.         return hr;
  697.     }
  698.  
  699.     hr = pGraphC->Run();
  700.     if(FAILED(hr))
  701.     {
  702.         printf("Failed to run the graph!  hr=0x%x\nCopy aborted.\n\n", hr);
  703.         printf("Please check that you have selected the correct profile for copying.\n"
  704.                "Note that if your source ASF file is audio-only, then selecting a\n"
  705.                "video profile will cause a failure when running the graph.\n\n");
  706.         ListProfiles();
  707.     }
  708.     else
  709.     {
  710.         WaitForCompletion(pGraph);
  711.         printf("Copy complete.\n");
  712.  
  713.         // Stop the graph
  714.         hr = pGraphC->Stop();
  715.     }
  716.  
  717.     return hr;
  718. }
  719.  
  720.  
  721. int __cdecl
  722. main(
  723.     int argc,
  724.     char *argv[]
  725.     )
  726. {
  727.     // Initialize COM
  728.     HRESULT hr = CoInitialize(NULL);
  729.  
  730.     // Since COM smart pointers are used, the main functionality is wrapped
  731.     // in CopyASF().  When the function returns, the smart pointers will clean
  732.     // up properly, and then we'll uninitialize COM.
  733.     hr = CopyASF(argc, argv);
  734.  
  735.     CoUninitialize();
  736.     return hr;
  737. }
  738.  
  739.