home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / directshow / bda / bdasample / graph.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  32.7 KB  |  1,307 lines

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