bdagraph.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:65k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * bdagraph.cpp : DirectShow BDA graph for vlc
  3.  *****************************************************************************
  4.  * Copyright( C ) 2007 the VideoLAN team
  5.  *
  6.  * Author: Ken Self <kenself(at)optusnet(dot)com(dot)au>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  *( at your option ) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  21.  *****************************************************************************/
  22. /*****************************************************************************
  23.  * Preamble
  24.  *****************************************************************************/
  25. #include "bdagraph.h"
  26. #include <ctype.h>
  27. /****************************************************************************
  28.  * Interfaces for calls from C
  29.  ****************************************************************************/
  30. extern "C" {
  31.     void dvb_newBDAGraph( access_t* p_access )
  32.     {
  33.         p_access->p_sys->p_bda_module = new BDAGraph( p_access );
  34.     };
  35.     void dvb_deleteBDAGraph( access_t* p_access )
  36.     {
  37.         delete p_access->p_sys->p_bda_module;
  38.     };
  39.     int dvb_SubmitATSCTuneRequest( access_t* p_access )
  40.     {
  41.         if( p_access->p_sys->p_bda_module )
  42.             return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
  43.         return VLC_EGENERIC;
  44.     };
  45.     int dvb_SubmitDVBTTuneRequest( access_t* p_access )
  46.     {
  47.         if( p_access->p_sys->p_bda_module )
  48.             return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
  49.         return VLC_EGENERIC;
  50.     };
  51.     int dvb_SubmitDVBCTuneRequest( access_t* p_access )
  52.     {
  53.         if( p_access->p_sys->p_bda_module )
  54.             return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
  55.         return VLC_EGENERIC;
  56.     };
  57.     int dvb_SubmitDVBSTuneRequest( access_t* p_access )
  58.     {
  59.         if( p_access->p_sys->p_bda_module )
  60.             return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
  61.         return VLC_EGENERIC;
  62.     };
  63.     block_t *dvb_Pop( access_t* p_access )
  64.     {
  65.         if( p_access->p_sys->p_bda_module )
  66.             return p_access->p_sys->p_bda_module->Pop();
  67.         return NULL;
  68.     };
  69. };
  70. /*****************************************************************************
  71. * BDAOutput
  72. *****************************************************************************/
  73. BDAOutput::BDAOutput( access_t *p_access ) :
  74.     p_access(p_access), p_first(NULL), pp_next(&p_first)
  75. {
  76.     vlc_mutex_init( &lock );
  77.     vlc_cond_init( &wait );
  78. }
  79. BDAOutput::~BDAOutput()
  80. {
  81.     Empty();
  82.     vlc_mutex_destroy( &lock );
  83.     vlc_cond_destroy( &wait );
  84. }
  85. void BDAOutput::Push( block_t *p_block )
  86. {
  87.     vlc_mutex_locker l( &lock );
  88.     block_ChainLastAppend( &pp_next, p_block );
  89.     vlc_cond_signal( &wait );
  90. }
  91. block_t *BDAOutput::Pop()
  92. {
  93.     vlc_mutex_locker l( &lock );
  94.     if( !p_first )
  95.         vlc_cond_timedwait( &wait, &lock, mdate() + 250*1000 );
  96.     block_t *p_ret = p_first;
  97.     p_first = NULL;
  98.     pp_next = &p_first;
  99.     return p_ret;
  100. }
  101. void BDAOutput::Empty()
  102. {
  103.     vlc_mutex_locker l( &lock );
  104.     if( p_first )
  105.         block_ChainRelease( p_first );
  106.     p_first = NULL;
  107.     pp_next = &p_first;
  108. }
  109. /*****************************************************************************
  110. * Constructor
  111. *****************************************************************************/
  112. BDAGraph::BDAGraph( access_t* p_this ):
  113.     p_access( p_this ),
  114.     guid_network_type(GUID_NULL),
  115.     l_tuner_used(-1),
  116.     d_graph_register( 0 ),
  117.     output( p_this )
  118. {
  119.     p_tuning_space = NULL;
  120.     p_tune_request = NULL;
  121.     p_media_control = NULL;
  122.     p_filter_graph = NULL;
  123.     p_system_dev_enum = NULL;
  124.     p_network_provider = p_tuner_device = p_capture_device = NULL;
  125.     p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
  126.     p_scanning_tuner = NULL;
  127.     p_grabber = NULL;
  128.     /* Initialize COM - MS says to use CoInitializeEx in preference to
  129.      * CoInitialize */
  130.     CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
  131. }
  132. /*****************************************************************************
  133. * Destructor
  134. *****************************************************************************/
  135. BDAGraph::~BDAGraph()
  136. {
  137.     Destroy();
  138.     CoUninitialize();
  139. }
  140. /*****************************************************************************
  141. * Submit an ATSC Tune Request
  142. *****************************************************************************/
  143. int BDAGraph::SubmitATSCTuneRequest()
  144. {
  145.     HRESULT hr = S_OK;
  146.     class localComPtr
  147.     {
  148.         public:
  149.         IATSCChannelTuneRequest* p_atsc_tune_request;
  150.         IATSCLocator* p_atsc_locator;
  151.         localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
  152.         ~localComPtr()
  153.         {
  154.             if( p_atsc_tune_request )
  155.                 p_atsc_tune_request->Release();
  156.             if( p_atsc_locator )
  157.                 p_atsc_locator->Release();
  158.         }
  159.     } l;
  160.     long l_major_channel, l_minor_channel, l_physical_channel;
  161.     long l_frequency;
  162.     l_major_channel     = var_GetInteger( p_access, "dvb-major-channel" );
  163.     l_minor_channel     = var_GetInteger( p_access, "dvb-minor-channel" );
  164.     l_physical_channel  = var_GetInteger( p_access, "dvb-physical-channel" );
  165.     l_frequency         = var_GetInteger( p_access, "dvb-frequency" );
  166.     guid_network_type = CLSID_ATSCNetworkProvider;
  167.     hr = CreateTuneRequest();
  168.     if( FAILED( hr ) )
  169.     {
  170.         msg_Warn( p_access, "SubmitATSCTuneRequest: "
  171.             "Cannot create Tuning Space: hr=0x%8lx", hr );
  172.         return VLC_EGENERIC;
  173.     }
  174.     hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
  175.         (void**)&l.p_atsc_tune_request );
  176.     if( FAILED( hr ) )
  177.     {
  178.         msg_Warn( p_access, "SubmitATSCTuneRequest: "
  179.             "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
  180.         return VLC_EGENERIC;
  181.     }
  182.     hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
  183.                              IID_IATSCLocator, (void**)&l.p_atsc_locator );
  184.     if( FAILED( hr ) )
  185.     {
  186.         msg_Warn( p_access, "SubmitATSCTuneRequest: "
  187.             "Cannot create the ATSC locator: hr=0x%8lx", hr );
  188.         return VLC_EGENERIC;
  189.     }
  190.     hr = S_OK;
  191.     if( l_frequency > 0 )
  192.         hr = l.p_atsc_locator->put_CarrierFrequency( l_frequency );
  193.     if( l_major_channel > 0 )
  194.         hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
  195.     if( SUCCEEDED( hr ) && l_minor_channel > 0 )
  196.         hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
  197.     if( SUCCEEDED( hr ) && l_physical_channel > 0 )
  198.         hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
  199.     if( FAILED( hr ) )
  200.     {
  201.         msg_Warn( p_access, "SubmitATSCTuneRequest: "
  202.             "Cannot set tuning parameters: hr=0x%8lx", hr );
  203.         return VLC_EGENERIC;
  204.     }
  205.     hr = p_tune_request->put_Locator( l.p_atsc_locator );
  206.     if( FAILED( hr ) )
  207.     {
  208.         msg_Warn( p_access, "SubmitATSCTuneRequest: "
  209.             "Cannot put the locator: hr=0x%8lx", hr );
  210.         return VLC_EGENERIC;
  211.     }
  212.     /* Build and Run the Graph. If a Tuner device is in use the graph will
  213.      * fail to run. Repeated calls to build will check successive tuner
  214.      * devices */
  215.     do
  216.     {
  217.         hr = Build();
  218.         if( FAILED( hr ) )
  219.         {
  220.             msg_Warn( p_access, "SubmitATSCTuneRequest: "
  221.                 "Cannot Build the Graph: hr=0x%8lx", hr );
  222.             return VLC_EGENERIC;
  223.         }
  224.         hr = Start();
  225.     }
  226.     while( hr != S_OK );
  227.     return VLC_SUCCESS;
  228. }
  229. /*****************************************************************************
  230. * Submit a DVB-T Tune Request
  231. ******************************************************************************/
  232. int BDAGraph::SubmitDVBTTuneRequest()
  233. {
  234.     HRESULT hr = S_OK;
  235.     class localComPtr
  236.     {
  237.         public:
  238.         IDVBTuneRequest* p_dvbt_tune_request;
  239.         IDVBTLocator* p_dvbt_locator;
  240.         IDVBTuningSpace2* p_dvb_tuning_space;
  241.         localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL),
  242.            p_dvb_tuning_space(NULL) {};
  243.         ~localComPtr()
  244.         {
  245.             if( p_dvbt_tune_request )
  246.                 p_dvbt_tune_request->Release();
  247.             if( p_dvbt_locator )
  248.                 p_dvbt_locator->Release();
  249.             if( p_dvb_tuning_space )
  250.                 p_dvb_tuning_space->Release();
  251.         }
  252.     } l;
  253.     long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
  254.     long l_transmission, l_hierarchy;
  255.     BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
  256.     GuardInterval             i_guard;
  257.     TransmissionMode          i_transmission;
  258.     HierarchyAlpha            i_hierarchy;
  259.     l_frequency    = var_GetInteger( p_access, "dvb-frequency" ) / 1000;
  260.     l_bandwidth    = var_GetInteger( p_access, "dvb-bandwidth" );
  261.     l_hp_fec       = var_GetInteger( p_access, "dvb-code-rate-hp" );
  262.     l_lp_fec       = var_GetInteger( p_access, "dvb-code-rate-lp" );
  263.     l_guard        = var_GetInteger( p_access, "dvb-guard" );
  264.     l_transmission = var_GetInteger( p_access, "dvb-transmission" );
  265.     l_hierarchy    = var_GetInteger( p_access, "dvb-hierarchy" );
  266.     switch( l_hp_fec )
  267.     {
  268.     case 1:
  269.         i_hp_fec = BDA_BCC_RATE_1_2; break;
  270.     case 2:
  271.         i_hp_fec = BDA_BCC_RATE_2_3; break;
  272.     case 3:
  273.         i_hp_fec = BDA_BCC_RATE_3_4; break;
  274.     case 4:
  275.         i_hp_fec = BDA_BCC_RATE_5_6; break;
  276.     case 5:
  277.         i_hp_fec = BDA_BCC_RATE_7_8;break;
  278.     default:
  279.         i_hp_fec = BDA_BCC_RATE_NOT_SET;
  280.     }
  281.     switch( l_lp_fec )
  282.     {
  283.     case 1:
  284.         i_lp_fec = BDA_BCC_RATE_1_2; break;
  285.     case 2:
  286.         i_lp_fec = BDA_BCC_RATE_2_3; break;
  287.     case 3:
  288.         i_lp_fec = BDA_BCC_RATE_3_4; break;
  289.     case 4:
  290.         i_lp_fec = BDA_BCC_RATE_5_6; break;
  291.     case 5:
  292.         i_lp_fec = BDA_BCC_RATE_7_8; break;
  293.     default:
  294.         i_lp_fec = BDA_BCC_RATE_NOT_SET;
  295.     }
  296.     switch( l_guard )
  297.     {
  298.     case 32:
  299.         i_guard = BDA_GUARD_1_32; break;
  300.     case 16:
  301.         i_guard = BDA_GUARD_1_16; break;
  302.     case 8:
  303.         i_guard = BDA_GUARD_1_8; break;
  304.     case 4:
  305.         i_guard = BDA_GUARD_1_4; break;
  306.     default:
  307.         i_guard = BDA_GUARD_NOT_SET;
  308.     }
  309.     switch( l_transmission )
  310.     {
  311.     case 2:
  312.         i_transmission = BDA_XMIT_MODE_2K; break;
  313.     case 8:
  314.         i_transmission = BDA_XMIT_MODE_8K; break;
  315.     default:
  316.         i_transmission = BDA_XMIT_MODE_NOT_SET;
  317.     }
  318.     switch( l_hierarchy )
  319.     {
  320.     case 1:
  321.         i_hierarchy = BDA_HALPHA_1; break;
  322.     case 2:
  323.         i_hierarchy = BDA_HALPHA_2; break;
  324.     case 4:
  325.         i_hierarchy = BDA_HALPHA_4; break;
  326.     default:
  327.         i_hierarchy = BDA_HALPHA_NOT_SET;
  328.     }
  329.     guid_network_type = CLSID_DVBTNetworkProvider;
  330.     hr = CreateTuneRequest();
  331.     if( FAILED( hr ) )
  332.     {
  333.         msg_Warn( p_access, "SubmitDVBTTuneRequest: "
  334.             "Cannot create Tune Request: hr=0x%8lx", hr );
  335.         return VLC_EGENERIC;
  336.     }
  337.     hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
  338.         (void**)&l.p_dvbt_tune_request );
  339.     if( FAILED( hr ) )
  340.     {
  341.         msg_Warn( p_access, "SubmitDVBTTuneRequest: "
  342.             "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
  343.         return VLC_EGENERIC;
  344.     }
  345.     l.p_dvbt_tune_request->put_ONID( -1 );
  346.     l.p_dvbt_tune_request->put_SID( -1 );
  347.     l.p_dvbt_tune_request->put_TSID( -1 );
  348.     hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
  349.         IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
  350.     if( FAILED( hr ) )
  351.     {
  352.         msg_Warn( p_access, "SubmitDVBTTuneRequest: "
  353.             "Cannot create the DVBT Locator: hr=0x%8lx", hr );
  354.         return VLC_EGENERIC;
  355.     }
  356.     hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
  357.         (void**)&l.p_dvb_tuning_space );
  358.     if( FAILED( hr ) )
  359.     {
  360.         msg_Warn( p_access, "SubmitDVBTTuneRequest: "
  361.             "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
  362.         return VLC_EGENERIC;
  363.     }
  364.     hr = S_OK;
  365.     hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
  366.     if( SUCCEEDED( hr ) && l_frequency > 0 )
  367.         hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
  368.     if( SUCCEEDED( hr ) && l_bandwidth > 0 )
  369.         hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
  370.     if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
  371.         hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
  372.     if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
  373.         hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
  374.     if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
  375.         hr = l.p_dvbt_locator->put_Guard( i_guard );
  376.     if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
  377.         hr = l.p_dvbt_locator->put_Mode( i_transmission );
  378.     if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
  379.         hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
  380.     if( FAILED( hr ) )
  381.     {
  382.         msg_Warn( p_access, "SubmitDVBTTuneRequest: "
  383.             "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
  384.         return VLC_EGENERIC;
  385.     }
  386.     hr = p_tune_request->put_Locator( l.p_dvbt_locator );
  387.     if( FAILED( hr ) )
  388.     {
  389.         msg_Warn( p_access, "SubmitDVBTTuneRequest: "
  390.             "Cannot put the locator: hr=0x%8lx", hr );
  391.         return VLC_EGENERIC;
  392.     }
  393.     /* Build and Run the Graph. If a Tuner device is in use the graph will
  394.      * fail to run. Repeated calls to build will check successive tuner
  395.      * devices */
  396.     do
  397.     {
  398.         hr = Build();
  399.         if( FAILED( hr ) )
  400.         {
  401.             msg_Warn( p_access, "SubmitDVBTTuneRequest: "
  402.                 "Cannot Build the Graph: hr=0x%8lx", hr );
  403.             return VLC_EGENERIC;
  404.         }
  405.         hr = Start();
  406.     }
  407.     while( hr != S_OK );
  408.     return VLC_SUCCESS;
  409. }
  410. /*****************************************************************************
  411. * Submit a DVB-C Tune Request
  412. ******************************************************************************/
  413. int BDAGraph::SubmitDVBCTuneRequest()
  414. {
  415.     HRESULT hr = S_OK;
  416.     class localComPtr
  417.     {
  418.         public:
  419.         IDVBTuneRequest* p_dvbc_tune_request;
  420.         IDVBCLocator* p_dvbc_locator;
  421.         IDVBTuningSpace2* p_dvb_tuning_space;
  422.         localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL),
  423.                        p_dvb_tuning_space(NULL) {};
  424.         ~localComPtr()
  425.         {
  426.             if( p_dvbc_tune_request )
  427.                 p_dvbc_tune_request->Release();
  428.             if( p_dvbc_locator )
  429.                 p_dvbc_locator->Release();
  430.             if( p_dvb_tuning_space )
  431.                 p_dvb_tuning_space->Release();
  432.         }
  433.     } l;
  434.     long l_frequency, l_symbolrate;
  435.     int  i_qam;
  436.     ModulationType i_qam_mod;
  437.     l_frequency  = var_GetInteger( p_access, "dvb-frequency" ) / 1000;
  438.     l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
  439.     i_qam        = var_GetInteger( p_access, "dvb-modulation" );
  440.     switch( i_qam )
  441.     {
  442.     case 16:
  443.         i_qam_mod = BDA_MOD_16QAM; break;
  444.     case 32:
  445.         i_qam_mod = BDA_MOD_32QAM; break;
  446.     case 64:
  447.         i_qam_mod = BDA_MOD_64QAM; break;
  448.     case 128:
  449.         i_qam_mod = BDA_MOD_128QAM; break;
  450.     case 256:
  451.         i_qam_mod = BDA_MOD_256QAM; break;
  452.     default:
  453.         i_qam_mod = BDA_MOD_NOT_SET;
  454.     }
  455.     guid_network_type = CLSID_DVBCNetworkProvider;
  456.     hr = CreateTuneRequest();
  457.     if( FAILED( hr ) )
  458.     {
  459.         msg_Warn( p_access, "SubmitDVBCTuneRequest: "
  460.             "Cannot create Tune Request: hr=0x%8lx", hr );
  461.         return VLC_EGENERIC;
  462.     }
  463.     hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
  464.         (void**)&l.p_dvbc_tune_request );
  465.     if( FAILED( hr ) )
  466.     {
  467.         msg_Warn( p_access, "SubmitDVBCTuneRequest: "
  468.             "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
  469.         return VLC_EGENERIC;
  470.     }
  471.     l.p_dvbc_tune_request->put_ONID( -1 );
  472.     l.p_dvbc_tune_request->put_SID( -1 );
  473.     l.p_dvbc_tune_request->put_TSID( -1 );
  474.     hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
  475.         IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
  476.     if( FAILED( hr ) )
  477.     {
  478.         msg_Warn( p_access, "SubmitDVBCTuneRequest: "
  479.             "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
  480.         return VLC_EGENERIC;
  481.     }
  482.     hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
  483.         (void**)&l.p_dvb_tuning_space );
  484.     if( FAILED( hr ) )
  485.     {
  486.         msg_Warn( p_access, "SubmitDVBCTuneRequest: "
  487.             "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
  488.         return VLC_EGENERIC;
  489.     }
  490.     hr = S_OK;
  491.     hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
  492.     if( SUCCEEDED( hr ) && l_frequency > 0 )
  493.         hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
  494.     if( SUCCEEDED( hr ) && l_symbolrate > 0 )
  495.         hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
  496.     if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
  497.         hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
  498.     if( FAILED( hr ) )
  499.     {
  500.         msg_Warn( p_access, "SubmitDVBCTuneRequest: "
  501.             "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
  502.         return VLC_EGENERIC;
  503.     }
  504.     hr = p_tune_request->put_Locator( l.p_dvbc_locator );
  505.     if( FAILED( hr ) )
  506.     {
  507.         msg_Warn( p_access, "SubmitDVBCTuneRequest: "
  508.             "Cannot put the locator: hr=0x%8lx", hr );
  509.         return VLC_EGENERIC;
  510.     }
  511.     /* Build and Run the Graph. If a Tuner device is in use the graph will
  512.      * fail to run. Repeated calls to build will check successive tuner
  513.      * devices */
  514.     do
  515.     {
  516.         hr = Build();
  517.         if( FAILED( hr ) )
  518.         {
  519.             msg_Warn( p_access, "SubmitDVBCTuneRequest: "
  520.                 "Cannot Build the Graph: hr=0x%8lx", hr );
  521.             return VLC_EGENERIC;
  522.         }
  523.         hr = Start();
  524.     }
  525.     while( hr != S_OK );
  526.     return VLC_SUCCESS;
  527. }
  528. /*****************************************************************************
  529. * Submit a DVB-S Tune Request
  530. ******************************************************************************/
  531. int BDAGraph::SubmitDVBSTuneRequest()
  532. {
  533.     HRESULT hr = S_OK;
  534.     class localComPtr
  535.     {
  536.         public:
  537.         IDVBTuneRequest* p_dvbs_tune_request;
  538.         IDVBSLocator* p_dvbs_locator;
  539.         IDVBSTuningSpace* p_dvbs_tuning_space;
  540.         char* psz_polarisation;
  541.         char* psz_input_range;
  542.         BSTR bstr_input_range;
  543.         WCHAR* pwsz_input_range;
  544.         int i_range_len;
  545.         localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
  546.             p_dvbs_tuning_space(NULL), bstr_input_range(NULL),
  547.             pwsz_input_range(NULL), i_range_len(0), psz_polarisation(NULL),
  548.             psz_input_range(NULL) {};
  549.         ~localComPtr()
  550.         {
  551.             if( p_dvbs_tuning_space )
  552.                 p_dvbs_tuning_space->Release();
  553.             if( p_dvbs_tune_request )
  554.                 p_dvbs_tune_request->Release();
  555.             if( p_dvbs_locator )
  556.                 p_dvbs_locator->Release();
  557.             SysFreeString( bstr_input_range );
  558.             delete pwsz_input_range;
  559.             free( psz_input_range );
  560.             free( psz_polarisation );
  561.         }
  562.     } l;
  563.     long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
  564.     long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
  565.     long l_hp_fec;
  566.     int  i_mod;
  567.     Polarisation i_polar;
  568.     SpectralInversion i_inversion;
  569.     VARIANT_BOOL b_west;
  570.     BinaryConvolutionCodeRate i_hp_fec;
  571.     ModulationType i_mod_typ;
  572.     l_frequency        = var_GetInteger( p_access, "dvb-frequency" );
  573.     l_symbolrate       = var_GetInteger( p_access, "dvb-srate" );
  574.     l_azimuth          = var_GetInteger( p_access, "dvb-azimuth" );
  575.     l_elevation        = var_GetInteger( p_access, "dvb-elevation" );
  576.     l_longitude        = var_GetInteger( p_access, "dvb-longitude" );
  577.     l_lnb_lof1         = var_GetInteger( p_access, "dvb-lnb-lof1" );
  578.     l_lnb_lof2         = var_GetInteger( p_access, "dvb-lnb-lof2" );
  579.     l_lnb_slof         = var_GetInteger( p_access, "dvb-lnb-slof" );
  580.     i_mod              = var_GetInteger( p_access, "dvb-modulation" );
  581.     l_hp_fec           = var_GetInteger( p_access, "dvb-code-rate-hp" );
  582.     l_inversion        = var_GetInteger( p_access, "dvb-inversion" );
  583.     l_network_id       = var_GetInteger( p_access, "dvb-network-id" );
  584.     l.psz_input_range  = var_GetNonEmptyString( p_access, "dvb-range" );
  585.     l.psz_polarisation = var_GetNonEmptyString( p_access, "dvb-polarisation" );
  586.     b_west = ( l_longitude < 0 );
  587.     i_polar = BDA_POLARISATION_NOT_SET;
  588.     if( l.psz_polarisation != NULL )
  589.     {
  590.         switch( toupper( l.psz_polarisation[0] ) )
  591.         {
  592.         case 'H':
  593.             i_polar = BDA_POLARISATION_LINEAR_H;
  594.             break;
  595.         case 'V':
  596.             i_polar = BDA_POLARISATION_LINEAR_V;
  597.             break;
  598.         case 'L':
  599.             i_polar = BDA_POLARISATION_CIRCULAR_L;
  600.             break;
  601.         case 'R':
  602.             i_polar = BDA_POLARISATION_CIRCULAR_R;
  603.             break;
  604.         }
  605.     }
  606.     switch( l_inversion )
  607.     {
  608.     case 0:
  609.         i_inversion = BDA_SPECTRAL_INVERSION_NORMAL; break;
  610.     case 1:
  611.         i_inversion = BDA_SPECTRAL_INVERSION_INVERTED; break;
  612.     case 2:
  613.         i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC; break;
  614.     default:
  615.         i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
  616.     }
  617.     switch( i_mod )
  618.     {
  619.     case 16:
  620.         i_mod_typ = BDA_MOD_16QAM; break;
  621.     case 128:
  622.         i_mod_typ = BDA_MOD_128QAM; break;
  623.     case 256:
  624.         i_mod_typ = BDA_MOD_256QAM; break;
  625.     case 10004:
  626.         i_mod_typ = BDA_MOD_QPSK; break;
  627.     default:
  628.         i_mod_typ = BDA_MOD_NOT_SET;
  629.     }
  630.     switch( l_hp_fec )
  631.     {
  632.     case 1:
  633.         i_hp_fec = BDA_BCC_RATE_1_2; break;
  634.     case 2:
  635.         i_hp_fec = BDA_BCC_RATE_2_3; break;
  636.     case 3:
  637.         i_hp_fec = BDA_BCC_RATE_3_4; break;
  638.     case 4:
  639.         i_hp_fec = BDA_BCC_RATE_5_6; break;
  640.     case 5:
  641.         i_hp_fec = BDA_BCC_RATE_7_8; break;
  642.     default:
  643.         i_hp_fec = BDA_BCC_RATE_NOT_SET;
  644.     }
  645.     l.i_range_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  646.         l.psz_input_range, -1, l.pwsz_input_range, 0 );
  647.     if( l.i_range_len > 0 )
  648.     {
  649.         l.pwsz_input_range = new WCHAR[l.i_range_len];
  650.         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  651.             l.psz_input_range, -1, l.pwsz_input_range, l.i_range_len );
  652.         l.bstr_input_range=SysAllocString( l.pwsz_input_range );
  653.     }
  654.     guid_network_type = CLSID_DVBSNetworkProvider;
  655.     hr = CreateTuneRequest();
  656.     if( FAILED( hr ) )
  657.     {
  658.         msg_Warn( p_access, "SubmitDVBSTuneRequest: "
  659.             "Cannot create Tune Request: hr=0x%8lx", hr );
  660.         return VLC_EGENERIC;
  661.     }
  662.     hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
  663.         (void**)&l.p_dvbs_tune_request );
  664.     if( FAILED( hr ) )
  665.     {
  666.         msg_Warn( p_access, "SubmitDVBSTuneRequest: "
  667.             "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
  668.         return VLC_EGENERIC;
  669.     }
  670.     l.p_dvbs_tune_request->put_ONID( -1 );
  671.     l.p_dvbs_tune_request->put_SID( -1 );
  672.     l.p_dvbs_tune_request->put_TSID( -1 );
  673.     hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
  674.         IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
  675.     if( FAILED( hr ) )
  676.     {
  677.         msg_Warn( p_access, "SubmitDVBSTuneRequest: "
  678.             "Cannot create the DVBS Locator: hr=0x%8lx", hr );
  679.         return VLC_EGENERIC;
  680.     }
  681.     hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
  682.         (void**)&l.p_dvbs_tuning_space );
  683.     if( FAILED( hr ) )
  684.     {
  685.         msg_Warn( p_access, "SubmitDVBSTuneRequest: "
  686.             "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
  687.         return VLC_EGENERIC;
  688.     }
  689.     hr = S_OK;
  690.     hr = l.p_dvbs_tuning_space->put_SystemType( DVB_Satellite );
  691.     if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
  692.         hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
  693.     if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
  694.         hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
  695.     if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
  696.         hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
  697.     if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
  698.         hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
  699.     if( SUCCEEDED( hr ) && l_network_id > 0 )
  700.         hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
  701.     if( SUCCEEDED( hr ) && l.i_range_len > 0 )
  702.         hr = l.p_dvbs_tuning_space->put_InputRange( l.bstr_input_range );
  703.     if( SUCCEEDED( hr ) && l_frequency > 0 )
  704.         hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
  705.     if( SUCCEEDED( hr ) && l_symbolrate > 0 )
  706.         hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
  707.     if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
  708.         hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
  709.     if( SUCCEEDED( hr ) && i_mod_typ != BDA_MOD_NOT_SET )
  710.         hr = l.p_dvbs_locator->put_Modulation( i_mod_typ );
  711.     if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
  712.         hr = l.p_dvbs_locator->put_InnerFECRate( i_hp_fec );
  713.     if( SUCCEEDED( hr ) && l_azimuth > 0 )
  714.         hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
  715.     if( SUCCEEDED( hr ) && l_elevation > 0 )
  716.         hr = l.p_dvbs_locator->put_Elevation( l_elevation );
  717.     if( SUCCEEDED( hr ) )
  718.         hr = l.p_dvbs_locator->put_WestPosition( b_west );
  719.     if( SUCCEEDED( hr ) )
  720.         hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
  721.     if( FAILED( hr ) )
  722.     {
  723.         msg_Warn( p_access, "SubmitDVBSTuneRequest: "
  724.             "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
  725.         return VLC_EGENERIC;
  726.     }
  727.     hr = p_tune_request->put_Locator( l.p_dvbs_locator );
  728.     if( FAILED( hr ) )
  729.     {
  730.         msg_Warn( p_access, "SubmitDVBSTuneRequest: "
  731.             "Cannot put the locator: hr=0x%8lx", hr );
  732.         return VLC_EGENERIC;
  733.     }
  734.     /* Build and Run the Graph. If a Tuner device is in use the graph will
  735.      * fail to run. Repeated calls to build will check successive tuner
  736.      * devices */
  737.     do
  738.     {
  739.         hr = Build();
  740.         if( FAILED( hr ) )
  741.         {
  742.             msg_Warn( p_access, "SubmitDVBSTuneRequest: "
  743.                 "Cannot Build the Graph: hr=0x%8lx", hr );
  744.             return VLC_EGENERIC;
  745.         }
  746.         hr = Start();
  747.     }
  748.     while( hr != S_OK );
  749.     return VLC_SUCCESS;
  750. }
  751. /*****************************************************************************
  752. * Load the Tuning Space from System Tuning Spaces according to the
  753. * Network Type requested
  754. ******************************************************************************/
  755. HRESULT BDAGraph::CreateTuneRequest()
  756. {
  757.     HRESULT hr = S_OK;
  758.     GUID guid_this_network_type;
  759.     class localComPtr
  760.     {
  761.         public:
  762.         ITuningSpaceContainer*  p_tuning_space_container;
  763.         IEnumTuningSpaces*      p_tuning_space_enum;
  764.         ITuningSpace*           p_this_tuning_space;
  765.         IDVBTuningSpace2*       p_dvb_tuning_space;
  766.         BSTR                    bstr_name;
  767.         char * psz_network_name;
  768.         char * psz_create_name;
  769.         char * psz_bstr_name;
  770.         WCHAR * wpsz_create_name;
  771.         int i_name_len;
  772.         localComPtr(): p_tuning_space_container(NULL),
  773.             p_tuning_space_enum(NULL), p_this_tuning_space(NULL),
  774.             p_dvb_tuning_space(NULL),
  775.             i_name_len(0), psz_network_name(NULL), wpsz_create_name(NULL),
  776.             psz_create_name(NULL), bstr_name(NULL), psz_bstr_name(NULL) {};
  777.         ~localComPtr()
  778.         {
  779.             if( p_tuning_space_enum )
  780.                 p_tuning_space_enum->Release();
  781.             if( p_tuning_space_container )
  782.                 p_tuning_space_container->Release();
  783.             if( p_this_tuning_space )
  784.                 p_this_tuning_space->Release();
  785.             if( p_dvb_tuning_space )
  786.                 p_dvb_tuning_space->Release();
  787.             SysFreeString( bstr_name );
  788.             delete[] psz_bstr_name;
  789.             delete[] wpsz_create_name;
  790.             free( psz_network_name );
  791.             free( psz_create_name );
  792.         }
  793.     } l;
  794.     /* We shall test for a specific Tuning space name supplied on the command
  795.      * line as dvb-networkname=xxx.
  796.      * For some users with multiple cards and/or multiple networks this could
  797.      * be useful. This allows us to reasonably safely apply updates to the
  798.      * System Tuning Space in the registry without disrupting other streams. */
  799.     l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-network-name" );
  800.     if( l.psz_network_name )
  801.     {
  802.         msg_Dbg( p_access, "CreateTuneRequest: Find Tuning Space: %s",
  803.             l.psz_network_name );
  804.     }
  805.     else
  806.     {
  807.         l.psz_network_name = new char[1];
  808.         *l.psz_network_name = '';
  809.     }
  810.     /* A Tuning Space may already have been set up. If it is for the same
  811.      * network type then all is well. Otherwise, reset the Tuning Space and get
  812.      * a new one */
  813.     if( p_tuning_space )
  814.     {
  815.         hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
  816.         if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
  817.         if( guid_this_network_type == guid_network_type )
  818.         {
  819.             hr = p_tuning_space->get_UniqueName( &l.bstr_name );
  820.             if( FAILED( hr ) )
  821.             {
  822.                 msg_Warn( p_access, "CreateTuneRequest: "
  823.                     "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
  824.                 return hr;
  825.             }
  826.             l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
  827.                 l.psz_bstr_name, 0, NULL, NULL );
  828.             l.psz_bstr_name = new char[ l.i_name_len ];
  829.             l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
  830.                 l.psz_bstr_name, l.i_name_len, NULL, NULL );
  831.             /* Test for a specific Tuning space name supplied on the command
  832.              * line as dvb-networkname=xxx */
  833.             if( strlen( l.psz_network_name ) == 0 ||
  834.                 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
  835.             {
  836.                 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
  837.                     l.psz_network_name );
  838.                 return S_OK;
  839.             }
  840.         }
  841.         /* else different guid_network_type */
  842.         if( p_tuning_space )
  843.             p_tuning_space->Release();
  844.         if( p_tune_request )
  845.             p_tune_request->Release();
  846.         p_tuning_space = NULL;
  847.         p_tune_request = NULL;
  848.     }
  849.     /* Force use of the first available Tuner Device during Build */
  850.     l_tuner_used = -1;
  851.     /* Get the SystemTuningSpaces container to enumerate through all the
  852.      * defined tuning spaces.
  853.      * l.p_tuning_space_container->Refcount = 1  */
  854.     hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
  855.         IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
  856.     if( FAILED( hr ) )
  857.     {
  858.         msg_Warn( p_access, "CreateTuneRequest: "
  859.             "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
  860.         return hr;
  861.     }
  862.     /* Get the SystemTuningSpaces container to enumerate through all the
  863.      * defined tuning spaces.
  864.      * l.p_tuning_space_container->Refcount = 2
  865.      * l.p_tuning_space_enum->Refcount = 1  */
  866.     hr = l.p_tuning_space_container->get_EnumTuningSpaces(
  867.          &l.p_tuning_space_enum );
  868.     if( FAILED( hr ) )
  869.     {
  870.         msg_Warn( p_access, "CreateTuneRequest: "
  871.             "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
  872.         return hr;
  873.     }
  874.     do
  875.     {
  876.         /* l.p_this_tuning_space->RefCount = 1 after the first pass
  877.          * Release before overwriting with Next */
  878.         if( l.p_this_tuning_space )
  879.             l.p_this_tuning_space->Release();
  880.         l.p_this_tuning_space = NULL;
  881.         SysFreeString( l.bstr_name );
  882.         hr = l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL );
  883.         if( hr != S_OK ) break;
  884.         hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
  885.         /* GUID_NULL means a non-BDA network was found e.g analog
  886.          * Ignore failures and non-BDA networks and keep looking */
  887.         if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
  888.         if( guid_this_network_type == guid_network_type )
  889.         {
  890.             /* QueryInterface to clone l.p_this_tuning_space
  891.              * l.p_this_tuning_space->RefCount = 2 */
  892.             hr = l.p_this_tuning_space->Clone( &p_tuning_space );
  893.             if( FAILED( hr ) )
  894.             {
  895.                 msg_Warn( p_access, "CreateTuneRequest: "
  896.                     "Cannot QI Tuning Space: hr=0x%8lx", hr );
  897.                 return hr;
  898.             }
  899.             hr = p_tuning_space->get_UniqueName( &l.bstr_name );
  900.             if( FAILED( hr ) )
  901.             {
  902.                 msg_Warn( p_access, "CreateTuneRequest: "
  903.                     "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
  904.                 return hr;
  905.             }
  906.             /* Test for a specific Tuning space name supplied on the command
  907.              * line as dvb-networkname=xxx */
  908.             delete[] l.psz_bstr_name;
  909.             l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
  910.                 l.psz_bstr_name, 0, NULL, NULL );
  911.             l.psz_bstr_name = new char[ l.i_name_len ];
  912.             l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
  913.                 l.psz_bstr_name, l.i_name_len, NULL, NULL );
  914.             if( strlen( l.psz_network_name ) == 0 ||
  915.                 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
  916.             {
  917.                 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
  918.                     l.psz_bstr_name );
  919.             /* CreateTuneRequest adds TuneRequest to p_tuning_space
  920.              * p_tune_request->RefCount = 1 */
  921.                 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
  922.                 if( FAILED( hr ) )
  923.                     msg_Warn( p_access, "CreateTuneRequest: "
  924.                         "Cannot Create Tune Request: hr=0x%8lx", hr );
  925.                 return hr;
  926.             }
  927.             if( p_tuning_space )
  928.                 p_tuning_space->Release();
  929.             p_tuning_space = NULL;
  930.         }
  931.     }
  932.     while( true );
  933.     /* No tuning space was found. If the create-name parameter was set then
  934.      * create a tuning space. By rights should use the same name used in
  935.      * network-name
  936.      * Also would be nice to copy a tuning space but we only come here if we do
  937.      * not find any. */
  938.     l.psz_create_name = var_GetNonEmptyString( p_access, "dvb-create-name" );
  939.     if( !l.psz_create_name || strlen( l.psz_create_name ) <= 0 )
  940.     {
  941.         hr = E_FAIL;
  942.         msg_Warn( p_access, "CreateTuneRequest: "
  943.             "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
  944.         return hr;
  945.     }
  946.     if( strcmp( l.psz_create_name, l.psz_network_name ) )
  947.     {
  948.         hr = E_FAIL;
  949.         msg_Warn( p_access, "CreateTuneRequest: "
  950.             "dvb-create-name %s must match dvb-network-name %s",
  951.             l.psz_create_name, l.psz_network_name );
  952.         return hr;
  953.     }
  954.     /* Need to use DVBSTuningSpace for DVB-S and ATSCTuningSpace for ATSC */
  955.     VARIANT var_id;
  956.     CLSID cls_tuning_space;
  957.     if( IsEqualCLSID( guid_network_type, CLSID_ATSCNetworkProvider ) )
  958.         cls_tuning_space = CLSID_ATSCTuningSpace;
  959.     if( IsEqualCLSID( guid_network_type, CLSID_DVBTNetworkProvider ) )
  960.         cls_tuning_space = CLSID_DVBTuningSpace;
  961.     if( IsEqualCLSID( guid_network_type, CLSID_DVBCNetworkProvider ) )
  962.         cls_tuning_space = CLSID_DVBTuningSpace;
  963.     if( IsEqualCLSID( guid_network_type, CLSID_DVBSNetworkProvider ) )
  964.         cls_tuning_space = CLSID_DVBSTuningSpace;
  965.     l.i_name_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  966.         l.psz_create_name, -1, l.wpsz_create_name, 0 );
  967.     if( l.i_name_len <= 0 )
  968.     {
  969.         hr = E_FAIL;
  970.         msg_Warn( p_access, "CreateTuneRequest: "
  971.             "Cannot convert zero length dvb-create-name %s",
  972.             l.psz_create_name );
  973.         return hr;
  974.     }
  975.     l.wpsz_create_name = new WCHAR[l.i_name_len];
  976.     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, l.psz_create_name, -1,
  977.             l.wpsz_create_name, l.i_name_len );
  978.     if( l.bstr_name )
  979.         SysFreeString( l.bstr_name );
  980.     l.bstr_name = SysAllocString( l.wpsz_create_name );
  981.     msg_Dbg( p_access, "CreateTuneRequest: Create Tuning Space: %s",
  982.         l.psz_create_name );
  983.     hr = ::CoCreateInstance( cls_tuning_space, 0, CLSCTX_INPROC,
  984.          IID_ITuningSpace, (void**)&p_tuning_space );
  985.     if( FAILED( hr ) )
  986.         msg_Warn( p_access, "CreateTuneRequest: "
  987.             "Cannot CoCreate new TuningSpace: hr=0x%8lx", hr );
  988.     if( SUCCEEDED( hr ) )
  989.         hr = p_tuning_space->put__NetworkType( guid_network_type );
  990.     if( FAILED( hr ) )
  991.         msg_Warn( p_access, "CreateTuneRequest: "
  992.             "Cannot Put Network Type: hr=0x%8lx", hr );
  993.     if( SUCCEEDED( hr ) )
  994.         hr = p_tuning_space->put_UniqueName( l.bstr_name );
  995.     if( FAILED( hr ) )
  996.         msg_Warn( p_access, "CreateTuneRequest: "
  997.             "Cannot Put Unique Name: hr=0x%8lx", hr );
  998.     if( SUCCEEDED( hr ) )
  999.         hr = p_tuning_space->put_FriendlyName( l.bstr_name );
  1000.     if( FAILED( hr ) )
  1001.         msg_Warn( p_access, "CreateTuneRequest: "
  1002.             "Cannot Put Friendly Name: hr=0x%8lx", hr );
  1003.     if( guid_network_type == CLSID_DVBTNetworkProvider ||
  1004.         guid_network_type == CLSID_DVBCNetworkProvider ||
  1005.         guid_network_type == CLSID_DVBSNetworkProvider )
  1006.     {
  1007.         hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
  1008.             (void**)&l.p_dvb_tuning_space );
  1009.         if( FAILED( hr ) )
  1010.         {
  1011.             msg_Warn( p_access, "CreateTuneRequest: "
  1012.                 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
  1013.             return hr;
  1014.         }
  1015.         if( guid_network_type == CLSID_DVBTNetworkProvider )
  1016.             hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
  1017.         if( guid_network_type == CLSID_DVBCNetworkProvider )
  1018.             hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
  1019.         if( guid_network_type == CLSID_DVBSNetworkProvider )
  1020.             hr = l.p_dvb_tuning_space->put_SystemType( DVB_Satellite );
  1021.     }
  1022.     if( SUCCEEDED( hr ) )
  1023.         hr = l.p_tuning_space_container->Add( p_tuning_space, &var_id );
  1024.     if( FAILED( hr ) )
  1025.     {
  1026.         msg_Warn( p_access, "CreateTuneRequest: "
  1027.             "Cannot Create new TuningSpace: hr=0x%8lx", hr );
  1028.         return hr;
  1029.     }
  1030.     msg_Dbg( p_access, "CreateTuneRequest: Tuning Space: %s created",
  1031.          l.psz_create_name );
  1032.     hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
  1033.     if( FAILED( hr ) )
  1034.         msg_Warn( p_access, "CreateTuneRequest: "
  1035.             "Cannot Create Tune Request: hr=0x%8lx", hr );
  1036.     return hr;
  1037. }
  1038. /******************************************************************************
  1039. * Build
  1040. * Step 4: Build the Filter Graph
  1041. * Build sets up devices, adds and connects filters
  1042. ******************************************************************************/
  1043. HRESULT BDAGraph::Build()
  1044. {
  1045.     HRESULT hr = S_OK;
  1046.     long l_capture_used, l_tif_used;
  1047.     VARIANT l_tuning_space_id;
  1048.     AM_MEDIA_TYPE grabber_media_type;
  1049.     class localComPtr
  1050.     {
  1051.         public:
  1052.         ITuningSpaceContainer*  p_tuning_space_container;
  1053.         localComPtr(): p_tuning_space_container(NULL) {};
  1054.         ~localComPtr()
  1055.         {
  1056.             if( p_tuning_space_container )
  1057.                 p_tuning_space_container->Release();
  1058.         }
  1059.     } l;
  1060.     /* Get the SystemTuningSpaces container to save the Tuning space */
  1061.     l_tuning_space_id.vt = VT_I4;
  1062.     l_tuning_space_id.lVal = 0L;
  1063.     hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
  1064.         IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
  1065.     if( FAILED( hr ) )
  1066.     {
  1067.         msg_Warn( p_access, "Build: "
  1068.             "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
  1069.         return hr;
  1070.     }
  1071.     hr = l.p_tuning_space_container->FindID( p_tuning_space,
  1072.         &l_tuning_space_id.lVal );
  1073.     if( FAILED( hr ) )
  1074.     {
  1075.         msg_Warn( p_access, "Build: "
  1076.             "Cannot Find Tuning Space ID: hr=0x%8lx", hr );
  1077.         return hr;
  1078.     }
  1079.     msg_Dbg( p_access, "Build: Using Tuning Space ID %d",
  1080.         l_tuning_space_id.lVal );
  1081.     hr = l.p_tuning_space_container->put_Item( l_tuning_space_id,
  1082.         p_tuning_space );
  1083.     if( FAILED( hr ) )
  1084.     {
  1085.         msg_Warn( p_access, "Build: "
  1086.             "Cannot save Tuning Space: hr=0x%8lx (ignored)", hr );
  1087.     }
  1088.     /* If we have already have a filter graph, rebuild it*/
  1089.     Destroy();
  1090.     hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
  1091.         IID_IGraphBuilder, (void**)&p_filter_graph );
  1092.     if( FAILED( hr ) )
  1093.     {
  1094.         msg_Warn( p_access, "Build: "
  1095.             "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
  1096.         return hr;
  1097.     }
  1098.     /* First filter in the graph is the Network Provider and
  1099.      * its Scanning Tuner which takes the Tune Request*/
  1100.     hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
  1101.         IID_IBaseFilter, (void**)&p_network_provider);
  1102.     if( FAILED( hr ) )
  1103.     {
  1104.         msg_Warn( p_access, "Build: "
  1105.             "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
  1106.         return hr;
  1107.     }
  1108.     hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
  1109.     if( FAILED( hr ) )
  1110.     {
  1111.         msg_Warn( p_access, "Build: "
  1112.             "Cannot load network provider: hr=0x%8lx", hr );
  1113.         return hr;
  1114.     }
  1115.     hr = p_network_provider->QueryInterface( IID_IScanningTuner,
  1116.         (void**)&p_scanning_tuner );
  1117.     if( FAILED( hr ) )
  1118.     {
  1119.         msg_Warn( p_access, "Build: "
  1120.             "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
  1121.         return hr;
  1122.     }
  1123.     hr = p_scanning_tuner->Validate( p_tune_request );
  1124.     if( FAILED( hr ) )
  1125.     {
  1126.         msg_Warn( p_access, "Build: "
  1127.             "Tune Request is invalid: hr=0x%8lx", hr );
  1128.         return hr;
  1129.     }
  1130.     hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
  1131.     if( FAILED( hr ) )
  1132.     {
  1133.         msg_Warn( p_access, "Build: "
  1134.             "Cannot submit the tune request: hr=0x%8lx", hr );
  1135.         return hr;
  1136.     }
  1137.     /* Add the Network Tuner to the Network Provider. On subsequent calls,
  1138.      * l_tuner_used will cause a different tuner to be selected
  1139.      * To select a specific device first get the parameter that nominates the
  1140.      * device (dvb-adapter) and use the value to initialise l_tuner_used.
  1141.      * When FindFilter returns check the contents of l_tuner_used.
  1142.      * If it is not what was selected then the requested device was not
  1143.      * available so return with an error. */
  1144.     long l_adapter = -1;
  1145.     l_adapter = var_GetInteger( p_access, "dvb-adapter" );
  1146.     if( l_tuner_used < 0 && l_adapter >= 0 )
  1147.         l_tuner_used = l_adapter - 1;
  1148.     hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
  1149.         p_network_provider, &p_tuner_device );
  1150.     if( FAILED( hr ) )
  1151.     {
  1152.         msg_Warn( p_access, "Build: "
  1153.             "Cannot load tuner device and connect network provider: "
  1154.             "hr=0x%8lx", hr );
  1155.         return hr;
  1156.     }
  1157.     if( l_adapter > 0 && l_tuner_used != l_adapter )
  1158.     {
  1159.          msg_Warn( p_access, "Build: "
  1160.              "Tuner device %d is not available", l_adapter );
  1161.         return E_FAIL;
  1162.     }
  1163.     msg_Dbg( p_access, "BDAGraph: Using adapter %d", l_tuner_used );
  1164. /* VLC 1.0 works reliably up this point then crashes
  1165.  * Obvious candidate is FindFilter */
  1166.     /* Always look for all capture devices to match the Network Tuner */
  1167.     l_capture_used = -1;
  1168.     hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
  1169.         p_tuner_device, &p_capture_device );
  1170.     if( FAILED( hr ) )
  1171.     {
  1172.         /* Some BDA drivers do not provide a Capture Device Filter so force
  1173.          * the Sample Grabber to connect directly to the Tuner Device */
  1174.         p_capture_device = p_tuner_device;
  1175.         p_tuner_device = NULL;
  1176.         msg_Warn( p_access, "Build: "
  1177.             "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
  1178.     }
  1179.     if( p_sample_grabber )
  1180.          p_sample_grabber->Release();
  1181.     p_sample_grabber = NULL;
  1182.     /* Insert the Sample Grabber to tap into the Transport Stream. */
  1183.     hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
  1184.         IID_IBaseFilter, (void**)&p_sample_grabber );
  1185.     if( FAILED( hr ) )
  1186.     {
  1187.         msg_Warn( p_access, "Build: "
  1188.             "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
  1189.         return hr;
  1190.     }
  1191.     hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
  1192.     if( FAILED( hr ) )
  1193.     {
  1194.         msg_Warn( p_access, "Build: "
  1195.             "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
  1196.         return hr;
  1197.     }
  1198.     if( p_grabber )
  1199.         p_grabber->Release();
  1200.     p_grabber = NULL;
  1201.     hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
  1202.         (void**)&p_grabber );
  1203.     if( FAILED( hr ) )
  1204.     {
  1205.         msg_Warn( p_access, "Build: "
  1206.             "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
  1207.         return hr;
  1208.     }
  1209.     /* Try the possible stream type */
  1210.     hr = E_FAIL;
  1211.     for( int i = 0; i < 2; i++ )
  1212.     {
  1213.         ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
  1214.         grabber_media_type.majortype = MEDIATYPE_Stream;
  1215.         grabber_media_type.subtype   =  i == 0 ? MEDIASUBTYPE_MPEG2_TRANSPORT : KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT;
  1216.         msg_Dbg( p_access, "Build: "
  1217.                            "Trying connecting with subtype %s",
  1218.                            i == 0 ? "MEDIASUBTYPE_MPEG2_TRANSPORT" : "KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT" );
  1219.         hr = p_grabber->SetMediaType( &grabber_media_type );
  1220.         if( SUCCEEDED( hr ) )
  1221.         {
  1222.             hr = Connect( p_capture_device, p_sample_grabber );
  1223.             if( SUCCEEDED( hr ) )
  1224.                 break;
  1225.             msg_Warn( p_access, "Build: "
  1226.                 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr, 1+i );
  1227.         }
  1228.         else
  1229.         {
  1230.             msg_Warn( p_access, "Build: "
  1231.                 "Cannot set media type on grabber filter: hr=0x%8lx (try %d/2", hr, 1+i );
  1232.         }
  1233.     }
  1234.     if( hr )
  1235.         return hr;
  1236.     /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
  1237.      * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
  1238.      * the Network Provider filter to set up the stream */
  1239.     hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
  1240.         CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
  1241.     if( FAILED( hr ) )
  1242.     {
  1243.         msg_Warn( p_access, "Build: "
  1244.             "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
  1245.         return hr;
  1246.     }
  1247.     hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
  1248.     if( FAILED( hr ) )
  1249.     {
  1250.         msg_Warn( p_access, "Build: "
  1251.             "Cannot add demux filter to graph: hr=0x%8lx", hr );
  1252.         return hr;
  1253.     }
  1254.     hr = Connect( p_sample_grabber, p_mpeg_demux );
  1255.     if( FAILED( hr ) )
  1256.     {
  1257.         msg_Warn( p_access, "Build: "
  1258.             "Cannot connect demux to grabber: hr=0x%8lx", hr );
  1259.         return hr;
  1260.     }
  1261.     /* Always look for the Transform Information Filter from the start
  1262.      * of the collection*/
  1263.     l_tif_used = -1;
  1264.     hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
  1265.         p_mpeg_demux, &p_transport_info );
  1266.     if( FAILED( hr ) )
  1267.     {
  1268.         msg_Warn( p_access, "Build: "
  1269.             "Cannot load TIF onto demux: hr=0x%8lx", hr );
  1270.         return hr;
  1271.     }
  1272.     /* Configure the Sample Grabber to buffer the samples continuously */
  1273.     hr = p_grabber->SetBufferSamples( true );
  1274.     if( FAILED( hr ) )
  1275.     {
  1276.         msg_Warn( p_access, "Build: "
  1277.             "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
  1278.         return hr;
  1279.     }
  1280.     hr = p_grabber->SetOneShot( false );
  1281.     if( FAILED( hr ) )
  1282.     {
  1283.         msg_Warn( p_access, "Build: "
  1284.             "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
  1285.         return hr;
  1286.     }
  1287.     hr = p_grabber->SetCallback( this, 0 );
  1288.     if( FAILED( hr ) )
  1289.     {
  1290.         msg_Warn( p_access, "Build: "
  1291.             "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
  1292.         return hr;
  1293.     }
  1294.     hr = Register();
  1295.     if( FAILED( hr ) )
  1296.     {
  1297.         d_graph_register = 0;
  1298.     }
  1299.     /* The Media Control is used to Run and Stop the Graph */
  1300.     if( p_media_control )
  1301.         p_media_control->Release();
  1302.     p_media_control = NULL;
  1303.     hr = p_filter_graph->QueryInterface( IID_IMediaControl,
  1304.         (void**)&p_media_control );
  1305.     if( FAILED( hr ) )
  1306.     {
  1307.         msg_Warn( p_access, "Build: "
  1308.             "Cannot QI Media Control: hr=0x%8lx", hr );
  1309.         return hr;
  1310.     }
  1311.     return hr;
  1312. }
  1313. /******************************************************************************
  1314. * FindFilter
  1315. * Looks up all filters in a category and connects to the upstream filter until
  1316. * a successful match is found. The index of the connected filter is returned.
  1317. * On subsequent calls, this can be used to start from that point to find
  1318. * another match.
  1319. * This is used when the graph does not run because a tuner device is in use so
  1320. * another one needs to be selected.
  1321. ******************************************************************************/
  1322. HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
  1323.     IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
  1324. {
  1325.     HRESULT                 hr = S_OK;
  1326.     int                     i_moniker_index = -1;
  1327.     class localComPtr
  1328.     {
  1329.         public:
  1330.         IMoniker*      p_moniker;
  1331.         IEnumMoniker*  p_moniker_enum;
  1332.         IBaseFilter*   p_filter;
  1333.         IPropertyBag*  p_property_bag;
  1334.         VARIANT        var_bstr;
  1335.         char *         psz_bstr;
  1336.         int            i_bstr_len;
  1337.         localComPtr():
  1338.             p_moniker(NULL),
  1339.             p_moniker_enum(NULL),
  1340.             p_filter(NULL),
  1341.             p_property_bag(NULL),
  1342.             psz_bstr( NULL )
  1343.             { ::VariantInit(&var_bstr); };
  1344.         ~localComPtr()
  1345.         {
  1346.             if( p_property_bag )
  1347.                 p_property_bag->Release();
  1348.             if( p_filter )
  1349.                 p_filter->Release();
  1350.             if( p_moniker )
  1351.                 p_moniker->Release();
  1352.             if( p_moniker_enum )
  1353.                 p_moniker_enum->Release();
  1354.             ::VariantClear(&var_bstr);
  1355.             delete[] psz_bstr;
  1356.         }
  1357.     } l;
  1358.     if( !p_system_dev_enum )
  1359.     {
  1360.         hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
  1361.             IID_ICreateDevEnum, (void**)&p_system_dev_enum );
  1362.         if( FAILED( hr ) )
  1363.         {
  1364.             msg_Warn( p_access, "FindFilter: "
  1365.                 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
  1366.             return hr;
  1367.         }
  1368.     }
  1369.     hr = p_system_dev_enum->CreateClassEnumerator( clsid,
  1370.         &l.p_moniker_enum, 0 );
  1371.     if( hr != S_OK )
  1372.     {
  1373.         msg_Warn( p_access, "FindFilter: "
  1374.             "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
  1375.         return E_FAIL;
  1376.     }
  1377.     do
  1378.     {
  1379.         /* We are overwriting l.p_moniker so we should Release and nullify
  1380.          * It is important that p_moniker and p_property_bag are fully released
  1381.          * l.p_filter may not be dereferenced so we could force to NULL */
  1382.         if( l.p_property_bag )
  1383.             l.p_property_bag->Release();
  1384.         l.p_property_bag = NULL;
  1385.         if( l.p_filter )
  1386.             l.p_filter->Release();
  1387.         l.p_filter = NULL;
  1388.         if( l.p_moniker )
  1389.             l.p_moniker->Release();
  1390.          l.p_moniker = NULL;
  1391.         hr = l.p_moniker_enum->Next( 1, &l.p_moniker, 0 );
  1392.         if( hr != S_OK ) break;
  1393.         i_moniker_index++;
  1394.         /* Skip over devices already found on previous calls */
  1395.         if( i_moniker_index <= *i_moniker_used ) continue;
  1396.         *i_moniker_used = i_moniker_index;
  1397.         /* l.p_filter is Released at the top of the loop */
  1398.         hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
  1399.             (void**)&l.p_filter );
  1400.         if( FAILED( hr ) )
  1401.         {
  1402.             continue;
  1403.         }
  1404.         /* l.p_property_bag is released at the top of the loop */
  1405.         hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
  1406.             (void**)&l.p_property_bag );
  1407.         if( FAILED( hr ) )
  1408.         {
  1409.             msg_Warn( p_access, "FindFilter: "
  1410.                 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
  1411.             return hr;
  1412.         }
  1413.         hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
  1414.         if( FAILED( hr ) )
  1415.         {
  1416.             msg_Warn( p_access, "FindFilter: "
  1417.                 "Cannot read filter friendly name: hr=0x%8lx", hr );
  1418.             return hr;
  1419.         }
  1420.         hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
  1421.         if( FAILED( hr ) )
  1422.         {
  1423.             msg_Warn( p_access, "FindFilter: "
  1424.                 "Cannot add filter: hr=0x%8lx", hr );
  1425.             return hr;
  1426.         }
  1427.         hr = Connect( p_upstream, l.p_filter );
  1428.         if( SUCCEEDED( hr ) )
  1429.         {
  1430.             /* p_p_downstream has not been touched yet so no release needed */
  1431.             delete[] l.psz_bstr;
  1432.             l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
  1433.                 l.var_bstr.bstrVal, -1, l.psz_bstr, 0, NULL, NULL );
  1434.             l.psz_bstr = new char[l.i_bstr_len];
  1435.             l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
  1436.                 l.var_bstr.bstrVal, -1, l.psz_bstr, l.i_bstr_len, NULL, NULL );
  1437.             msg_Dbg( p_access, "FindFilter: Connected %s", l.psz_bstr );
  1438.             l.p_filter->QueryInterface( IID_IBaseFilter,
  1439.                 (void**)p_p_downstream );
  1440.             return S_OK;
  1441.         }
  1442.         /* Not the filter we want so unload and try the next one */
  1443.         hr = p_filter_graph->RemoveFilter( l.p_filter );
  1444.         if( FAILED( hr ) )
  1445.         {
  1446.             msg_Warn( p_access, "FindFilter: "
  1447.                 "Failed unloading Filter: hr=0x%8lx", hr );
  1448.             return hr;
  1449.         }
  1450.     }
  1451.     while( true );
  1452.     hr = E_FAIL;
  1453.     msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
  1454.     return hr;
  1455. }
  1456. /*****************************************************************************
  1457. * Connect is called from Build to enumerate and connect pins
  1458. *****************************************************************************/
  1459. HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
  1460. {
  1461.     HRESULT             hr = E_FAIL;
  1462.     class localComPtr
  1463.     {
  1464.         public:
  1465.         IPin*      p_pin_upstream;
  1466.         IPin*      p_pin_downstream;
  1467.         IEnumPins* p_pin_upstream_enum;
  1468.         IEnumPins* p_pin_downstream_enum;
  1469.         IPin*      p_pin_temp;
  1470.         localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
  1471.             p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
  1472.             p_pin_temp(NULL) { };
  1473.         ~localComPtr()
  1474.         {
  1475.             if( p_pin_temp )
  1476.                 p_pin_temp->Release();
  1477.             if( p_pin_downstream )
  1478.                 p_pin_downstream->Release();
  1479.             if( p_pin_upstream )
  1480.                 p_pin_upstream->Release();
  1481.             if( p_pin_downstream_enum )
  1482.                 p_pin_downstream_enum->Release();
  1483.             if( p_pin_upstream_enum )
  1484.                 p_pin_upstream_enum->Release();
  1485.         }
  1486.     } l;
  1487.     PIN_DIRECTION pin_dir;
  1488.     hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
  1489.     if( FAILED( hr ) )
  1490.     {
  1491.         msg_Warn( p_access, "Connect: "
  1492.             "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
  1493.         return hr;
  1494.     }
  1495.     do
  1496.     {
  1497.         /* Release l.p_pin_upstream before next iteration */
  1498.         if( l.p_pin_upstream  )
  1499.             l.p_pin_upstream ->Release();
  1500.         l.p_pin_upstream = NULL;
  1501.         hr = l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 );
  1502.         if( hr != S_OK ) break;
  1503.         hr = l.p_pin_upstream->QueryDirection( &pin_dir );
  1504.         if( FAILED( hr ) )
  1505.         {
  1506.             msg_Warn( p_access, "Connect: "
  1507.                 "Cannot get upstream filter pin direction: hr=0x%8lx", hr );
  1508.             return hr;
  1509.         }
  1510.         hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
  1511.         if( SUCCEEDED( hr ) )
  1512.         {
  1513.             l.p_pin_downstream->Release();
  1514.             l.p_pin_downstream = NULL;
  1515.         }
  1516.         if( FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
  1517.         {
  1518.             msg_Warn( p_access, "Connect: "
  1519.                 "Cannot check upstream filter connection: hr=0x%8lx", hr );
  1520.             return hr;
  1521.         }
  1522.         if( ( pin_dir == PINDIR_OUTPUT ) && ( hr == VFW_E_NOT_CONNECTED ) )
  1523.         {
  1524.             /* The upstream pin is not yet connected so check each pin on the
  1525.              * downstream filter */
  1526.             hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
  1527.             if( FAILED( hr ) )
  1528.             {
  1529.                 msg_Warn( p_access, "Connect: Cannot get "
  1530.                     "downstream filter enumerator: hr=0x%8lx", hr );
  1531.                 return hr;
  1532.             }
  1533.             do
  1534.             {
  1535.                 /* Release l.p_pin_downstream before next iteration */
  1536.                 if( l.p_pin_downstream  )
  1537.                     l.p_pin_downstream ->Release();
  1538.                 l.p_pin_downstream = NULL;
  1539.                 hr = l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 );
  1540.                 if( hr != S_OK ) break;
  1541.                 hr = l.p_pin_downstream->QueryDirection( &pin_dir );
  1542.                 if( FAILED( hr ) )
  1543.                 {
  1544.                     msg_Warn( p_access, "Connect: Cannot get "
  1545.                         "downstream filter pin direction: hr=0x%8lx", hr );
  1546.                     return hr;
  1547.                 }
  1548.                 /* Looking for a free Pin to connect to
  1549.                  * A connected Pin may have an reference count > 1
  1550.                  * so Release and nullify the pointer */
  1551.                 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
  1552.                 if( SUCCEEDED( hr ) )
  1553.                 {
  1554.                     l.p_pin_temp->Release();
  1555.                     l.p_pin_temp = NULL;
  1556.                 }
  1557.                 if( hr != VFW_E_NOT_CONNECTED )
  1558.                 {
  1559.                     if( FAILED( hr ) )
  1560.                     {
  1561.                         msg_Warn( p_access, "Connect: Cannot check "
  1562.                             "downstream filter connection: hr=0x%8lx", hr );
  1563.                         return hr;
  1564.                     }
  1565.                 }
  1566.                 if( ( pin_dir == PINDIR_INPUT ) &&
  1567.                     ( hr == VFW_E_NOT_CONNECTED ) )
  1568.                 {
  1569.                     hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
  1570.                         l.p_pin_downstream, NULL );
  1571.                     if( SUCCEEDED( hr ) )
  1572.                     {
  1573.                         /* If we arrive here then we have a matching pair of
  1574.                          * pins. */
  1575.                         return S_OK;
  1576.                     }
  1577.                 }
  1578.                 /* If we arrive here it means this downstream pin is not
  1579.                  * suitable so try the next downstream pin.
  1580.                  * l.p_pin_downstream is released at the top of the loop */
  1581.             }
  1582.             while( true );
  1583.             /* If we arrive here then we ran out of pins before we found a
  1584.              * suitable one. Release outstanding refcounts */
  1585.             if( l.p_pin_downstream_enum )
  1586.                 l.p_pin_downstream_enum->Release();
  1587.             l.p_pin_downstream_enum = NULL;
  1588.             if( l.p_pin_downstream )
  1589.                 l.p_pin_downstream->Release();
  1590.             l.p_pin_downstream = NULL;
  1591.         }
  1592.         /* If we arrive here it means this upstream pin is not suitable
  1593.          * so try the next upstream pin
  1594.          * l.p_pin_upstream is released at the top of the loop */
  1595.     }
  1596.     while( true );
  1597.     /* If we arrive here it means we did not find any pair of suitable pins
  1598.      * Outstanding refcounts are released in the destructor */
  1599.     return E_FAIL;
  1600. }
  1601. /*****************************************************************************
  1602. * Start uses MediaControl to start the graph
  1603. *****************************************************************************/
  1604. HRESULT BDAGraph::Start()
  1605. {
  1606.     HRESULT hr = S_OK;
  1607.     OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
  1608.     if( !p_media_control )
  1609.     {
  1610.         msg_Dbg( p_access, "Start: Media Control has not been created" );
  1611.         return E_FAIL;
  1612.     }
  1613.     hr = p_media_control->Run();
  1614.     msg_Dbg( p_access, "Graph started hr=0x%lx", hr );
  1615.     if( hr == S_OK )
  1616.         return hr;
  1617.     /* Query the state of the graph - timeout after 100 milliseconds */
  1618.     while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
  1619.     {
  1620.         if( FAILED( hr ) )
  1621.         {
  1622.             msg_Warn( p_access,
  1623.                 "Start: Cannot get Graph state: hr=0x%8lx", hr );
  1624.             return hr;
  1625.         }
  1626.     }
  1627.     if( i_state == State_Running )
  1628.         return hr;
  1629.     /* The Graph is not running so stop it and return an error */
  1630.     msg_Warn( p_access, "Start: Graph not started: %d", i_state );
  1631.     hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
  1632.     if( FAILED( hr ) )
  1633.     {
  1634.         msg_Warn( p_access,
  1635.             "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
  1636.         return hr;
  1637.     }
  1638.     return E_FAIL;
  1639. }
  1640. /*****************************************************************************
  1641. * Pop the stream of data
  1642. *****************************************************************************/
  1643. block_t *BDAGraph::Pop()
  1644. {
  1645.     return output.Pop();
  1646. }
  1647. /******************************************************************************
  1648. * SampleCB - Callback when the Sample Grabber has a sample
  1649. ******************************************************************************/
  1650. STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
  1651. {
  1652.     if( p_sample->IsDiscontinuity() == S_OK )
  1653.         msg_Warn( p_access, "BDA SampleCB: Sample Discontinuity.");
  1654.     const size_t i_sample_size = p_sample->GetActualDataLength();
  1655.     BYTE *p_sample_data;
  1656.     p_sample->GetPointer( &p_sample_data );
  1657.     if( i_sample_size > 0 && p_sample_data )
  1658.     {
  1659.         block_t *p_block = block_New( p_access, i_sample_size );
  1660.         if( p_block )
  1661.         {
  1662.             memcpy( p_block->p_buffer, p_sample_data, i_sample_size );
  1663.             output.Push( p_block );
  1664.         }
  1665.      }
  1666.      return S_OK;
  1667. }
  1668. STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
  1669.     long l_buffer_len )
  1670. {
  1671.     return E_FAIL;
  1672. }
  1673. /******************************************************************************
  1674. * removes each filter from the graph
  1675. ******************************************************************************/
  1676. HRESULT BDAGraph::Destroy()
  1677. {
  1678.     HRESULT hr = S_OK;
  1679.     ULONG ul_refcount = 0;
  1680.     if( p_media_control )
  1681.         hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
  1682.     if( d_graph_register )
  1683.     {
  1684.         Deregister();
  1685.     }
  1686.     output.Empty();
  1687.     if( p_grabber )
  1688.     {
  1689.         p_grabber->Release();
  1690.         p_grabber = NULL;
  1691.     }
  1692.     if( p_transport_info )
  1693.     {
  1694.         p_filter_graph->RemoveFilter( p_transport_info );
  1695.         p_transport_info->Release();
  1696.         p_transport_info = NULL;
  1697.     }
  1698.     if( p_mpeg_demux )
  1699.     {
  1700.         p_filter_graph->RemoveFilter( p_mpeg_demux );
  1701.         p_mpeg_demux->Release();
  1702.         p_mpeg_demux = NULL;
  1703.     }
  1704.     if( p_sample_grabber )
  1705.     {
  1706.         p_filter_graph->RemoveFilter( p_sample_grabber );
  1707.         p_sample_grabber->Release();
  1708.         p_sample_grabber = NULL;
  1709.     }
  1710.     if( p_capture_device )
  1711.     {
  1712.         p_filter_graph->RemoveFilter( p_capture_device );
  1713.         p_capture_device->Release();
  1714.         p_capture_device = NULL;
  1715.     }
  1716.     if( p_tuner_device )
  1717.     {
  1718.         p_filter_graph->RemoveFilter( p_tuner_device );
  1719.         p_tuner_device->Release();
  1720.         p_tuner_device = NULL;
  1721.     }
  1722.     if( p_scanning_tuner )
  1723.     {
  1724.         p_scanning_tuner->Release();
  1725.         p_scanning_tuner = NULL;
  1726.     }
  1727.     if( p_network_provider )
  1728.     {
  1729.         p_filter_graph->RemoveFilter( p_network_provider );
  1730.         p_network_provider->Release();
  1731.         p_network_provider = NULL;
  1732.     }
  1733.     if( p_media_control )
  1734.     {
  1735.         p_media_control->Release();
  1736.         p_media_control = NULL;
  1737.     }
  1738.     if( p_filter_graph )
  1739.     {
  1740.         p_filter_graph->Release();
  1741.         p_filter_graph = NULL;
  1742.     }
  1743.     if( p_system_dev_enum )
  1744.     {
  1745.         p_system_dev_enum->Release();
  1746.         p_system_dev_enum = NULL;
  1747.     }
  1748.     return S_OK;
  1749. }
  1750. /*****************************************************************************
  1751. * Add/Remove a DirectShow filter graph to/from the Running Object Table.
  1752. * Allows GraphEdit to "spy" on a remote filter graph.
  1753. ******************************************************************************/
  1754. HRESULT BDAGraph::Register()
  1755. {
  1756.     class localComPtr
  1757.     {
  1758.         public:
  1759.         IMoniker*             p_moniker;
  1760.         IRunningObjectTable*  p_ro_table;
  1761.         localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
  1762.         ~localComPtr()
  1763.         {
  1764.             if( p_moniker )
  1765.                 p_moniker->Release();
  1766.             if( p_ro_table )
  1767.                 p_ro_table->Release();
  1768.         }
  1769.     } l;
  1770.     WCHAR     psz_w_graph_name[128];
  1771.     HRESULT   hr;
  1772.     hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
  1773.     if( FAILED( hr ) )
  1774.     {
  1775.         msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
  1776.         return hr;
  1777.     }
  1778.     wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
  1779.         (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
  1780.     hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
  1781.     if( FAILED( hr ) )
  1782.     {
  1783.         msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
  1784.         return hr;
  1785.     }
  1786.     hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
  1787.         p_filter_graph, l.p_moniker, &d_graph_register );
  1788.     if( FAILED( hr ) )
  1789.     {
  1790.         msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
  1791.         return hr;
  1792.     }
  1793. //    msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
  1794.     return hr;
  1795. }
  1796. void BDAGraph::Deregister()
  1797. {
  1798.     HRESULT   hr;
  1799.     IRunningObjectTable* p_ro_table;
  1800.     hr = ::GetRunningObjectTable( 0, &p_ro_table );
  1801.     if( SUCCEEDED( hr ) )
  1802.         p_ro_table->Revoke( d_graph_register );
  1803.     d_graph_register = 0;
  1804.     p_ro_table->Release();
  1805. }