1 /*****************************************************************************
2 * bdagraph.cpp : DirectShow BDA graph for vlc
3 *****************************************************************************
4 * Copyright( C ) 2007 the VideoLAN team
6 * Author: Ken Self <kens@campoz.fslife.co.uk>
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.
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.
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 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
31 #include <vlc_input.h>
32 #include <vlc_access.h>
34 /* Needed to call CoInitializeEx */
37 /* Work-around a bug in w32api-2.5 */
39 # define QACONTAINERFLAGS QACONTAINERFLAGS_SOMETHINGELSE
44 const GUID CLSID_ATSCLocator =
45 {0x8872FF1B,0x98FA,0x4D7A,{0x8D,0x93,0xC9,0xF1,0x05,0x5F,0x85,0xBB}};
46 const GUID CLSID_ATSCNetworkProvider =
47 {0x0dad2fdd,0x5fd7,0x11d3,{0x8f,0x50,0x00,0xc0,0x4f,0x79,0x71,0xe2}};
48 const GUID CLSID_DVBCLocator =
49 {0xc531d9fd,0x9685,0x4028,{0x8b,0x68,0x6e,0x12,0x32,0x07,0x9f,0x1e}};
50 const GUID CLSID_DVBCNetworkProvider =
51 {0xdc0c0fe7,0x0485,0x4266,{0xb9,0x3f,0x68,0xfb,0xf8,0xe,0xd8,0x34}};
52 const GUID CLSID_DVBSLocator =
53 {0x1df7d126,0x4050,0x47f0,{0xa7,0xcf,0x4c,0x4c,0xa9,0x24,0x13,0x33}};
54 const GUID CLSID_DVBSNetworkProvider =
55 {0xfa4b375a,0x45b4,0x4d45,{0x84,0x40,0x26,0x39,0x57,0xb1,0x16,0x23}};
56 const GUID CLSID_DVBSTuningSpace =
57 {0xb64016f3,0xc9a2,0x4066,{0x96,0xf0,0xbd,0x95,0x63,0x31,0x47,0x26}};
58 const GUID CLSID_DVBTLocator =
59 {0x9cd64701,0xbdf3,0x4d14,{0x8e,0x03,0xf1,0x29,0x83,0xd8,0x66,0x64}};
60 const GUID CLSID_DVBTNetworkProvider =
61 {0x216c62df,0x6d7f,0x4e9a,{0x85,0x71,0x05,0xf1,0x4e,0xdb,0x76,0x6a}};
62 const GUID CLSID_FilterGraph =
63 {0xe436ebb3,0x524f,0x11ce,{0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
64 const GUID CLSID_InfTee =
65 {0xf8388a40,0xd5bb,0x11d0,{0xbe,0x5a,0x00,0x80,0xc7,0x06,0x56,0x8e}};
66 const GUID CLSID_MPEG2Demultiplexer =
67 {0xafb6c280,0x2c41,0x11d3,{0x8a,0x60,0x00,0x00,0xf8,0x1e,0x0e,0x4a}};
68 const GUID CLSID_NullRenderer =
69 {0xc1f400a4,0x3f08,0x11d3,{0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37}};
70 const GUID CLSID_SampleGrabber =
71 {0xc1f400a0,0x3f08,0x11d3,{0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37}};
72 const GUID CLSID_SystemDeviceEnum =
73 {0x62be5d10,0x60eb,0x11d0,{0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86}};
74 const GUID CLSID_SystemTuningSpaces =
75 {0xd02aac50,0x027e,0x11d3,{0x9d,0x8e,0x00,0xc0,0x4f,0x72,0xd9,0x80}};
77 const GUID IID_IATSCChannelTuneRequest =
78 {0x0369B4E1,0x45B6,0x11d3,{0xB6,0x50,0x00,0xC0,0x4F,0x79,0x49,0x8E}};
79 const GUID IID_IATSCLocator =
80 {0xbf8d986f,0x8c2b,0x4131,{0x94,0xd7,0x4d,0x3d,0x9f,0xcc,0x21,0xef}};
81 const GUID IID_IBaseFilter =
82 {0x56a86895,0x0ad4,0x11ce,{0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
83 const GUID IID_ICreateDevEnum =
84 {0x29840822,0x5b84,0x11d0,{0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86}};
85 const GUID IID_IDVBTLocator =
86 {0x8664da16,0xdda2,0x42ac,{0x92,0x6a,0xc1,0x8f,0x91,0x27,0xc3,0x02}};
87 const GUID IID_IDVBCLocator =
88 {0x6e42f36e,0x1dd2,0x43c4,{0x9f,0x78,0x69,0xd2,0x5a,0xe3,0x90,0x34}};
89 const GUID IID_IDVBSLocator =
90 {0x3d7c353c,0x0d04,0x45f1,{0xa7,0x42,0xf9,0x7c,0xc1,0x18,0x8d,0xc8}};
91 const GUID IID_IDVBSTuningSpace =
92 {0xcdf7be60,0xd954,0x42fd,{0xa9,0x72,0x78,0x97,0x19,0x58,0xe4,0x70}};
93 const GUID IID_IDVBTuneRequest =
94 {0x0D6F567E,0xA636,0x42bb,{0x83,0xBA,0xCE,0x4C,0x17,0x04,0xAF,0xA2}};
95 const GUID IID_IGraphBuilder =
96 {0x56a868a9,0x0ad4,0x11ce,{0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
97 const GUID IID_IMediaControl =
98 {0x56a868b1,0x0ad4,0x11ce,{0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
99 const GUID IID_IMpeg2Demultiplexer =
100 {0x436eee9c,0x264f,0x4242,{0x90,0xe1,0x4e,0x33,0x0c,0x10,0x75,0x12}};
101 const GUID IID_ISampleGrabber =
102 {0x6b652fff,0x11fe,0x4fce,{0x92,0xad,0x02,0x66,0xb5,0xd7,0xc7,0x8f}};
103 const GUID IID_IScanningTuner =
104 {0x1dfd0a5c,0x0284,0x11d3,{0x9d,0x8e,0x00,0xc0,0x4f,0x72,0xd9,0x80}};
105 const GUID IID_ITuner =
106 {0x28C52640,0x018A,0x11d3,{0x9D,0x8E,0x00,0xC0,0x4F,0x72,0xD9,0x80}};
107 const GUID IID_ITuningSpace =
108 {0x061c6e30,0xe622,0x11d2,{0x94,0x93,0x00,0xc0,0x4f,0x72,0xd9,0x80}};
109 const GUID IID_ITuningSpaceContainer =
110 {0x5B692E84,0xE2F1,0x11d2,{0x94,0x93,0x00,0xC0,0x4F,0x72,0xD9,0x80}};
112 const GUID KSCATEGORY_BDA_TRANSPORT_INFORMATION =
113 {0xa2e3074f,0x6c3d,0x11d3,{0xb6,0x53,0x00,0xc0,0x4f,0x79,0x49,0x8e}};
114 const GUID KSCATEGORY_BDA_RECEIVER_COMPONENT =
115 {0xFD0A5AF4,0xB41D,0x11d2,{0x9c,0x95,0x00,0xc0,0x4f,0x79,0x71,0xe0}};
116 const GUID KSCATEGORY_BDA_NETWORK_TUNER =
117 {0x71985f48,0x1ca1,0x11d3,{0x9c,0xc8,0x00,0xc0,0x4f,0x79,0x71,0xe0}};
118 const GUID MEDIATYPE_MPEG2_SECTIONS =
119 {0x455f176c,0x4b06,0x47ce,{0x9a,0xef,0x8c,0xae,0xf7,0x3d,0xf7,0xb5}};
120 const GUID MEDIASUBTYPE_None =
121 {0xe436eb8e,0x524f,0x11ce,{0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
122 const GUID FORMAT_None =
123 {0x0f6417d6,0xc318,0x11d0,{0xa4,0x3f,0x00,0xa0,0xc9,0x22,0x31,0x96}};
125 /****************************************************************************
126 * Interfaces for calls from C
127 ****************************************************************************/
130 void dvb_newBDAGraph( access_t* p_access )
132 p_access->p_sys->p_bda_module = new BDAGraph( p_access );
135 void dvb_deleteBDAGraph( access_t* p_access )
137 delete p_access->p_sys->p_bda_module;
140 int dvb_SubmitATSCTuneRequest( access_t* p_access )
142 return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
145 int dvb_SubmitDVBTTuneRequest( access_t* p_access )
147 return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
150 int dvb_SubmitDVBCTuneRequest( access_t* p_access )
152 return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
155 int dvb_SubmitDVBSTuneRequest( access_t* p_access )
157 return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
160 long dvb_GetBufferSize( access_t* p_access )
162 return p_access->p_sys->p_bda_module->GetBufferSize();
165 long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
167 return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
173 /*****************************************************************************
175 *****************************************************************************/
176 BDAGraph::BDAGraph( access_t* p_this ):
178 guid_network_type(GUID_NULL),
180 d_graph_register( 0 )
182 p_tuning_space = NULL;
183 p_tune_request = NULL;
184 p_media_control = NULL;
185 p_filter_graph = NULL;
186 p_system_dev_enum = NULL;
187 p_network_provider = p_tuner_device = p_capture_device = NULL;
188 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
189 p_scanning_tuner = NULL;
192 /* Initialize COM - MS says to use CoInitializeEx in preference to
194 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
197 /*****************************************************************************
199 *****************************************************************************/
200 BDAGraph::~BDAGraph()
206 /*****************************************************************************
207 * Submit an ATSC Tune Request
208 *****************************************************************************/
209 int BDAGraph::SubmitATSCTuneRequest()
215 IATSCChannelTuneRequest* p_atsc_tune_request;
216 IATSCLocator* p_atsc_locator;
217 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
220 if( p_atsc_tune_request )
221 p_atsc_tune_request->Release();
223 p_atsc_locator->Release();
226 long l_major_channel, l_minor_channel, l_physical_channel;
228 l_major_channel = l_minor_channel = l_physical_channel = -1;
230 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
231 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
232 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
235 guid_network_type = CLSID_ATSCNetworkProvider;
236 hr = CreateTuneRequest();
239 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
240 "Cannot create Tuning Space: hr=0x%8lx", hr );
244 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
245 (void**)&l.p_atsc_tune_request );
248 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
249 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
252 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
253 IID_IATSCLocator, (void**)&l.p_atsc_locator );
256 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
257 "Cannot create the ATSC locator: hr=0x%8lx", hr );
262 if( l_major_channel > 0 )
263 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
264 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
265 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
266 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
267 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
270 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
271 "Cannot set tuning parameters: hr=0x%8lx", hr );
275 hr = p_tune_request->put_Locator( l.p_atsc_locator );
278 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
279 "Cannot put the locator: hr=0x%8lx", hr );
283 /* Build and Run the Graph. If a Tuner device is in use the graph will
284 * fail to run. Repeated calls to build will check successive tuner
291 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
292 "Cannot Build the Graph: hr=0x%8lx", hr );
302 /*****************************************************************************
303 * Submit a DVB-T Tune Request
304 ******************************************************************************/
305 int BDAGraph::SubmitDVBTTuneRequest()
311 IDVBTuneRequest* p_dvbt_tune_request;
312 IDVBTLocator* p_dvbt_locator;
313 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
316 if( p_dvbt_tune_request )
317 p_dvbt_tune_request->Release();
319 p_dvbt_locator->Release();
322 long l_frequency, l_bandwidth;
324 l_frequency = l_bandwidth = -1;
325 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
326 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
328 guid_network_type = CLSID_DVBTNetworkProvider;
329 hr = CreateTuneRequest();
332 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
333 "Cannot create Tune Request: hr=0x%8lx", hr );
337 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
338 (void**)&l.p_dvbt_tune_request );
341 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
342 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
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 );
349 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
350 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
353 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
354 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
359 if( l_frequency > 0 )
360 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
361 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
362 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
365 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
366 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
370 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
373 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
374 "Cannot put the locator: hr=0x%8lx", hr );
378 /* Build and Run the Graph. If a Tuner device is in use the graph will
379 * fail to run. Repeated calls to build will check successive tuner
386 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
387 "Cannot Build the Graph: hr=0x%8lx", hr );
397 /*****************************************************************************
398 * Submit a DVB-C Tune Request
399 ******************************************************************************/
400 int BDAGraph::SubmitDVBCTuneRequest()
407 IDVBTuneRequest* p_dvbc_tune_request;
408 IDVBCLocator* p_dvbc_locator;
409 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
412 if( p_dvbc_tune_request )
413 p_dvbc_tune_request->Release();
415 p_dvbc_locator->Release();
419 long l_frequency, l_symbolrate;
421 ModulationType i_qam_mod;
423 l_frequency = l_symbolrate = i_qam = -1;
424 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
425 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
426 i_qam = var_GetInteger( p_access, "dvb-modulation" );
427 i_qam_mod = BDA_MOD_NOT_SET;
429 i_qam_mod = BDA_MOD_16QAM;
431 i_qam_mod = BDA_MOD_32QAM;
433 i_qam_mod = BDA_MOD_64QAM;
435 i_qam_mod = BDA_MOD_128QAM;
437 i_qam_mod = BDA_MOD_256QAM;
439 guid_network_type = CLSID_DVBCNetworkProvider;
440 hr = CreateTuneRequest();
443 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
444 "Cannot create Tune Request: hr=0x%8lx", hr );
448 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
449 (void**)&l.p_dvbc_tune_request );
452 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
453 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
456 l.p_dvbc_tune_request->put_ONID( -1 );
457 l.p_dvbc_tune_request->put_SID( -1 );
458 l.p_dvbc_tune_request->put_TSID( -1 );
460 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
461 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
464 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
465 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
470 if( l_frequency > 0 )
471 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
472 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
473 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
474 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
475 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
478 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
479 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
483 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
486 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
487 "Cannot put the locator: hr=0x%8lx", hr );
491 /* Build and Run the Graph. If a Tuner device is in use the graph will
492 * fail to run. Repeated calls to build will check successive tuner
499 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
500 "Cannot Build the Graph: hr=0x%8lx", hr );
510 /*****************************************************************************
511 * Submit a DVB-S Tune Request
512 ******************************************************************************/
513 int BDAGraph::SubmitDVBSTuneRequest()
520 IDVBTuneRequest* p_dvbs_tune_request;
521 IDVBSLocator* p_dvbs_locator;
522 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL) {};
525 if( p_dvbs_tune_request )
526 p_dvbs_tune_request->Release();
528 p_dvbs_locator->Release();
531 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
532 char* psz_polarisation;
533 Polarisation i_polar;
536 l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
537 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
538 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
539 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
540 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
541 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
542 psz_polarisation = var_GetString( p_access, "dvb-polarisation" );
544 b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
546 i_polar = BDA_POLARISATION_NOT_SET;
547 if( *psz_polarisation == 'H' || *psz_polarisation == 'h' )
548 i_polar = BDA_POLARISATION_LINEAR_H;
549 if( *psz_polarisation == 'V' || *psz_polarisation == 'v' )
550 i_polar = BDA_POLARISATION_LINEAR_V;
551 if( *psz_polarisation == 'L' || *psz_polarisation == 'l' )
552 i_polar = BDA_POLARISATION_CIRCULAR_L;
553 if( *psz_polarisation == 'R' || *psz_polarisation == 'r' )
554 i_polar = BDA_POLARISATION_CIRCULAR_R;
556 guid_network_type = CLSID_DVBSNetworkProvider;
557 hr = CreateTuneRequest();
560 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
561 "Cannot create Tune Request: hr=0x%8lx", hr );
565 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
566 (void**)&l.p_dvbs_tune_request );
569 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
570 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
573 l.p_dvbs_tune_request->put_ONID( -1 );
574 l.p_dvbs_tune_request->put_SID( -1 );
575 l.p_dvbs_tune_request->put_TSID( -1 );
577 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
578 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
581 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
582 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
587 if( l_frequency > 0 )
588 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
589 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
590 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
591 if( SUCCEEDED( hr ) && l_azimuth > 0 )
592 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
593 if( SUCCEEDED( hr ) && l_elevation > 0 )
594 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
595 if( SUCCEEDED( hr ) )
596 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
597 if( SUCCEEDED( hr ) )
598 hr = l.p_dvbs_locator->put_WestPosition( b_west );
599 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
600 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
603 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
604 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
608 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
611 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
612 "Cannot put the locator: hr=0x%8lx", hr );
616 /* Build and Run the Graph. If a Tuner device is in use the graph will
617 * fail to run. Repeated calls to build will check successive tuner
624 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
625 "Cannot Build the Graph: hr=0x%8lx", hr );
635 /*****************************************************************************
636 * Load the Tuning Space from System Tuning Spaces according to the
637 * Network Type requested
638 ******************************************************************************/
639 HRESULT BDAGraph::CreateTuneRequest()
642 GUID guid_this_network_type;
646 ITuningSpaceContainer* p_tuning_space_container;
647 IEnumTuningSpaces* p_tuning_space_enum;
648 ITuningSpace* p_this_tuning_space;
649 localComPtr(): p_tuning_space_container(NULL),
650 p_tuning_space_enum(NULL), p_this_tuning_space(NULL) {};
653 if( p_tuning_space_container )
654 p_tuning_space_container->Release();
655 if( p_tuning_space_enum )
656 p_tuning_space_enum->Release();
657 if( p_this_tuning_space )
658 p_this_tuning_space->Release();
662 /* A Tuning Space may already have been set up. If it is for the same
663 * network type then all is well. Otherwise, reset the Tuning Space and get
667 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
668 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
669 if( guid_this_network_type == guid_network_type )
675 p_tuning_space->Release();
676 p_tuning_space = NULL;
680 /* Force use of the first available Tuner Device during Build */
683 /* Get the SystemTuningSpaces container to enumerate through all the
684 * defined tuning spaces */
685 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
686 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
689 msg_Warn( p_access, "CreateTuneRequest: "\
690 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
694 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
695 &l.p_tuning_space_enum );
698 msg_Warn( p_access, "CreateTuneRequest: "\
699 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
703 while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
706 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
708 /* GUID_NULL means a non-BDA network was found e.g analog
709 * Ignore failures and non-BDA networks and keep looking */
710 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
712 if( guid_this_network_type == guid_network_type )
714 hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
715 (void**)&p_tuning_space );
718 msg_Warn( p_access, "CreateTuneRequest: "\
719 "Cannot QI Tuning Space: hr=0x%8lx", hr );
722 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
725 msg_Warn( p_access, "CreateTuneRequest: "\
726 "Cannot Create Tune Request: hr=0x%8lx", hr );
735 msg_Warn( p_access, "CreateTuneRequest: "\
736 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
742 /******************************************************************************
744 * Step 4: Build the Filter Graph
745 * Build sets up devices, adds and connects filters
746 ******************************************************************************/
747 HRESULT BDAGraph::Build()
750 long l_capture_used, l_tif_used;
751 AM_MEDIA_TYPE grabber_media_type;
753 /* If we have already have a filter graph, rebuild it*/
756 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
757 IID_IGraphBuilder, (void**)&p_filter_graph );
760 msg_Warn( p_access, "Build: "\
761 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
765 /* First filter in the graph is the Network Provider and
766 * its Scanning Tuner which takes the Tune Request*/
767 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
768 IID_IBaseFilter, (void**)&p_network_provider);
771 msg_Warn( p_access, "Build: "\
772 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
775 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
778 msg_Warn( p_access, "Build: "\
779 "Cannot load network provider: hr=0x%8lx", hr );
783 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
784 (void**)&p_scanning_tuner );
787 msg_Warn( p_access, "Build: "\
788 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
792 hr = p_scanning_tuner->Validate( p_tune_request );
795 msg_Warn( p_access, "Build: "\
796 "Tune Request is invalid: hr=0x%8lx", hr );
799 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
802 msg_Warn( p_access, "Build: "\
803 "Cannot submit the tune request: hr=0x%8lx", hr );
807 /* Add the Network Tuner to the Network Provider. On subsequent calls,
808 * l_tuner_used will cause a different tuner to be selected */
809 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
810 p_network_provider, &p_tuner_device );
813 msg_Warn( p_access, "Build: "\
814 "Cannot load tuner device and connect network provider: "\
819 /* Always look for all capture devices to match the Network Tuner */
821 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
822 p_tuner_device, &p_capture_device );
825 /* Some BDA drivers do not provide a Capture Device Filter so force
826 * the Sample Grabber to connect directly to the Tuner Device */
827 p_capture_device = p_tuner_device;
828 p_tuner_device = NULL;
829 msg_Warn( p_access, "Build: "\
830 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
833 /* Insert the Sample Grabber to tap into the Transport Stream. */
834 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
835 IID_IBaseFilter, (void**)&p_sample_grabber );
838 msg_Warn( p_access, "Build: "\
839 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
842 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
845 msg_Warn( p_access, "Build: "\
846 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
850 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
851 (void**)&p_grabber );
854 msg_Warn( p_access, "Build: "\
855 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
859 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
860 grabber_media_type.majortype == MEDIATYPE_Stream;
861 grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
862 hr = p_grabber->SetMediaType( &grabber_media_type );
865 msg_Warn( p_access, "Build: "\
866 "Cannot set media type on grabber filter: hr=0x%8lx", hr );
869 hr = Connect( p_capture_device, p_sample_grabber );
872 msg_Warn( p_access, "Build: "\
873 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
877 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
878 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
879 * the Network Provider filter to set up the stream */
880 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
881 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
884 msg_Warn( p_access, "Build: "\
885 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
888 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
891 msg_Warn( p_access, "Build: "\
892 "Cannot add demux filter to graph: hr=0x%8lx", hr );
896 hr = Connect( p_sample_grabber, p_mpeg_demux );
899 msg_Warn( p_access, "Build: "\
900 "Cannot connect demux to grabber: hr=0x%8lx", hr );
904 /* Always look for the Transform Information Filter from the start
905 * of the collection*/
907 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
908 p_mpeg_demux, &p_transport_info );
911 msg_Warn( p_access, "Build: "\
912 "Cannot load TIF onto demux: hr=0x%8lx", hr );
916 /* Configure the Sample Grabber to buffer the samples continuously */
917 hr = p_grabber->SetBufferSamples( TRUE );
920 msg_Warn( p_access, "Build: "\
921 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
924 hr = p_grabber->SetOneShot( FALSE );
927 msg_Warn( p_access, "Build: "\
928 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
931 hr = p_grabber->SetCallback( this, 0 );
934 msg_Warn( p_access, "Build: "\
935 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
942 d_graph_register = 0;
945 /* The Media Control is used to Run and Stop the Graph */
946 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
947 (void**)&p_media_control );
950 msg_Warn( p_access, "Build: "\
951 "Cannot QI Media Control: hr=0x%8lx", hr );
957 /******************************************************************************
959 * Looks up all filters in a category and connects to the upstream filter until
960 * a successful match is found. The index of the connected filter is returned.
961 * On subsequent calls, this can be used to start from that point to find
963 * This is used when the graph does not run because a tuner device is in use so
964 * another one needs to be slected.
965 ******************************************************************************/
966 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
967 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
970 int i_moniker_index = -1;
975 IEnumMoniker* p_moniker_enum;
976 IBaseFilter* p_filter;
977 IPropertyBag* p_property_bag;
981 p_moniker_enum(NULL),
984 { ::VariantInit(&var_bstr); };
988 p_moniker->Release();
990 p_moniker_enum->Release();
994 p_property_bag->Release();
995 ::VariantClear(&var_bstr);
999 if( !p_system_dev_enum )
1001 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1002 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1005 msg_Warn( p_access, "FindFilter: "\
1006 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1011 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1012 &l.p_moniker_enum, 0 );
1015 msg_Warn( p_access, "FindFilter: "\
1016 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1019 while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
1023 /* Skip over devices already found on previous calls */
1024 if( i_moniker_index <= *i_moniker_used ) continue;
1025 *i_moniker_used = i_moniker_index;
1027 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1028 (void**)&l.p_filter );
1032 l.p_moniker->Release();
1035 l.p_filter->Release();
1040 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1041 (void**)&l.p_property_bag );
1044 msg_Warn( p_access, "FindFilter: "\
1045 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1049 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1052 msg_Warn( p_access, "FindFilter: "\
1053 "Cannot read filter friendly name: hr=0x%8lx", hr );
1057 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1060 msg_Warn( p_access, "FindFilter: "\
1061 "Cannot add filter: hr=0x%8lx", hr );
1065 hr = Connect( p_upstream, l.p_filter );
1066 if( SUCCEEDED( hr ) )
1068 msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
1069 l.p_filter->QueryInterface( IID_IBaseFilter,
1070 (void**)p_p_downstream );
1073 /* Not the filter we want so unload and try the next one */
1074 hr = p_filter_graph->RemoveFilter( l.p_filter );
1077 msg_Warn( p_access, "FindFilter: "\
1078 "Failed unloading Filter: hr=0x%8lx", hr );
1083 l.p_moniker->Release();
1086 l.p_filter->Release();
1091 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1095 /*****************************************************************************
1096 * Connect is called from Build to enumerate and connect pins
1097 *****************************************************************************/
1098 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1100 HRESULT hr = E_FAIL;
1104 IPin* p_pin_upstream;
1105 IPin* p_pin_downstream;
1106 IEnumPins* p_pin_upstream_enum;
1107 IEnumPins* p_pin_downstream_enum;
1109 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1110 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1111 p_pin_temp(NULL) { };
1114 if( p_pin_upstream )
1115 p_pin_upstream->Release();
1116 if( p_pin_downstream )
1117 p_pin_downstream->Release();
1118 if( p_pin_upstream_enum )
1119 p_pin_upstream_enum->Release();
1120 if( p_pin_downstream_enum )
1121 p_pin_downstream_enum->Release();
1123 p_pin_temp->Release();
1127 PIN_INFO pin_info_upstream;
1128 PIN_INFO pin_info_downstream;
1130 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1133 msg_Warn( p_access, "Connect: "\
1134 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1137 while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
1139 hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
1142 msg_Warn( p_access, "Connect: "\
1143 "Cannot get upstream filter pin information: hr=0x%8lx", hr );
1146 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1148 l.p_pin_downstream->Release();
1149 if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1151 msg_Warn( p_access, "Connect: "\
1152 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1155 if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
1156 ( hr == VFW_E_NOT_CONNECTED ) )
1158 /* The upstream pin is not yet connected so check each pin on the
1159 * downstream filter */
1160 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1163 msg_Warn( p_access, "Connect: Cannot get "\
1164 "downstream filter enumerator: hr=0x%8lx", hr );
1167 while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
1170 hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
1173 msg_Warn( p_access, "Connect: Cannot get "\
1174 "downstream filter pin information: hr=0x%8lx", hr );
1178 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1179 if( hr == S_OK ) l.p_pin_temp->Release();
1180 if( hr != VFW_E_NOT_CONNECTED )
1184 msg_Warn( p_access, "Connect: Cannot check "\
1185 "downstream filter connection: hr=0x%8lx", hr );
1189 if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
1190 ( hr == VFW_E_NOT_CONNECTED ) )
1192 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1193 l.p_pin_downstream, NULL );
1194 if( SUCCEEDED( hr ) )
1196 pin_info_downstream.pFilter->Release();
1197 pin_info_upstream.pFilter->Release();
1201 /* If we fall out here it means this downstream pin was not
1202 * suitable so try the next downstream pin */
1203 l.p_pin_downstream = NULL;
1204 pin_info_downstream.pFilter->Release();
1208 /* If we fall out here it means we did not find any suitable downstream
1209 * pin so try the next upstream pin */
1210 l.p_pin_upstream = NULL;
1211 pin_info_upstream.pFilter->Release();
1214 /* If we fall out here it means we did not find any pair of suitable pins */
1218 /*****************************************************************************
1219 * Start uses MediaControl to start the graph
1220 *****************************************************************************/
1221 HRESULT BDAGraph::Start()
1224 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1226 if( !p_media_control )
1228 msg_Dbg( p_access, "Start: Media Control has not been created" );
1231 hr = p_media_control->Run();
1235 /* Query the state of the graph - timeout after 100 milliseconds */
1236 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1241 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1245 if( i_state == State_Running )
1248 /* The Graph is not running so stop it and return an error */
1249 hr = p_media_control->Stop();
1253 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1259 /*****************************************************************************
1260 * Read the stream of data - query the buffer size required
1261 *****************************************************************************/
1262 long BDAGraph::GetBufferSize()
1264 while( queue_sample.empty() )
1267 long l_buffer_size = 0;
1270 /* Establish the length of the queue as it grows quickly. If the queue
1271 * size is checked dynamically there is a risk of not exiting the loop */
1272 l_queue_size = queue_sample.size();
1273 for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1275 l_buffer_size += queue_sample.front()->GetActualDataLength();
1276 queue_buffer.push( queue_sample.front() );
1279 return l_buffer_size;
1282 /*****************************************************************************
1283 * Read the stream of data - Retrieve from the buffer queue
1284 ******************************************************************************/
1285 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1292 while( !queue_buffer.empty() )
1294 queue_buffer.front()->GetPointer( &p_buff_temp );
1295 hr = queue_buffer.front()->IsDiscontinuity();
1298 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1299 memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1300 queue_buffer.front()->GetActualDataLength() );
1301 *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1302 queue_buffer.front()->Release();
1306 return *pl_buffer_len;
1309 /******************************************************************************
1310 * SampleCB - Callback when the Sample Grabber has a sample
1311 ******************************************************************************/
1312 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1315 queue_sample.push( p_sample );
1319 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1325 /******************************************************************************
1326 * removes each filter from the graph
1327 ******************************************************************************/
1328 HRESULT BDAGraph::Destroy()
1332 if( p_media_control )
1333 hr = p_media_control->Stop();
1335 if( p_transport_info )
1337 p_filter_graph->RemoveFilter( p_transport_info );
1338 p_transport_info->Release();
1339 p_transport_info = NULL;
1343 p_filter_graph->RemoveFilter( p_mpeg_demux );
1344 p_mpeg_demux->Release();
1345 p_mpeg_demux = NULL;
1347 if( p_sample_grabber )
1349 p_filter_graph->RemoveFilter( p_sample_grabber );
1350 p_sample_grabber->Release();
1351 p_sample_grabber = NULL;
1353 if( p_capture_device )
1355 p_filter_graph->RemoveFilter( p_capture_device );
1356 p_capture_device->Release();
1357 p_capture_device = NULL;
1359 if( p_tuner_device )
1361 p_filter_graph->RemoveFilter( p_tuner_device );
1362 p_tuner_device->Release();
1363 p_tuner_device = NULL;
1365 if( p_network_provider )
1367 p_filter_graph->RemoveFilter( p_network_provider );
1368 p_network_provider->Release();
1369 p_network_provider = NULL;
1372 if( p_scanning_tuner )
1374 p_scanning_tuner->Release();
1375 p_scanning_tuner = NULL;
1377 if( p_media_control )
1379 p_media_control->Release();
1380 p_media_control = NULL;
1382 if( p_scanning_tuner )
1384 p_filter_graph->Release();
1385 p_filter_graph = NULL;
1388 if( d_graph_register )
1396 /*****************************************************************************
1397 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1398 * Allows GraphEdit to "spy" on a remote filter graph.
1399 ******************************************************************************/
1400 HRESULT BDAGraph::Register()
1405 IMoniker* p_moniker;
1406 IRunningObjectTable* p_ro_table;
1407 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1411 p_moniker->Release();
1413 p_ro_table->Release();
1416 WCHAR psz_w_graph_name[128];
1419 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1422 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1426 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1427 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1428 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1429 if( SUCCEEDED( hr ) )
1430 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1431 p_filter_graph, l.p_moniker, &d_graph_register );
1436 void BDAGraph::Deregister()
1438 IRunningObjectTable* p_ro_table;
1439 if( SUCCEEDED( ::GetRunningObjectTable( 0, &p_ro_table ) ) )
1440 p_ro_table->Revoke( d_graph_register );
1441 d_graph_register = 0;
1442 p_ro_table->Release();