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

  1. //------------------------------------------------------------------------------
  2. // File: Graph.cpp
  3. //
  4. // Desc: Sample code for BDA graph building.
  5. //
  6. // Copyright (c) 2000-2001, Microsoft Corporation. All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9. #include "graph.h"
  10.  
  11. // Constructor, initializes member variables
  12. // and calls InitializeGraphBuilder
  13. CBDAFilterGraph::CBDAFilterGraph() :
  14.     m_fGraphBuilt(FALSE),
  15.     m_fGraphRunning(FALSE),
  16.     m_NetworkType(ATSC),
  17.     m_lMajorChannel(-1), 
  18.     m_lMinorChannel(-1),
  19.     m_lPhysicalChannel(46L),// 46 is an in house test channel - go ahead and change it
  20.     m_dwGraphRegister (0)
  21. {
  22.     if(FAILED(InitializeGraphBuilder()))
  23.         m_fGraphFailure = TRUE;
  24.     else
  25.         m_fGraphFailure = FALSE;
  26. }
  27.  
  28. // Destructor
  29. CBDAFilterGraph::~CBDAFilterGraph()
  30. {
  31.     if(m_fGraphRunning)
  32.     {
  33.         StopGraph();
  34.     }
  35.  
  36.     if(m_fGraphBuilt || m_fGraphFailure)
  37.     {
  38.         TearDownGraph();
  39.     }
  40. }
  41.  
  42.  
  43. // Instantiate graph object for filter graph building
  44. HRESULT
  45. CBDAFilterGraph::InitializeGraphBuilder()
  46. {
  47.     HRESULT hr = S_OK;
  48.     
  49.     // we have a graph already
  50.     if (m_pFilterGraph)
  51.         return S_OK;
  52.  
  53.     // create the filter graph
  54.     if (FAILED (hr = m_pFilterGraph.CoCreateInstance (CLSID_FilterGraph)))
  55.     {
  56.         ErrorMessageBox(TEXT("Couldn't CoCreate IGraphBuilder\n"));
  57.         m_fGraphFailure = TRUE;
  58.         return hr;
  59.     }
  60.     
  61.     return hr;
  62. }
  63.  
  64. // BuildGraph sets up devices, adds and connects filters
  65. HRESULT
  66. CBDAFilterGraph::BuildGraph(NETWORK_TYPE NetType)
  67. {
  68.     HRESULT hr = S_OK;
  69.     m_NetworkType = NetType;
  70.  
  71.     // if we have already have a filter graph, tear it down
  72.     if(m_fGraphBuilt)
  73.     {
  74.         if(m_fGraphRunning)
  75.         {
  76.             hr = StopGraph ();
  77.         }
  78.  
  79.         hr = TearDownGraph ();
  80.     }
  81.  
  82.     // STEP 1: load network provider first so that it can configure other
  83.     // filters, such as configuring the demux to sprout output pins.
  84.     // We also need to submit a tune request to the Network Provider so it will
  85.     // tune to a channel
  86.     if(FAILED (hr = LoadNetworkProvider()))
  87.     {
  88.         ErrorMessageBox(TEXT("Cannot load network provider\n"));
  89.         TearDownGraph();
  90.         m_fGraphFailure = true;
  91.         return hr;
  92.     }
  93.  
  94.     hr = m_pNetworkProvider->QueryInterface(__uuidof (ITuner), reinterpret_cast <void**> (&m_pITuner));
  95.     if(FAILED (hr))
  96.     {
  97.         ErrorMessageBox(TEXT("pNetworkProvider->QI: Can't QI for ITuner.\n"));
  98.         TearDownGraph();
  99.         m_fGraphFailure = true;
  100.         return hr;
  101.     }
  102.  
  103.     // create a tune request to initialize the network provider
  104.     // before connecting other filters
  105.     CComPtr <IATSCChannelTuneRequest>  pATSCTuneRequest;
  106.     if(FAILED (hr = CreateATSCTuneRequest(
  107.         m_lPhysicalChannel,
  108.         m_lMajorChannel, 
  109.         m_lMinorChannel,
  110.         &pATSCTuneRequest
  111.         )))
  112.     {
  113.         ErrorMessageBox(TEXT("Cannot create tune request\n"));
  114.         TearDownGraph();
  115.         m_fGraphFailure = true;
  116.         return hr;
  117.     }
  118.  
  119.     //submit the tune request to the network provider
  120.     hr = m_pITuner->put_TuneRequest(pATSCTuneRequest);
  121.     if(FAILED(hr))
  122.     {
  123.         ErrorMessageBox(TEXT("Cannot submit the tune request\n"));
  124.         TearDownGraph();
  125.         m_fGraphFailure = true;
  126.         return hr;
  127.     }
  128.  
  129.  
  130.     // STEP2: Load tuner device and connect to network provider
  131.     if(FAILED (hr = LoadFilter (
  132.         KSCATEGORY_BDA_NETWORK_TUNER, 
  133.         &m_pTunerDevice,
  134.         m_pNetworkProvider, 
  135.         TRUE
  136.         )))
  137.     {
  138.         ErrorMessageBox(TEXT("Cannot load tuner device and connect network provider\n"));
  139.         TearDownGraph();
  140.         m_fGraphFailure = true;
  141.         return hr;
  142.     }
  143.  
  144.     // STEP3: Load tuner device and connect to demodulator device
  145.     if(FAILED (hr = LoadFilter (
  146.         KSCATEGORY_BDA_RECEIVER_COMPONENT, 
  147.         &m_pDemodulatorDevice,
  148.         m_pTunerDevice, 
  149.         TRUE
  150.         )))
  151.     {
  152.         ErrorMessageBox(TEXT("Cannot load capture device and connect tuner\n"));
  153.         TearDownGraph();
  154.         m_fGraphFailure = true;
  155.         return hr;
  156.     }
  157.  
  158.     // Step4: Load capture device and connect to tuner device
  159.     if(FAILED (hr = LoadFilter (
  160.         KSCATEGORY_BDA_RECEIVER_COMPONENT, 
  161.         &m_pCaptureDevice,
  162.         m_pDemodulatorDevice, 
  163.         TRUE
  164.         )))
  165.     {
  166.         ErrorMessageBox(TEXT("Cannot load capture device and connect tuner\n"));
  167.         TearDownGraph();
  168.         m_fGraphFailure = true;
  169.         return hr;
  170.     }
  171.  
  172.     // Step5: Load demux
  173.     if(FAILED (hr = LoadDemux()))
  174.     {
  175.         ErrorMessageBox(TEXT("Cannot load demux\n"));
  176.         TearDownGraph();
  177.         m_fGraphFailure = true;
  178.         return hr;
  179.     }
  180.  
  181.     //
  182.     // this next call loads and connects filters associated with
  183.     // the demultiplexor. if you want to manually load individual
  184.     // filters such as audio and video decoders, use the code at
  185.     // the bottom of this file
  186.     //
  187. #ifdef DEBUG
  188.     hr = AddGraphToRot (m_pFilterGraph, &m_dwGraphRegister);
  189.     if (FAILED(hr))
  190.     {
  191.         ///ErrorMessageBox(TEXT("Failed to register filter graph with ROT!  hr=0x%x"), hr);
  192.         m_dwGraphRegister = 0;
  193.     }
  194. #endif
  195.     //MessageBox (NULL, _T(""), _T(""), MB_OK);
  196.     // Step6: Render demux pins
  197.     if(FAILED (hr = RenderDemux()))
  198.     {
  199.         ErrorMessageBox(TEXT("Cannot load demux\n"));
  200.         TearDownGraph();
  201.         m_fGraphFailure = true;
  202.         return hr;
  203.     }
  204.  
  205.     m_fGraphBuilt = true;
  206.  
  207.     return S_OK;
  208. }
  209.  
  210.  
  211. // Loads the correct tuning space based on NETWORK_TYPE that got
  212. // passed into BuildGraph()
  213. HRESULT
  214. CBDAFilterGraph::LoadTuningSpace()
  215. {   
  216.     CComPtr <ITuningSpaceContainer>  pITuningSpaceContainer;
  217.  
  218.     // get the tuningspace container for all the tuning spaces from SYSTEM_TUNING_SPACES
  219.     HRESULT hr = pITuningSpaceContainer.CoCreateInstance(CLSID_SystemTuningSpaces);
  220.     if (FAILED (hr))
  221.     {
  222.         ErrorMessageBox(TEXT("Could not CoCreate SystemTuningSpaces\n"));
  223.         return hr;
  224.     }
  225.  
  226.     CComVariant var (m_NetworkType);
  227.  
  228.     hr = pITuningSpaceContainer->get_Item(var, &m_pITuningSpace);
  229.  
  230.     if(FAILED(hr))
  231.     {
  232.         ErrorMessageBox(TEXT("Unable to retrieve Tuning Space\n"));
  233.     }
  234.  
  235.     return hr;
  236. }
  237.  
  238. // Creates an ATSC Tune Request
  239. HRESULT
  240. CBDAFilterGraph::CreateATSCTuneRequest(
  241.         LONG lPhysicalChannel,
  242.         LONG lMajorChannel, 
  243.         LONG lMinorChannel,
  244.         IATSCChannelTuneRequest**   pTuneRequest
  245.     )
  246. {
  247.     HRESULT hr = S_OK;
  248.  
  249.     if (pTuneRequest == NULL)
  250.     {
  251.         ErrorMessageBox (TEXT("Invalid pointer\n"));
  252.         return E_POINTER;
  253.     }
  254.  
  255.     // Making sure we have a valid tuning space
  256.     if (m_pITuningSpace == NULL)
  257.     {
  258.         ErrorMessageBox(TEXT("Tuning Space is NULL\n"));
  259.         return E_FAIL;
  260.     }
  261.  
  262.     //  Create an instance of the ATSC tuning space
  263.     CComQIPtr <IATSCTuningSpace> pATSCTuningSpace (m_pITuningSpace);
  264.     if (!pATSCTuningSpace)
  265.     {
  266.         ErrorMessageBox(TEXT("Cannot QI for an IATSCTuningSpace\n"));
  267.         return E_FAIL;
  268.     }
  269.  
  270.     //  Create an empty tune request.
  271.     CComPtr <ITuneRequest> pNewTuneRequest;
  272.     hr = pATSCTuningSpace->CreateTuneRequest(&pNewTuneRequest);
  273.  
  274.     if (FAILED (hr))
  275.     {
  276.         ErrorMessageBox(TEXT("CreateTuneRequest: Can't create tune request.\n"));
  277.         return hr;
  278.     }
  279.  
  280.     //query for an IATSCChannelTuneRequest interface pointer
  281.     CComQIPtr <IATSCChannelTuneRequest> pATSCTuneRequest (pNewTuneRequest);
  282.     if (!pATSCTuneRequest)
  283.     {
  284.         ErrorMessageBox(TEXT("CreateATSCTuneRequest: Can't QI for IATSCChannelTuneRequest.\n"));
  285.         return E_FAIL;
  286.     }
  287.  
  288.     //  Set the initial major and minor channels
  289.     hr = pATSCTuneRequest->put_Channel(lMajorChannel);
  290.     if(FAILED(hr))
  291.     {
  292.         ErrorMessageBox(TEXT("put_Channel failed\n"));
  293.         return hr;
  294.     }
  295.  
  296.     hr = pATSCTuneRequest->put_MinorChannel(lMinorChannel);
  297.     if(FAILED(hr))
  298.     {
  299.         ErrorMessageBox(TEXT("put_MinorChannel failed\n"));
  300.         return hr;
  301.     }
  302.  
  303.     CComPtr <IATSCLocator> pATSCLocator;
  304.     hr = pATSCLocator.CoCreateInstance (CLSID_ATSCLocator);
  305.     if (FAILED( hr))
  306.     {
  307.         ErrorMessageBox(TEXT("Cannot create the ATSC locator failed\n"));
  308.         return hr;
  309.     }
  310.  
  311.     //  Set the initial physical channel.
  312.     //
  313.     hr = pATSCLocator->put_PhysicalChannel (lPhysicalChannel);
  314.     if (FAILED( hr))
  315.     {
  316.         ErrorMessageBox(TEXT("Cannot put the physical channel\n"));
  317.         return hr;
  318.     }
  319.  
  320.     hr = pATSCTuneRequest->put_Locator (pATSCLocator);
  321.     if (FAILED (hr))
  322.     {
  323.         ErrorMessageBox(TEXT("Cannot put the locator\n"));
  324.         return hr;
  325.     }
  326.  
  327.     hr = pATSCTuneRequest.QueryInterface (pTuneRequest);
  328.  
  329.     return hr;
  330. }
  331.  
  332.  
  333. // LoadNetworkProvider loads network provider
  334. HRESULT
  335. CBDAFilterGraph::LoadNetworkProvider()
  336. {
  337.     HRESULT     hr = S_OK;
  338.     CComBSTR    bstrNetworkType;
  339.     CLSID       CLSIDNetworkType;
  340.  
  341.     // obtain tuning space then load network provider
  342.     if(m_pITuningSpace == NULL)
  343.     {
  344.         hr = LoadTuningSpace();
  345.         if(FAILED(hr))
  346.         {
  347.             ErrorMessageBox(TEXT("Cannot load TuningSpace\n"));
  348.             return hr;
  349.         }
  350.     }
  351.  
  352.     // Get the current Network Type clsid
  353.     hr = m_pITuningSpace->get_NetworkType(&bstrNetworkType);
  354.     if (FAILED (hr))
  355.     {
  356.         ErrorMessageBox(TEXT("ITuningSpace::Get Network Type failed\n"));
  357.         return hr;
  358.     }
  359.  
  360.     hr = CLSIDFromString(bstrNetworkType, &CLSIDNetworkType);
  361.     if (FAILED (hr))
  362.     {
  363.         ErrorMessageBox(TEXT("Couldn't get CLSIDFromString\n"));
  364.         return hr;
  365.     }
  366.  
  367.     // create the network provider based on the clsid obtained from the tuning space
  368.     hr = CoCreateInstance(CLSIDNetworkType, NULL, CLSCTX_INPROC_SERVER,
  369.             IID_IBaseFilter, reinterpret_cast<void**>(&m_pNetworkProvider));
  370.     if (FAILED (hr))
  371.     {
  372.         ErrorMessageBox(TEXT("Couldn't CoCreate Network Provider\n"));
  373.         return hr;
  374.     }
  375.  
  376.     //add the Network Provider filter to the graph
  377.     hr = m_pFilterGraph->AddFilter(m_pNetworkProvider, L"Network Provider");
  378.  
  379.     return hr;
  380. }
  381.  
  382.  
  383. // enumerates through registered filters
  384. // instantiates the the filter object and adds it to the graph
  385. // it checks to see if it connects to upstream filter
  386. // if not,  on to the next enumerated filter
  387. // used for tuner, capture, MPE Data Filters and decoders that
  388. // could have more than one filter object
  389. // if pUpstreamFilter is NULL don't bother connecting
  390. HRESULT
  391. CBDAFilterGraph::LoadFilter(
  392.     REFCLSID clsid, 
  393.     IBaseFilter** ppFilter,
  394.     IBaseFilter* pConnectFilter, 
  395.     BOOL fIsUpstream
  396.     )
  397. {
  398.     HRESULT                 hr = S_OK;
  399.     BOOL                    fFoundFilter = FALSE;
  400.     CComPtr <IMoniker>      pIMoniker;
  401.     CComPtr <IEnumMoniker>  pIEnumMoniker;
  402.  
  403.     if (!m_pICreateDevEnum)
  404.     {
  405.         hr = m_pICreateDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum);
  406.         if (FAILED (hr))
  407.         {
  408.             ErrorMessageBox(TEXT("LoadFilter(): Cannot CoCreate ICreateDevEnum"));
  409.             return hr;
  410.         }
  411.     }
  412.  
  413.     // obtain the enumerator
  414.     hr = m_pICreateDevEnum->CreateClassEnumerator(clsid, &pIEnumMoniker, 0);
  415.     // the call can return S_FALSE if no moniker exists, so explicitly check S_OK
  416.     if (FAILED (hr))
  417.     {
  418.         ErrorMessageBox(TEXT("LoadFilter(): Cannot CreateClassEnumerator"));
  419.         return hr;
  420.     }
  421.     if (S_OK != hr)  // Class not found
  422.     {
  423.         ErrorMessageBox(TEXT("LoadFilter(): Class not found, CreateClassEnumerator returned S_FALSE"));
  424.         return E_UNEXPECTED;
  425.     }
  426.  
  427.     // next filter
  428.     while(pIEnumMoniker->Next(1, &pIMoniker, 0) == S_OK)
  429.     {
  430.         // obtain filter's friendly name
  431.         CComPtr <IPropertyBag>  pBag;
  432.         hr = pIMoniker->BindToStorage(
  433.                 NULL, 
  434.                 NULL, 
  435.                 IID_IPropertyBag,
  436.                 reinterpret_cast<void**>(&pBag)
  437.                 );
  438.  
  439.         if(FAILED(hr))
  440.         {
  441.             OutputDebugString (TEXT("LoadFilter(): Cannot BindToStorage"));
  442.             return hr;
  443.         }
  444.  
  445.         CComVariant varBSTR;
  446.         hr = pBag->Read(L"FriendlyName", &varBSTR, NULL);
  447.         if(FAILED(hr))
  448.         {
  449.             OutputDebugString (TEXT("LoadFilter(): IPropertyBag->Read method failed"));
  450.             pIMoniker = NULL;
  451.             continue;
  452.         }
  453.  
  454.         // bind the filter
  455.         CComPtr <IBaseFilter>   pFilter;
  456.         hr = pIMoniker->BindToObject(
  457.                 NULL, 
  458.                 NULL, 
  459.                 IID_IBaseFilter,
  460.                 reinterpret_cast<void**>(&pFilter)
  461.                 );
  462.  
  463.         if (FAILED(hr))
  464.         {
  465.             pIMoniker = NULL;
  466.             pFilter = NULL;
  467.             continue;
  468.         }
  469.  
  470.  
  471.         hr = m_pFilterGraph->AddFilter (pFilter, varBSTR.bstrVal);
  472.  
  473.         if (FAILED(hr))
  474.         {
  475.             OutputDebugString (TEXT("Cannot add filter\n"));
  476.             return hr;
  477.         }
  478.  
  479.         //MessageBox (NULL, _T(""), _T(""), MB_OK);
  480.         // test connections
  481.         // to upstream filter
  482.         if (pConnectFilter)
  483.         {
  484.             if(fIsUpstream)
  485.             {
  486.                 hr = ConnectFilters (pConnectFilter, pFilter);
  487.             }
  488.             else
  489.             {
  490.                 hr = ConnectFilters (pFilter, pConnectFilter);
  491.             }
  492.  
  493.             if(SUCCEEDED(hr))
  494.             {
  495.                 //that's the filter we want
  496.                 fFoundFilter = TRUE;
  497.                 pFilter.QueryInterface (ppFilter);
  498.                 break;
  499.             }
  500.             else
  501.             {
  502.                 fFoundFilter = FALSE;
  503.                 // that wasn't the the filter we wanted
  504.                 // so unload and try the next one
  505.                 hr = m_pFilterGraph->RemoveFilter(pFilter);
  506.  
  507.                 if(FAILED(hr))
  508.                 {
  509.                     OutputDebugString(TEXT("Failed unloading Filter\n"));
  510.                     return hr;
  511.                 }
  512.             }
  513.         }
  514.         else
  515.         {
  516.             fFoundFilter = TRUE;
  517.             pFilter.QueryInterface (ppFilter);
  518.             break;
  519.         }
  520.  
  521.         pIMoniker = NULL;
  522.         pFilter = NULL;
  523.     } // while
  524.     return S_OK;
  525. }
  526.  
  527. // loads the demux into the FilterGraph
  528. HRESULT
  529. CBDAFilterGraph::LoadDemux()
  530. {
  531.     HRESULT hr = S_OK;
  532.     
  533.     hr = CoCreateInstance(
  534.             CLSID_MPEG2Demultiplexer, 
  535.             NULL, 
  536.             CLSCTX_INPROC_SERVER,
  537.             IID_IBaseFilter, 
  538.             reinterpret_cast<void**>(&m_pDemux)
  539.             );
  540.     if (FAILED (hr))
  541.     {
  542.         ErrorMessageBox(TEXT("Could not CoCreateInstance CLSID_MPEG2Demultiplexer\n"));
  543.         return hr;
  544.     }
  545.  
  546.     hr = m_pFilterGraph->AddFilter(m_pDemux, L"Demux");
  547.     if(FAILED(hr))
  548.     {
  549.         ErrorMessageBox(TEXT("Unable to add demux filter to graph\n"));
  550.         return hr;
  551.     }
  552.  
  553.     return hr;
  554. }
  555.  
  556.  
  557. // renders demux output pins
  558. HRESULT
  559. CBDAFilterGraph::RenderDemux()
  560. {
  561.     HRESULT             hr = S_OK;
  562.     CComPtr <IPin>      pIPin;
  563.     CComPtr <IPin>      pDownstreamPin;
  564.     CComPtr <IEnumPins> pIEnumPins;
  565.     PIN_DIRECTION       direction;
  566.  
  567.     if (!m_pDemux)
  568.     {
  569.         return E_FAIL;
  570.     }
  571.  
  572.     // connect the demux to the capture device
  573.     hr = ConnectFilters (m_pCaptureDevice, m_pDemux);
  574.  
  575.     if (FAILED (hr))
  576.     {
  577.         ErrorMessageBox(TEXT("Cannot connect demux to capture filter\n"));
  578.         return hr;
  579.     }
  580.  
  581.     // load transform information filter and connect it to the demux
  582.     hr = LoadFilter (
  583.             KSCATEGORY_BDA_TRANSPORT_INFORMATION, 
  584.             &m_pTIF, 
  585.             m_pDemux, 
  586.             TRUE
  587.             );
  588.     if (FAILED (hr))
  589.     {
  590.         ErrorMessageBox(TEXT("Cannot load TIF\n"));
  591.         return hr;
  592.     }
  593.  
  594.     // load multi protocol encapsulator
  595.     hr = LoadFilter (
  596.             KSCATEGORY_BDA_RECEIVER_COMPONENT, 
  597.             &m_pMPE, 
  598.             m_pDemux, 
  599.             TRUE
  600.             );
  601.     if (FAILED (hr))
  602.     {
  603.         ErrorMessageBox(TEXT("Cannot load MPE\n"));
  604.         return hr;
  605.     }
  606.  
  607.     // load IP Sink
  608.     hr = LoadFilter (
  609.             KSCATEGORY_IP_SINK, 
  610.             &m_pIPSink, 
  611.             m_pMPE, 
  612.             TRUE
  613.             );
  614.     if (FAILED (hr))
  615.     {
  616.         ErrorMessageBox(TEXT("Cannot load IP Sink\n"));
  617.         return hr;
  618.     }
  619.  
  620.     // render/connect the rest of the demux pins
  621.     hr = m_pDemux->EnumPins (&pIEnumPins);
  622.     if (FAILED (hr))
  623.     {
  624.         ErrorMessageBox(TEXT("Cannot get the enumpins\n"));
  625.         return hr;
  626.     }
  627.  
  628.     while(pIEnumPins->Next(1, &pIPin, 0) == S_OK)
  629.     {
  630.         hr = pIPin->QueryDirection(&direction);
  631.  
  632.         if(direction == PINDIR_OUTPUT)
  633.         {
  634.             pIPin->ConnectedTo (&pDownstreamPin);
  635.  
  636.             if(pDownstreamPin == NULL)
  637.             {
  638.                 m_pFilterGraph->Render (pIPin);
  639.             }
  640.  
  641.             pDownstreamPin = NULL;
  642.         }
  643.         pIPin = NULL;
  644.     }
  645.  
  646.     return hr;
  647. }
  648.  
  649.  
  650. // removes each filter from the graph
  651. HRESULT
  652. CBDAFilterGraph::TearDownGraph()
  653. {
  654.     HRESULT hr = S_OK;
  655.     CComPtr <IBaseFilter> pFilter;
  656.     CComPtr <IEnumFilters> pIFilterEnum;
  657.  
  658.     m_pITuningSpace = NULL;
  659.  
  660.     if(m_fGraphBuilt || m_fGraphFailure)
  661.     {
  662.         // unload manually added filters
  663.         m_pFilterGraph->RemoveFilter(m_pIPSink);
  664.         m_pFilterGraph->RemoveFilter(m_pMPE);
  665.         m_pFilterGraph->RemoveFilter(m_pTIF);
  666.         m_pFilterGraph->RemoveFilter(m_pDemux);
  667.         m_pFilterGraph->RemoveFilter(m_pNetworkProvider);
  668.         m_pFilterGraph->RemoveFilter(m_pTunerDevice);
  669.         m_pFilterGraph->RemoveFilter(m_pCaptureDevice);
  670.  
  671.         m_pIPSink = NULL;
  672.         m_pMPE = NULL;
  673.         m_pTIF = NULL;
  674.         m_pDemux = NULL;
  675.         m_pNetworkProvider = NULL;
  676.         m_pTunerDevice = NULL;
  677.         m_pDemodulatorDevice = NULL;
  678.         m_pCaptureDevice = NULL;
  679.  
  680.         // now go unload rendered filters
  681.         hr = m_pFilterGraph->EnumFilters(&pIFilterEnum);
  682.  
  683.         if(FAILED(hr))
  684.         {
  685.             ErrorMessageBox(TEXT("TearDownGraph: cannot EnumFilters\n"));
  686.             return E_FAIL;
  687.         }
  688.  
  689.         pIFilterEnum->Reset();
  690.  
  691.         while(pIFilterEnum->Next(1, &pFilter, 0) == S_OK) // addrefs filter
  692.         {
  693.             hr = m_pFilterGraph->RemoveFilter(pFilter);
  694.  
  695.             if (FAILED (hr))
  696.                 return hr;
  697.  
  698.             pIFilterEnum->Reset();
  699.             pFilter.Release ();
  700.         }
  701.     }
  702.  
  703. #ifdef DEBUG
  704.     if (m_dwGraphRegister)
  705.     {
  706.         RemoveGraphFromRot(m_dwGraphRegister);
  707.         m_dwGraphRegister = 0;
  708.     }
  709. #endif
  710.  
  711.     m_fGraphBuilt = FALSE;
  712.     return S_OK;
  713. }
  714.  
  715.  
  716. // ConnectFilters is called from BuildGraph
  717. // to enumerate and connect pins
  718. HRESULT
  719. CBDAFilterGraph::ConnectFilters(
  720.     IBaseFilter* pFilterUpstream, 
  721.     IBaseFilter* pFilterDownstream
  722.     )
  723. {
  724.     HRESULT         hr = E_FAIL;
  725.  
  726.     CComPtr <IPin>  pIPinUpstream;
  727.  
  728.  
  729.     PIN_INFO        PinInfoUpstream;
  730.     PIN_INFO        PinInfoDownstream;
  731.  
  732.     // validate passed in filters
  733.     ASSERT (pFilterUpstream);
  734.     ASSERT (pFilterDownstream);
  735.  
  736.     // grab upstream filter's enumerator
  737.     CComPtr <IEnumPins> pIEnumPinsUpstream;
  738.     hr = pFilterUpstream->EnumPins(&pIEnumPinsUpstream);
  739.  
  740.     if(FAILED(hr))
  741.     {
  742.         ErrorMessageBox(TEXT("Cannot Enumerate Upstream Filter's Pins\n"));
  743.         return hr;
  744.     }
  745.  
  746.     // iterate through upstream filter's pins
  747.     while (pIEnumPinsUpstream->Next (1, &pIPinUpstream, 0) == S_OK)
  748.     {
  749.         hr = pIPinUpstream->QueryPinInfo (&PinInfoUpstream);
  750.         if(FAILED(hr))
  751.         {
  752.             ErrorMessageBox(TEXT("Cannot Obtain Upstream Filter's PIN_INFO\n"));
  753.             return hr;
  754.         }
  755.  
  756.         CComPtr <IPin>  pPinDown;
  757.         pIPinUpstream->ConnectedTo (&pPinDown);
  758.  
  759.         // bail if pins are connected
  760.         // otherwise check direction and connect
  761.         if ((PINDIR_OUTPUT == PinInfoUpstream.dir) && (pPinDown == NULL))
  762.         {
  763.             // grab downstream filter's enumerator
  764.             CComPtr <IEnumPins> pIEnumPinsDownstream;
  765.             hr = pFilterDownstream->EnumPins (&pIEnumPinsDownstream);
  766.  
  767.             // iterate through downstream filter's pins
  768.             CComPtr <IPin>  pIPinDownstream;
  769.             while (pIEnumPinsDownstream->Next (1, &pIPinDownstream, 0) == S_OK)
  770.             {
  771.                 // make sure it is an input pin
  772.                 hr = pIPinDownstream->QueryPinInfo(&PinInfoDownstream);
  773.                 if(SUCCEEDED(hr))
  774.                 {
  775.                     CComPtr <IPin>  pPinUp;
  776.                     pIPinDownstream->ConnectedTo (&pPinUp);
  777.  
  778.                     if ((PINDIR_INPUT == PinInfoDownstream.dir) && (pPinUp == NULL))
  779.                     {
  780.                         if (SUCCEEDED (m_pFilterGraph->Connect(
  781.                                         pIPinUpstream,
  782.                                         pIPinDownstream))
  783.                                         )
  784.                         {
  785.                             PinInfoDownstream.pFilter->Release();
  786.                             PinInfoUpstream.pFilter->Release();
  787.                             return S_OK;
  788.                         }
  789.                     }
  790.                 }
  791.  
  792.                 PinInfoDownstream.pFilter->Release();
  793.                 pIPinDownstream = NULL;
  794.             } // while next downstream filter pin
  795.  
  796.             //We are now back into the upstream pin loop
  797.         } // if output pin
  798.  
  799.         pIPinUpstream = NULL;
  800.         PinInfoUpstream.pFilter->Release();
  801.     } // while next upstream filter pin
  802.  
  803.     return E_FAIL;
  804. }
  805.  
  806.  
  807. // RunGraph checks to see if a graph has been built
  808. // if not it calls BuildGraph
  809. // RunGraph then calls MediaCtrl-Run
  810. HRESULT
  811. CBDAFilterGraph::RunGraph()
  812. {
  813.     // check to see if the graph is already running
  814.     if(m_fGraphRunning)
  815.         return S_OK;
  816.  
  817.     HRESULT hr = S_OK;
  818.     if (m_pIMediaControl == NULL)
  819.         hr = m_pFilterGraph.QueryInterface (&m_pIMediaControl);
  820.  
  821.     if (SUCCEEDED (hr))
  822.     {
  823.         // run the graph
  824.         hr = m_pIMediaControl->Run();
  825.         if(SUCCEEDED(hr))
  826.         {
  827.             m_fGraphRunning = true;
  828.         }
  829.         else
  830.         {
  831.             // stop parts of the graph that ran
  832.             m_pIMediaControl->Stop();
  833.             ErrorMessageBox(TEXT("Cannot run graph\n"));
  834.         }
  835.     }
  836.  
  837.     return hr;
  838. }
  839.  
  840.  
  841. // StopGraph calls MediaCtrl - Stop
  842. HRESULT
  843. CBDAFilterGraph::StopGraph()
  844. {
  845.     // check to see if the graph is already stopped
  846.     if(m_fGraphRunning == false)
  847.         return S_OK;
  848.  
  849.     HRESULT hr = S_OK;
  850.  
  851.     ASSERT (m_pIMediaControl);
  852.     // pause before stopping
  853.     hr = m_pIMediaControl->Pause();
  854.  
  855.     // stop the graph
  856.     hr = m_pIMediaControl->Stop();
  857.  
  858.     m_fGraphRunning = (FAILED (hr))?true:false;
  859.     return hr;
  860. }
  861.  
  862. // Set our client area for viewing
  863. //
  864. // Note, what you're not seeing here is a call to
  865. // IAMSreamCconfig's GetFormat to obtain the video
  866. // format properties that would enable us to set
  867. // the viewing window's size
  868. HRESULT
  869. CBDAFilterGraph::SetVideoWindow(
  870.         HWND hwndMain
  871.         )
  872. {
  873.     CComPtr <IVideoWindow>  pVideoWindow;
  874.     RECT                    rc;
  875.     INT                     cyBorder;
  876.     INT                     cy;
  877.     HRESULT                 hr = S_OK;
  878.  
  879.     // get IVideoWindow interface
  880.     hr = m_pFilterGraph->QueryInterface (&pVideoWindow);
  881.     if (FAILED (hr))
  882.     {
  883.         ErrorMessageBox(TEXT("QueryInterface IVideoWindow Failed\n"));
  884.         return hr;
  885.     }
  886.  
  887.     hr = pVideoWindow->put_Owner (reinterpret_cast <LONG> (hwndMain));
  888.     if (FAILED (hr))
  889.     {
  890.         ErrorMessageBox(TEXT("Unable to set video window\n"));
  891.         return hr;
  892.     }
  893.  
  894.     hr = pVideoWindow->put_WindowStyle (WS_CHILD);
  895.     if (FAILED (hr))
  896.     {
  897.         ErrorMessageBox(TEXT("Unable to set the style for the video window\n"));
  898.         return hr;
  899.     }
  900.  
  901.     GetClientRect(hwndMain, &rc);
  902.     cyBorder = GetSystemMetrics(SM_CYBORDER);
  903.     cy = cyBorder;
  904.     rc.bottom -= cy;
  905.     hr = pVideoWindow->SetWindowPosition(
  906.                             0, 
  907.                             0, 
  908.                             rc.right, 
  909.                             rc.bottom
  910.                             );
  911.     hr = pVideoWindow->put_Visible (OATRUE);
  912.  
  913.     return hr;
  914. }
  915.  
  916. HRESULT
  917. CBDAFilterGraph::ChangeChannel(
  918.         LONG lMajorChannel, 
  919.         LONG lMinorChannel
  920.         )
  921. {
  922.     HRESULT hr = S_OK;
  923.     m_lMajorChannel = lMajorChannel;
  924.     m_lMinorChannel = lMinorChannel;
  925.  
  926.     CComPtr <IScanningTuner> pIScanningTuner;
  927.  
  928.     if (!m_pNetworkProvider)
  929.     {
  930.         ErrorMessageBox(TEXT("The FilterGraph is not yet built.\n"));
  931.         return E_FAIL;
  932.     }
  933.  
  934.     hr = m_pNetworkProvider.QueryInterface (&pIScanningTuner);
  935.     if (FAILED(hr))
  936.     {
  937.         ErrorMessageBox(TEXT("Cannot QI for IScanningTuner\n"));
  938.         return hr;
  939.     }
  940.  
  941.  
  942.     // create tune request
  943.     CComPtr <IATSCChannelTuneRequest> pTuneRequest;
  944.     hr = CreateATSCTuneRequest(
  945.         m_lPhysicalChannel, 
  946.         lMajorChannel, 
  947.         lMinorChannel,
  948.         &pTuneRequest
  949.         );
  950.  
  951.     if(SUCCEEDED(hr))
  952.     {
  953.         hr = m_pITuner->put_TuneRequest (pTuneRequest);
  954.         if (FAILED (hr))
  955.             ErrorMessageBox(TEXT("Cannot submit tune request\n"));
  956.     }
  957.     else
  958.     {
  959.         ErrorMessageBox(TEXT("Cannot Change Channels\n"));
  960.     }
  961.  
  962.     return hr;
  963. }
  964.  
  965.  
  966. //
  967. // USE THE CODE BELOW IF YOU WANT TO MANUALLY LOAD AND
  968. // CONNECT A/V DECODERS TO THE DEMUX OUTPUT PINS
  969. //
  970.  
  971. /*
  972. To use this code:
  973. 1) in LoadAudioDecoder() and LoadVideoDecoder(), fill in decoder specific information (clsid)
  974. 2) goto BuildGraph() and replace RenderDemux() with BuildAVSegment()
  975. */
  976.  
  977. /*
  978. // Builds the Audio, Video segment of the digital TV graph.
  979. // Demux -> AV Decoder -> OVMixer -> Video Renderer
  980. HRESULT
  981. CBDAFilterGraph::BuildAVSegment()
  982. {
  983.     HRESULT hr = E_FAIL;
  984.  
  985.     // connect the demux to the capture device
  986.     hr = ConnectFilters(m_pCaptureDevice, m_pDemux);
  987.  
  988.     hr = LoadVideoDecoder();
  989.  
  990.     if(SUCCEEDED(hr) && m_pVideoDecoder)
  991.     {
  992.         // Connect the demux & video decoder
  993.         hr = ConnectFilters(m_pDemux, m_pVideoDecoder);
  994.  
  995.         if(FAILED(hr))
  996.         {
  997.             ErrorMessageBox("Connecting Demux & Video Decoder Failed\n");
  998.             goto err;
  999.         }
  1000.     }
  1001.     else
  1002.     {
  1003.         //ErrorMessageBox("Unable to load Video Decoder\n");
  1004.         goto err;
  1005.     }
  1006.  
  1007.     //Audio
  1008.     hr = LoadAudioDecoder();
  1009.  
  1010.     if(SUCCEEDED(hr) && m_pAudioDecoder)
  1011.     {
  1012.         hr = ConnectFilters(m_pDemux, m_pAudioDecoder);
  1013.  
  1014.         if(FAILED(hr))
  1015.         {
  1016.             ErrorMessageBox("Connecting Deumx & Audio Decoder Failed\n");
  1017.             goto err;
  1018.         }
  1019.     }
  1020.     else
  1021.     {
  1022.         ErrorMessageBox("Unable to load Audio Decoder\n");
  1023.         goto err;
  1024.     }
  1025.  
  1026.     // Create the OVMixer & Video Renderer for the video segment
  1027.     hr = CoCreateInstance(CLSID_OverlayMixer, NULL, CLSCTX_INPROC_SERVER,
  1028.             IID_IBaseFilter, reinterpret_cast<void**>(&m_pOVMixer));
  1029.  
  1030.     if(SUCCEEDED(hr) && m_pOVMixer)
  1031.     {
  1032.         hr = m_pFilterGraph->AddFilter(m_pOVMixer, L"OVMixer");
  1033.  
  1034.         if(FAILED(hr))
  1035.         {
  1036.             ErrorMessageBox("Adding OVMixer to the FilterGraph Failed\n");
  1037.             goto err;
  1038.         }
  1039.     }
  1040.     else
  1041.     {
  1042.         ErrorMessageBox("Loading OVMixer Failed\n");
  1043.         goto err;
  1044.     }
  1045.  
  1046.     hr = CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
  1047.             IID_IBaseFilter, reinterpret_cast<void**>(&m_pVRenderer));
  1048.  
  1049.     if(SUCCEEDED(hr) && m_pVRenderer)
  1050.     {
  1051.         hr = m_pFilterGraph->AddFilter(m_pVRenderer, L"Video Renderer");
  1052.  
  1053.         if(FAILED(hr))
  1054.         {
  1055.             ErrorMessageBox("Adding Video Renderer to the FilterGraph Failed\n");
  1056.             goto err;
  1057.         }
  1058.     }
  1059.     else
  1060.     {
  1061.         ErrorMessageBox("Loading Video Renderer Failed\n");
  1062.         goto err;
  1063.     }
  1064.  
  1065.     // Split AV Decoder? Then add Default DirectSound Renderer to the filtergraph
  1066.     if(m_pVideoDecoder != m_pAudioDecoder)
  1067.     {
  1068.         hr = CoCreateInstance(CLSID_DSoundRender, NULL,
  1069.                         CLSCTX_INPROC_SERVER, IID_IBaseFilter,
  1070.                         reinterpret_cast<void**>(&m_pDDSRenderer));
  1071.  
  1072.         if(SUCCEEDED(hr) && m_pDDSRenderer)
  1073.         {
  1074.             hr = m_pFilterGraph->AddFilter(m_pDDSRenderer, L"Sound Renderer");
  1075.  
  1076.             if(FAILED(hr))
  1077.             {
  1078.                 ErrorMessageBox("Adding DirectSound Device to the FilterGraph Failed\n");
  1079.                 goto err;
  1080.             }
  1081.         }
  1082.         else
  1083.         {
  1084.             ErrorMessageBox("Loading DirectSound Device Failed\n");
  1085.             goto err;
  1086.         }
  1087.     }
  1088.  
  1089.     hr = ConnectFilters(m_pVideoDecoder, m_pOVMixer);
  1090.  
  1091.     if(FAILED(hr))
  1092.     {
  1093.         ErrorMessageBox("Connecting Capture & OVMixer Failed\n");
  1094.         goto err;
  1095.     }
  1096.  
  1097.     hr = ConnectFilters(m_pOVMixer, m_pVRenderer);
  1098.  
  1099.     if(FAILED(hr))
  1100.     {
  1101.         ErrorMessageBox("Connecting OVMixer & Video Renderer Failed\n");
  1102.         goto err;
  1103.     }
  1104.  
  1105.     // Split AV Decoder & if you need audio too ?? then connect Audio decoder to Sound Renderer
  1106.     if(m_pVideoDecoder != m_pAudioDecoder)
  1107.     {
  1108.         hr = ConnectFilters(m_pAudioDecoder, m_pDDSRenderer);
  1109.  
  1110.         if(FAILED(hr))
  1111.         {
  1112.             ErrorMessageBox("Connecting AudioDecoder & DirectSound Device Failed\n");
  1113.             goto err;
  1114.         }
  1115.     }
  1116.  
  1117. err:
  1118.     return hr;
  1119. }
  1120.  
  1121. // placeholders for real decoders
  1122. DEFINE_GUID(CLSID_FILL_IN_NAME_AUDIO_DECODER, 0xFEEDFEED, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1123. 0x00);
  1124. DEFINE_GUID(CLSID_FILL_IN_NAME_VIDEO_DECODER, 0xFEEDFEED, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1125. 0x00);
  1126.  
  1127. HRESULT
  1128. CBDAFilterGraph::LoadVideoDecoder()
  1129. {
  1130.     HRESULT hr = E_FAIL;
  1131.  
  1132.     hr = CoCreateInstance(CLSID_FILL_IN_NAME_VIDEO_DECODER, NULL,
  1133.             CLSCTX_INPROC_SERVER, IID_IBaseFilter,
  1134.             reinterpret_cast<void**>(&m_pVideoDecoder));
  1135.  
  1136.     if(SUCCEEDED(hr) && m_pVideoDecoder)
  1137.     {
  1138.         hr = m_pFilterGraph->AddFilter(m_pVideoDecoder, L"Video Decoder");
  1139.  
  1140.         if(FAILED(hr))
  1141.         {
  1142.             ErrorMessageBox("Unable to add Video Decoder filter to graph\n");
  1143.         }
  1144.     }
  1145.  
  1146.     return hr;
  1147. }
  1148.  
  1149.  
  1150. HRESULT
  1151. CBDAFilterGraph::LoadAudioDecoder()
  1152. {
  1153.     HRESULT hr = E_FAIL;
  1154.  
  1155.     hr = CoCreateInstance(CLSID_FILL_IN_NAME_AUDIO_DECODER, NULL,
  1156.             CLSCTX_INPROC_SERVER, IID_IBaseFilter,
  1157.             reinterpret_cast<void**>(&m_pAudioDecoder));
  1158.  
  1159.     if(SUCCEEDED(hr) && m_pAudioDecoder)
  1160.     {
  1161.         hr = m_pFilterGraph->AddFilter(m_pAudioDecoder, L"Audio Decoder");
  1162.  
  1163.         if(FAILED(hr))
  1164.         {
  1165.             ErrorMessageBox("Unable to add Audio filter to graph\n");
  1166.         }
  1167.     }
  1168.  
  1169.     return hr;
  1170. }
  1171.  
  1172. */
  1173.  
  1174. // Adds a DirectShow filter graph to the Running Object Table,
  1175. // allowing GraphEdit to "spy" on a remote filter graph.
  1176. HRESULT CBDAFilterGraph::AddGraphToRot(
  1177.         IUnknown *pUnkGraph, 
  1178.         DWORD *pdwRegister
  1179.         ) 
  1180. {
  1181.     CComPtr <IMoniker>              pMoniker;
  1182.     CComPtr <IRunningObjectTable>   pROT;
  1183.     WCHAR wsz[128];
  1184.     HRESULT hr;
  1185.  
  1186.     if (FAILED(GetRunningObjectTable(0, &pROT)))
  1187.         return E_FAIL;
  1188.  
  1189.     wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, 
  1190.               GetCurrentProcessId());
  1191.  
  1192.     hr = CreateItemMoniker(L"!", wsz, &pMoniker);
  1193.     if (SUCCEEDED(hr)) 
  1194.         hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
  1195.     return hr;
  1196. }
  1197.  
  1198. // Removes a filter graph from the Running Object Table
  1199. void CBDAFilterGraph::RemoveGraphFromRot(
  1200.         DWORD pdwRegister
  1201.         )
  1202. {
  1203.     CComPtr <IRunningObjectTable> pROT;
  1204.  
  1205.     if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) 
  1206.         pROT->Revoke(pdwRegister);
  1207.  
  1208. }
  1209.  
  1210.