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 *****************************************************************************/
28 /****************************************************************************
29 * Interfaces for calls from C
30 ****************************************************************************/
33 void dvb_newBDAGraph( access_t* p_access )
35 p_access->p_sys->p_bda_module = new BDAGraph( p_access );
38 void dvb_deleteBDAGraph( access_t* p_access )
40 if( p_access->p_sys->p_bda_module )
41 delete p_access->p_sys->p_bda_module;
44 int dvb_SubmitATSCTuneRequest( access_t* p_access )
46 if( p_access->p_sys->p_bda_module )
47 return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
51 int dvb_SubmitDVBTTuneRequest( access_t* p_access )
53 if( p_access->p_sys->p_bda_module )
54 return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
58 int dvb_SubmitDVBCTuneRequest( access_t* p_access )
60 if( p_access->p_sys->p_bda_module )
61 return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
65 int dvb_SubmitDVBSTuneRequest( access_t* p_access )
67 if( p_access->p_sys->p_bda_module )
68 return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
72 long dvb_GetBufferSize( access_t* p_access )
74 if( p_access->p_sys->p_bda_module )
75 return p_access->p_sys->p_bda_module->GetBufferSize();
79 long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
81 if( p_access->p_sys->p_bda_module )
82 return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
88 /*****************************************************************************
90 *****************************************************************************/
91 BDAGraph::BDAGraph( access_t* p_this ):
93 guid_network_type(GUID_NULL),
98 p_tuning_space = NULL;
99 p_tune_request = NULL;
100 p_media_control = NULL;
101 p_filter_graph = NULL;
102 p_system_dev_enum = NULL;
103 p_network_provider = p_tuner_device = p_capture_device = NULL;
104 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
105 p_scanning_tuner = NULL;
108 /* Initialize COM - MS says to use CoInitializeEx in preference to
110 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
113 /*****************************************************************************
115 *****************************************************************************/
116 BDAGraph::~BDAGraph()
122 /*****************************************************************************
123 * Submit an ATSC Tune Request
124 *****************************************************************************/
125 int BDAGraph::SubmitATSCTuneRequest()
131 IATSCChannelTuneRequest* p_atsc_tune_request;
132 IATSCLocator* p_atsc_locator;
133 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
136 if( p_atsc_tune_request )
137 p_atsc_tune_request->Release();
139 p_atsc_locator->Release();
142 long l_major_channel, l_minor_channel, l_physical_channel;
144 l_major_channel = l_minor_channel = l_physical_channel = -1;
146 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
147 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
148 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
151 guid_network_type = CLSID_ATSCNetworkProvider;
152 hr = CreateTuneRequest();
155 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
156 "Cannot create Tuning Space: hr=0x%8lx", hr );
160 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
161 (void**)&l.p_atsc_tune_request );
164 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
165 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
168 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
169 IID_IATSCLocator, (void**)&l.p_atsc_locator );
172 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
173 "Cannot create the ATSC locator: hr=0x%8lx", hr );
178 if( l_major_channel > 0 )
179 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
180 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
181 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
182 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
183 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
186 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
187 "Cannot set tuning parameters: hr=0x%8lx", hr );
191 hr = p_tune_request->put_Locator( l.p_atsc_locator );
194 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
195 "Cannot put the locator: hr=0x%8lx", hr );
199 /* Build and Run the Graph. If a Tuner device is in use the graph will
200 * fail to run. Repeated calls to build will check successive tuner
207 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
208 "Cannot Build the Graph: hr=0x%8lx", hr );
218 /*****************************************************************************
219 * Submit a DVB-T Tune Request
220 ******************************************************************************/
221 int BDAGraph::SubmitDVBTTuneRequest()
227 IDVBTuneRequest* p_dvbt_tune_request;
228 IDVBTLocator* p_dvbt_locator;
229 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
232 if( p_dvbt_tune_request )
233 p_dvbt_tune_request->Release();
235 p_dvbt_locator->Release();
238 long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
239 long l_transmission, l_hierarchy;
240 BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
241 GuardInterval i_guard;
242 TransmissionMode i_transmission;
243 HierarchyAlpha i_hierarchy;
245 l_frequency = l_bandwidth = l_hp_fec = l_lp_fec = l_guard = -1;
246 l_transmission = l_hierarchy = -1;
247 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
248 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
249 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
250 l_lp_fec = var_GetInteger( p_access, "dvb-code-rate-lp" );
251 l_guard = var_GetInteger( p_access, "dvb-guard" );
252 l_transmission = var_GetInteger( p_access, "dvb-transmission" );
253 l_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
255 i_hp_fec = BDA_BCC_RATE_NOT_SET;
257 i_hp_fec = BDA_BCC_RATE_1_2;
259 i_hp_fec = BDA_BCC_RATE_2_3;
261 i_hp_fec = BDA_BCC_RATE_3_4;
263 i_hp_fec = BDA_BCC_RATE_5_6;
265 i_hp_fec = BDA_BCC_RATE_7_8;
267 i_lp_fec = BDA_BCC_RATE_NOT_SET;
269 i_lp_fec = BDA_BCC_RATE_1_2;
271 i_lp_fec = BDA_BCC_RATE_2_3;
273 i_lp_fec = BDA_BCC_RATE_3_4;
275 i_lp_fec = BDA_BCC_RATE_5_6;
277 i_lp_fec = BDA_BCC_RATE_7_8;
279 i_guard = BDA_GUARD_NOT_SET;
281 i_guard = BDA_GUARD_1_32;
283 i_guard = BDA_GUARD_1_16;
285 i_guard = BDA_GUARD_1_8;
287 i_guard = BDA_GUARD_1_4;
289 i_transmission = BDA_XMIT_MODE_NOT_SET;
290 if( l_transmission == 2 )
291 i_transmission = BDA_XMIT_MODE_2K;
292 if( l_transmission == 8 )
293 i_transmission = BDA_XMIT_MODE_8K;
295 i_hierarchy = BDA_HALPHA_NOT_SET;
296 if( l_hierarchy == 1 )
297 i_hierarchy = BDA_HALPHA_1;
298 if( l_hierarchy == 2 )
299 i_hierarchy = BDA_HALPHA_2;
300 if( l_hierarchy == 4 )
301 i_hierarchy = BDA_HALPHA_4;
303 guid_network_type = CLSID_DVBTNetworkProvider;
304 hr = CreateTuneRequest();
307 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
308 "Cannot create Tune Request: hr=0x%8lx", hr );
312 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
313 (void**)&l.p_dvbt_tune_request );
316 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
317 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
320 l.p_dvbt_tune_request->put_ONID( -1 );
321 l.p_dvbt_tune_request->put_SID( -1 );
322 l.p_dvbt_tune_request->put_TSID( -1 );
324 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
325 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
328 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
329 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
334 if( l_frequency > 0 )
335 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
336 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
337 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
338 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
339 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
340 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
341 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
342 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
343 hr = l.p_dvbt_locator->put_Guard( i_guard );
344 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
345 hr = l.p_dvbt_locator->put_Mode( i_transmission );
346 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
347 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
350 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
351 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
355 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
358 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
359 "Cannot put the locator: hr=0x%8lx", hr );
363 /* Build and Run the Graph. If a Tuner device is in use the graph will
364 * fail to run. Repeated calls to build will check successive tuner
371 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
372 "Cannot Build the Graph: hr=0x%8lx", hr );
382 /*****************************************************************************
383 * Submit a DVB-C Tune Request
384 ******************************************************************************/
385 int BDAGraph::SubmitDVBCTuneRequest()
392 IDVBTuneRequest* p_dvbc_tune_request;
393 IDVBCLocator* p_dvbc_locator;
394 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
397 if( p_dvbc_tune_request )
398 p_dvbc_tune_request->Release();
400 p_dvbc_locator->Release();
404 long l_frequency, l_symbolrate;
406 ModulationType i_qam_mod;
408 l_frequency = l_symbolrate = i_qam = -1;
409 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
410 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
411 i_qam = var_GetInteger( p_access, "dvb-modulation" );
412 i_qam_mod = BDA_MOD_NOT_SET;
414 i_qam_mod = BDA_MOD_16QAM;
416 i_qam_mod = BDA_MOD_32QAM;
418 i_qam_mod = BDA_MOD_64QAM;
420 i_qam_mod = BDA_MOD_128QAM;
422 i_qam_mod = BDA_MOD_256QAM;
424 guid_network_type = CLSID_DVBCNetworkProvider;
425 hr = CreateTuneRequest();
428 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
429 "Cannot create Tune Request: hr=0x%8lx", hr );
433 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
434 (void**)&l.p_dvbc_tune_request );
437 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
438 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
441 l.p_dvbc_tune_request->put_ONID( -1 );
442 l.p_dvbc_tune_request->put_SID( -1 );
443 l.p_dvbc_tune_request->put_TSID( -1 );
445 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
446 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
449 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
450 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
455 if( l_frequency > 0 )
456 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
457 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
458 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
459 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
460 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
463 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
464 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
468 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
471 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
472 "Cannot put the locator: hr=0x%8lx", hr );
476 /* Build and Run the Graph. If a Tuner device is in use the graph will
477 * fail to run. Repeated calls to build will check successive tuner
484 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
485 "Cannot Build the Graph: hr=0x%8lx", hr );
495 /*****************************************************************************
496 * Submit a DVB-S Tune Request
497 ******************************************************************************/
498 int BDAGraph::SubmitDVBSTuneRequest()
505 IDVBTuneRequest* p_dvbs_tune_request;
506 IDVBSLocator* p_dvbs_locator;
507 IDVBSTuningSpace* p_dvbs_tuning_space;
508 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
509 p_dvbs_tuning_space(NULL) {};
512 if( p_dvbs_tuning_space )
513 p_dvbs_tuning_space->Release();
514 if( p_dvbs_tune_request )
515 p_dvbs_tune_request->Release();
517 p_dvbs_locator->Release();
520 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
521 long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
522 char* psz_polarisation;
523 Polarisation i_polar;
524 SpectralInversion i_inversion;
527 l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
528 l_lnb_lof1 = l_lnb_lof2 = l_lnb_slof = l_inversion = l_network_id = -1;
529 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
530 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
531 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
532 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
533 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
534 l_lnb_lof1 = var_GetInteger( p_access, "dvb-lnb-lof1" );
535 l_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
536 l_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
537 psz_polarisation = var_GetString( p_access, "dvb-polarisation" );
538 l_inversion = var_GetInteger( p_access, "dvb-inversion" );
539 l_network_id = var_GetInteger( p_access, "dvb-network_id" );
541 b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
543 i_polar = BDA_POLARISATION_NOT_SET;
544 if( *psz_polarisation == 'H' || *psz_polarisation == 'h' )
545 i_polar = BDA_POLARISATION_LINEAR_H;
546 if( *psz_polarisation == 'V' || *psz_polarisation == 'v' )
547 i_polar = BDA_POLARISATION_LINEAR_V;
548 if( *psz_polarisation == 'L' || *psz_polarisation == 'l' )
549 i_polar = BDA_POLARISATION_CIRCULAR_L;
550 if( *psz_polarisation == 'R' || *psz_polarisation == 'r' )
551 i_polar = BDA_POLARISATION_CIRCULAR_R;
553 i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
554 if( l_inversion == 0 )
555 i_inversion = BDA_SPECTRAL_INVERSION_NORMAL;
556 if( l_inversion == 1 )
557 i_inversion = BDA_SPECTRAL_INVERSION_INVERTED;
558 if( l_inversion == 2 )
559 i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC;
561 guid_network_type = CLSID_DVBSNetworkProvider;
562 hr = CreateTuneRequest();
565 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
566 "Cannot create Tune Request: hr=0x%8lx", hr );
570 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
571 (void**)&l.p_dvbs_tune_request );
574 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
575 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
578 l.p_dvbs_tune_request->put_ONID( -1 );
579 l.p_dvbs_tune_request->put_SID( -1 );
580 l.p_dvbs_tune_request->put_TSID( -1 );
582 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
583 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
586 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
587 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
591 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
592 (void**)&l.p_dvbs_tuning_space );
595 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
596 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
601 if( l_frequency > 0 )
602 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
603 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
604 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
605 if( SUCCEEDED( hr ) && l_azimuth > 0 )
606 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
607 if( SUCCEEDED( hr ) && l_elevation > 0 )
608 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
609 if( SUCCEEDED( hr ) )
610 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
611 if( SUCCEEDED( hr ) )
612 hr = l.p_dvbs_locator->put_WestPosition( b_west );
613 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
614 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
615 if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
616 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
617 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
618 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
619 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
620 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
621 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
622 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
623 if( SUCCEEDED( hr ) && l_network_id > 0 )
624 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
627 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
628 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
632 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
635 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
636 "Cannot put the locator: hr=0x%8lx", hr );
640 /* Build and Run the Graph. If a Tuner device is in use the graph will
641 * fail to run. Repeated calls to build will check successive tuner
648 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
649 "Cannot Build the Graph: hr=0x%8lx", hr );
659 /*****************************************************************************
660 * Load the Tuning Space from System Tuning Spaces according to the
661 * Network Type requested
662 ******************************************************************************/
663 HRESULT BDAGraph::CreateTuneRequest()
666 GUID guid_this_network_type;
670 ITuningSpaceContainer* p_tuning_space_container;
671 IEnumTuningSpaces* p_tuning_space_enum;
672 ITuningSpace* p_this_tuning_space;
673 localComPtr(): p_tuning_space_container(NULL),
674 p_tuning_space_enum(NULL), p_this_tuning_space(NULL) {};
677 if( p_tuning_space_container )
678 p_tuning_space_container->Release();
679 if( p_tuning_space_enum )
680 p_tuning_space_enum->Release();
681 if( p_this_tuning_space )
682 p_this_tuning_space->Release();
686 /* A Tuning Space may already have been set up. If it is for the same
687 * network type then all is well. Otherwise, reset the Tuning Space and get
691 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
692 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
693 if( guid_this_network_type == guid_network_type )
699 p_tuning_space->Release();
700 p_tuning_space = NULL;
704 /* Force use of the first available Tuner Device during Build */
707 /* Get the SystemTuningSpaces container to enumerate through all the
708 * defined tuning spaces */
709 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
710 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
713 msg_Warn( p_access, "CreateTuneRequest: "\
714 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
718 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
719 &l.p_tuning_space_enum );
722 msg_Warn( p_access, "CreateTuneRequest: "\
723 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
727 while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
730 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
732 /* GUID_NULL means a non-BDA network was found e.g analog
733 * Ignore failures and non-BDA networks and keep looking */
734 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
736 if( guid_this_network_type == guid_network_type )
738 hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
739 (void**)&p_tuning_space );
742 msg_Warn( p_access, "CreateTuneRequest: "\
743 "Cannot QI Tuning Space: hr=0x%8lx", hr );
746 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
749 msg_Warn( p_access, "CreateTuneRequest: "\
750 "Cannot Create Tune Request: hr=0x%8lx", hr );
759 msg_Warn( p_access, "CreateTuneRequest: "\
760 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
766 /******************************************************************************
768 * Step 4: Build the Filter Graph
769 * Build sets up devices, adds and connects filters
770 ******************************************************************************/
771 HRESULT BDAGraph::Build()
774 long l_capture_used, l_tif_used;
775 AM_MEDIA_TYPE grabber_media_type;
777 /* If we have already have a filter graph, rebuild it*/
780 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
781 IID_IGraphBuilder, (void**)&p_filter_graph );
784 msg_Warn( p_access, "Build: "\
785 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
789 /* First filter in the graph is the Network Provider and
790 * its Scanning Tuner which takes the Tune Request*/
791 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
792 IID_IBaseFilter, (void**)&p_network_provider);
795 msg_Warn( p_access, "Build: "\
796 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
799 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
802 msg_Warn( p_access, "Build: "\
803 "Cannot load network provider: hr=0x%8lx", hr );
807 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
808 (void**)&p_scanning_tuner );
811 msg_Warn( p_access, "Build: "\
812 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
816 hr = p_scanning_tuner->Validate( p_tune_request );
819 msg_Warn( p_access, "Build: "\
820 "Tune Request is invalid: hr=0x%8lx", hr );
823 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
826 msg_Warn( p_access, "Build: "\
827 "Cannot submit the tune request: hr=0x%8lx", hr );
831 /* Add the Network Tuner to the Network Provider. On subsequent calls,
832 * l_tuner_used will cause a different tuner to be selected */
833 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
834 p_network_provider, &p_tuner_device );
837 msg_Warn( p_access, "Build: "\
838 "Cannot load tuner device and connect network provider: "\
843 /* Always look for all capture devices to match the Network Tuner */
845 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
846 p_tuner_device, &p_capture_device );
849 /* Some BDA drivers do not provide a Capture Device Filter so force
850 * the Sample Grabber to connect directly to the Tuner Device */
851 p_capture_device = p_tuner_device;
852 p_tuner_device = NULL;
853 msg_Warn( p_access, "Build: "\
854 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
857 /* Insert the Sample Grabber to tap into the Transport Stream. */
858 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
859 IID_IBaseFilter, (void**)&p_sample_grabber );
862 msg_Warn( p_access, "Build: "\
863 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
866 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
869 msg_Warn( p_access, "Build: "\
870 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
874 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
875 (void**)&p_grabber );
878 msg_Warn( p_access, "Build: "\
879 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
883 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
884 grabber_media_type.majortype == MEDIATYPE_Stream;
885 grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
886 hr = p_grabber->SetMediaType( &grabber_media_type );
889 msg_Warn( p_access, "Build: "\
890 "Cannot set media type on grabber filter: hr=0x%8lx", hr );
893 hr = Connect( p_capture_device, p_sample_grabber );
896 msg_Warn( p_access, "Build: "\
897 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
901 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
902 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
903 * the Network Provider filter to set up the stream */
904 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
905 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
908 msg_Warn( p_access, "Build: "\
909 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
912 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
915 msg_Warn( p_access, "Build: "\
916 "Cannot add demux filter to graph: hr=0x%8lx", hr );
920 hr = Connect( p_sample_grabber, p_mpeg_demux );
923 msg_Warn( p_access, "Build: "\
924 "Cannot connect demux to grabber: hr=0x%8lx", hr );
928 /* Always look for the Transform Information Filter from the start
929 * of the collection*/
931 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
932 p_mpeg_demux, &p_transport_info );
935 msg_Warn( p_access, "Build: "\
936 "Cannot load TIF onto demux: hr=0x%8lx", hr );
940 /* Configure the Sample Grabber to buffer the samples continuously */
941 hr = p_grabber->SetBufferSamples( TRUE );
944 msg_Warn( p_access, "Build: "\
945 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
948 hr = p_grabber->SetOneShot( FALSE );
951 msg_Warn( p_access, "Build: "\
952 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
955 hr = p_grabber->SetCallback( this, 0 );
958 msg_Warn( p_access, "Build: "\
959 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
966 d_graph_register = 0;
969 /* The Media Control is used to Run and Stop the Graph */
970 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
971 (void**)&p_media_control );
974 msg_Warn( p_access, "Build: "\
975 "Cannot QI Media Control: hr=0x%8lx", hr );
981 /******************************************************************************
983 * Looks up all filters in a category and connects to the upstream filter until
984 * a successful match is found. The index of the connected filter is returned.
985 * On subsequent calls, this can be used to start from that point to find
987 * This is used when the graph does not run because a tuner device is in use so
988 * another one needs to be slected.
989 ******************************************************************************/
990 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
991 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
994 int i_moniker_index = -1;
999 IEnumMoniker* p_moniker_enum;
1000 IBaseFilter* p_filter;
1001 IPropertyBag* p_property_bag;
1005 p_moniker_enum(NULL),
1007 p_property_bag(NULL)
1008 { ::VariantInit(&var_bstr); };
1012 p_moniker->Release();
1013 if( p_moniker_enum )
1014 p_moniker_enum->Release();
1016 p_filter->Release();
1017 if( p_property_bag )
1018 p_property_bag->Release();
1019 ::VariantClear(&var_bstr);
1023 if( !p_system_dev_enum )
1025 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1026 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1029 msg_Warn( p_access, "FindFilter: "\
1030 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1035 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1036 &l.p_moniker_enum, 0 );
1039 msg_Warn( p_access, "FindFilter: "\
1040 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1043 while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
1047 /* Skip over devices already found on previous calls */
1048 if( i_moniker_index <= *i_moniker_used ) continue;
1049 *i_moniker_used = i_moniker_index;
1051 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1052 (void**)&l.p_filter );
1056 l.p_moniker->Release();
1059 l.p_filter->Release();
1064 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1065 (void**)&l.p_property_bag );
1068 msg_Warn( p_access, "FindFilter: "\
1069 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1073 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1076 msg_Warn( p_access, "FindFilter: "\
1077 "Cannot read filter friendly name: hr=0x%8lx", hr );
1081 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1084 msg_Warn( p_access, "FindFilter: "\
1085 "Cannot add filter: hr=0x%8lx", hr );
1089 hr = Connect( p_upstream, l.p_filter );
1090 if( SUCCEEDED( hr ) )
1092 msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
1093 l.p_filter->QueryInterface( IID_IBaseFilter,
1094 (void**)p_p_downstream );
1097 /* Not the filter we want so unload and try the next one */
1098 hr = p_filter_graph->RemoveFilter( l.p_filter );
1101 msg_Warn( p_access, "FindFilter: "\
1102 "Failed unloading Filter: hr=0x%8lx", hr );
1107 l.p_moniker->Release();
1110 l.p_filter->Release();
1115 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1119 /*****************************************************************************
1120 * Connect is called from Build to enumerate and connect pins
1121 *****************************************************************************/
1122 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1124 HRESULT hr = E_FAIL;
1128 IPin* p_pin_upstream;
1129 IPin* p_pin_downstream;
1130 IEnumPins* p_pin_upstream_enum;
1131 IEnumPins* p_pin_downstream_enum;
1133 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1134 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1135 p_pin_temp(NULL) { };
1138 if( p_pin_upstream )
1139 p_pin_upstream->Release();
1140 if( p_pin_downstream )
1141 p_pin_downstream->Release();
1142 if( p_pin_upstream_enum )
1143 p_pin_upstream_enum->Release();
1144 if( p_pin_downstream_enum )
1145 p_pin_downstream_enum->Release();
1147 p_pin_temp->Release();
1151 PIN_INFO pin_info_upstream;
1152 PIN_INFO pin_info_downstream;
1154 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1157 msg_Warn( p_access, "Connect: "\
1158 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1161 while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
1163 hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
1166 msg_Warn( p_access, "Connect: "\
1167 "Cannot get upstream filter pin information: hr=0x%8lx", hr );
1170 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1172 l.p_pin_downstream->Release();
1173 if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1175 msg_Warn( p_access, "Connect: "\
1176 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1179 if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
1180 ( hr == VFW_E_NOT_CONNECTED ) )
1182 /* The upstream pin is not yet connected so check each pin on the
1183 * downstream filter */
1184 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1187 msg_Warn( p_access, "Connect: Cannot get "\
1188 "downstream filter enumerator: hr=0x%8lx", hr );
1191 while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
1194 hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
1197 msg_Warn( p_access, "Connect: Cannot get "\
1198 "downstream filter pin information: hr=0x%8lx", hr );
1202 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1203 if( hr == S_OK ) l.p_pin_temp->Release();
1204 if( hr != VFW_E_NOT_CONNECTED )
1208 msg_Warn( p_access, "Connect: Cannot check "\
1209 "downstream filter connection: hr=0x%8lx", hr );
1213 if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
1214 ( hr == VFW_E_NOT_CONNECTED ) )
1216 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1217 l.p_pin_downstream, NULL );
1218 if( SUCCEEDED( hr ) )
1220 pin_info_downstream.pFilter->Release();
1221 pin_info_upstream.pFilter->Release();
1225 /* If we fall out here it means this downstream pin was not
1226 * suitable so try the next downstream pin */
1227 l.p_pin_downstream = NULL;
1228 pin_info_downstream.pFilter->Release();
1232 /* If we fall out here it means we did not find any suitable downstream
1233 * pin so try the next upstream pin */
1234 l.p_pin_upstream = NULL;
1235 pin_info_upstream.pFilter->Release();
1238 /* If we fall out here it means we did not find any pair of suitable pins */
1242 /*****************************************************************************
1243 * Start uses MediaControl to start the graph
1244 *****************************************************************************/
1245 HRESULT BDAGraph::Start()
1248 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1250 if( !p_media_control )
1252 msg_Dbg( p_access, "Start: Media Control has not been created" );
1255 hr = p_media_control->Run();
1259 /* Query the state of the graph - timeout after 100 milliseconds */
1260 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1265 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1269 if( i_state == State_Running )
1272 /* The Graph is not running so stop it and return an error */
1273 msg_Warn( p_access, "Start: Graph not started: %d", i_state );
1274 hr = p_media_control->Stop();
1278 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1284 /*****************************************************************************
1285 * Read the stream of data - query the buffer size required
1286 *****************************************************************************/
1287 long BDAGraph::GetBufferSize()
1289 long l_buffer_size = 0;
1294 for( int i_timer = 0; queue_sample.empty() && i_timer < 200; i_timer++ )
1297 l_queue_size = queue_sample.size();
1298 if( l_queue_size <= 0 )
1300 msg_Warn( p_access, "BDA GetBufferSize: Timed Out waiting for sample" );
1304 /* Establish the length of the queue as it grows quickly. If the queue
1305 * size is checked dynamically there is a risk of not exiting the loop */
1306 for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1308 l_buffer_size += queue_sample.front()->GetActualDataLength();
1309 queue_buffer.push( queue_sample.front() );
1312 return l_buffer_size;
1315 /*****************************************************************************
1316 * Read the stream of data - Retrieve from the buffer queue
1317 ******************************************************************************/
1318 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1325 while( !queue_buffer.empty() )
1327 queue_buffer.front()->GetPointer( &p_buff_temp );
1328 hr = queue_buffer.front()->IsDiscontinuity();
1331 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1332 memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1333 queue_buffer.front()->GetActualDataLength() );
1334 *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1335 queue_buffer.front()->Release();
1339 return *pl_buffer_len;
1342 /******************************************************************************
1343 * SampleCB - Callback when the Sample Grabber has a sample
1344 ******************************************************************************/
1345 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1350 queue_sample.push( p_sample );
1354 msg_Warn( p_access, "BDA SampleCB: Not ready - dropped sample" );
1359 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1365 /******************************************************************************
1366 * removes each filter from the graph
1367 ******************************************************************************/
1368 HRESULT BDAGraph::Destroy()
1372 if( p_media_control )
1373 hr = p_media_control->Stop();
1375 if( p_transport_info )
1377 p_filter_graph->RemoveFilter( p_transport_info );
1378 p_transport_info->Release();
1379 p_transport_info = NULL;
1383 p_filter_graph->RemoveFilter( p_mpeg_demux );
1384 p_mpeg_demux->Release();
1385 p_mpeg_demux = NULL;
1387 if( p_sample_grabber )
1389 p_filter_graph->RemoveFilter( p_sample_grabber );
1390 p_sample_grabber->Release();
1391 p_sample_grabber = NULL;
1393 if( p_capture_device )
1395 p_filter_graph->RemoveFilter( p_capture_device );
1396 p_capture_device->Release();
1397 p_capture_device = NULL;
1399 if( p_tuner_device )
1401 p_filter_graph->RemoveFilter( p_tuner_device );
1402 p_tuner_device->Release();
1403 p_tuner_device = NULL;
1405 if( p_network_provider )
1407 p_filter_graph->RemoveFilter( p_network_provider );
1408 p_network_provider->Release();
1409 p_network_provider = NULL;
1412 if( p_scanning_tuner )
1414 p_scanning_tuner->Release();
1415 p_scanning_tuner = NULL;
1417 if( p_media_control )
1419 p_media_control->Release();
1420 p_media_control = NULL;
1422 if( p_filter_graph )
1424 p_filter_graph->Release();
1425 p_filter_graph = NULL;
1428 if( d_graph_register )
1436 /*****************************************************************************
1437 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1438 * Allows GraphEdit to "spy" on a remote filter graph.
1439 ******************************************************************************/
1440 HRESULT BDAGraph::Register()
1445 IMoniker* p_moniker;
1446 IRunningObjectTable* p_ro_table;
1447 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1451 p_moniker->Release();
1453 p_ro_table->Release();
1456 WCHAR psz_w_graph_name[128];
1459 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1462 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1466 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1467 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1468 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1471 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1474 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1475 p_filter_graph, l.p_moniker, &d_graph_register );
1478 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1481 msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1485 void BDAGraph::Deregister()
1488 IRunningObjectTable* p_ro_table;
1489 hr = ::GetRunningObjectTable( 0, &p_ro_table );
1490 if( SUCCEEDED( hr ) )
1491 p_ro_table->Revoke( d_graph_register );
1492 d_graph_register = 0;
1493 p_ro_table->Release();