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 *****************************************************************************/
29 /****************************************************************************
30 * Interfaces for calls from C
31 ****************************************************************************/
34 void dvb_newBDAGraph( access_t* p_access )
36 p_access->p_sys->p_bda_module = new BDAGraph( p_access );
39 void dvb_deleteBDAGraph( access_t* p_access )
41 if( p_access->p_sys->p_bda_module )
42 delete p_access->p_sys->p_bda_module;
45 int dvb_SubmitATSCTuneRequest( access_t* p_access )
47 if( p_access->p_sys->p_bda_module )
48 return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
52 int dvb_SubmitDVBTTuneRequest( access_t* p_access )
54 if( p_access->p_sys->p_bda_module )
55 return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
59 int dvb_SubmitDVBCTuneRequest( access_t* p_access )
61 if( p_access->p_sys->p_bda_module )
62 return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
66 int dvb_SubmitDVBSTuneRequest( access_t* p_access )
68 if( p_access->p_sys->p_bda_module )
69 return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
73 long dvb_GetBufferSize( access_t* p_access )
75 if( p_access->p_sys->p_bda_module )
76 return p_access->p_sys->p_bda_module->GetBufferSize();
80 long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
82 if( p_access->p_sys->p_bda_module )
83 return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
89 /*****************************************************************************
91 *****************************************************************************/
92 BDAGraph::BDAGraph( access_t* p_this ):
94 guid_network_type(GUID_NULL),
99 p_tuning_space = NULL;
100 p_tune_request = NULL;
101 p_media_control = NULL;
102 p_filter_graph = NULL;
103 p_system_dev_enum = NULL;
104 p_network_provider = p_tuner_device = p_capture_device = NULL;
105 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
106 p_scanning_tuner = NULL;
109 /* Initialize COM - MS says to use CoInitializeEx in preference to
111 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
114 /*****************************************************************************
116 *****************************************************************************/
117 BDAGraph::~BDAGraph()
123 /*****************************************************************************
124 * Submit an ATSC Tune Request
125 *****************************************************************************/
126 int BDAGraph::SubmitATSCTuneRequest()
132 IATSCChannelTuneRequest* p_atsc_tune_request;
133 IATSCLocator* p_atsc_locator;
134 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
137 if( p_atsc_tune_request )
138 p_atsc_tune_request->Release();
140 p_atsc_locator->Release();
143 long l_major_channel, l_minor_channel, l_physical_channel;
145 l_major_channel = l_minor_channel = l_physical_channel = -1;
147 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
148 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
149 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
152 guid_network_type = CLSID_ATSCNetworkProvider;
153 hr = CreateTuneRequest();
156 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
157 "Cannot create Tuning Space: hr=0x%8lx", hr );
161 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
162 (void**)&l.p_atsc_tune_request );
165 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
166 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
169 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
170 IID_IATSCLocator, (void**)&l.p_atsc_locator );
173 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
174 "Cannot create the ATSC locator: hr=0x%8lx", hr );
179 if( l_major_channel > 0 )
180 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
181 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
182 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
183 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
184 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
187 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
188 "Cannot set tuning parameters: hr=0x%8lx", hr );
192 hr = p_tune_request->put_Locator( l.p_atsc_locator );
195 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
196 "Cannot put the locator: hr=0x%8lx", hr );
200 /* Build and Run the Graph. If a Tuner device is in use the graph will
201 * fail to run. Repeated calls to build will check successive tuner
208 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
209 "Cannot Build the Graph: hr=0x%8lx", hr );
219 /*****************************************************************************
220 * Submit a DVB-T Tune Request
221 ******************************************************************************/
222 int BDAGraph::SubmitDVBTTuneRequest()
228 IDVBTuneRequest* p_dvbt_tune_request;
229 IDVBTLocator* p_dvbt_locator;
230 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
233 if( p_dvbt_tune_request )
234 p_dvbt_tune_request->Release();
236 p_dvbt_locator->Release();
239 long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
240 long l_transmission, l_hierarchy;
241 BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
242 GuardInterval i_guard;
243 TransmissionMode i_transmission;
244 HierarchyAlpha i_hierarchy;
246 l_frequency = l_bandwidth = l_hp_fec = l_lp_fec = l_guard = -1;
247 l_transmission = l_hierarchy = -1;
248 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
249 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
250 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
251 l_lp_fec = var_GetInteger( p_access, "dvb-code-rate-lp" );
252 l_guard = var_GetInteger( p_access, "dvb-guard" );
253 l_transmission = var_GetInteger( p_access, "dvb-transmission" );
254 l_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
256 i_hp_fec = BDA_BCC_RATE_NOT_SET;
258 i_hp_fec = BDA_BCC_RATE_1_2;
260 i_hp_fec = BDA_BCC_RATE_2_3;
262 i_hp_fec = BDA_BCC_RATE_3_4;
264 i_hp_fec = BDA_BCC_RATE_5_6;
266 i_hp_fec = BDA_BCC_RATE_7_8;
268 i_lp_fec = BDA_BCC_RATE_NOT_SET;
270 i_lp_fec = BDA_BCC_RATE_1_2;
272 i_lp_fec = BDA_BCC_RATE_2_3;
274 i_lp_fec = BDA_BCC_RATE_3_4;
276 i_lp_fec = BDA_BCC_RATE_5_6;
278 i_lp_fec = BDA_BCC_RATE_7_8;
280 i_guard = BDA_GUARD_NOT_SET;
282 i_guard = BDA_GUARD_1_32;
284 i_guard = BDA_GUARD_1_16;
286 i_guard = BDA_GUARD_1_8;
288 i_guard = BDA_GUARD_1_4;
290 i_transmission = BDA_XMIT_MODE_NOT_SET;
291 if( l_transmission == 2 )
292 i_transmission = BDA_XMIT_MODE_2K;
293 if( l_transmission == 8 )
294 i_transmission = BDA_XMIT_MODE_8K;
296 i_hierarchy = BDA_HALPHA_NOT_SET;
297 if( l_hierarchy == 1 )
298 i_hierarchy = BDA_HALPHA_1;
299 if( l_hierarchy == 2 )
300 i_hierarchy = BDA_HALPHA_2;
301 if( l_hierarchy == 4 )
302 i_hierarchy = BDA_HALPHA_4;
304 guid_network_type = CLSID_DVBTNetworkProvider;
305 hr = CreateTuneRequest();
308 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
309 "Cannot create Tune Request: hr=0x%8lx", hr );
313 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
314 (void**)&l.p_dvbt_tune_request );
317 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
318 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
321 l.p_dvbt_tune_request->put_ONID( -1 );
322 l.p_dvbt_tune_request->put_SID( -1 );
323 l.p_dvbt_tune_request->put_TSID( -1 );
325 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
326 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
329 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
330 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
335 if( l_frequency > 0 )
336 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
337 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
338 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
339 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
340 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
341 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
342 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
343 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
344 hr = l.p_dvbt_locator->put_Guard( i_guard );
345 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
346 hr = l.p_dvbt_locator->put_Mode( i_transmission );
347 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
348 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
351 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
352 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
356 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
359 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
360 "Cannot put the locator: hr=0x%8lx", hr );
364 /* Build and Run the Graph. If a Tuner device is in use the graph will
365 * fail to run. Repeated calls to build will check successive tuner
372 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
373 "Cannot Build the Graph: hr=0x%8lx", hr );
383 /*****************************************************************************
384 * Submit a DVB-C Tune Request
385 ******************************************************************************/
386 int BDAGraph::SubmitDVBCTuneRequest()
393 IDVBTuneRequest* p_dvbc_tune_request;
394 IDVBCLocator* p_dvbc_locator;
395 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
398 if( p_dvbc_tune_request )
399 p_dvbc_tune_request->Release();
401 p_dvbc_locator->Release();
405 long l_frequency, l_symbolrate;
407 ModulationType i_qam_mod;
409 l_frequency = l_symbolrate = i_qam = -1;
410 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
411 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
412 i_qam = var_GetInteger( p_access, "dvb-modulation" );
413 i_qam_mod = BDA_MOD_NOT_SET;
415 i_qam_mod = BDA_MOD_16QAM;
417 i_qam_mod = BDA_MOD_32QAM;
419 i_qam_mod = BDA_MOD_64QAM;
421 i_qam_mod = BDA_MOD_128QAM;
423 i_qam_mod = BDA_MOD_256QAM;
425 guid_network_type = CLSID_DVBCNetworkProvider;
426 hr = CreateTuneRequest();
429 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
430 "Cannot create Tune Request: hr=0x%8lx", hr );
434 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
435 (void**)&l.p_dvbc_tune_request );
438 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
439 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
442 l.p_dvbc_tune_request->put_ONID( -1 );
443 l.p_dvbc_tune_request->put_SID( -1 );
444 l.p_dvbc_tune_request->put_TSID( -1 );
446 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
447 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
450 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
451 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
456 if( l_frequency > 0 )
457 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
458 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
459 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
460 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
461 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
464 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
465 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
469 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
472 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
473 "Cannot put the locator: hr=0x%8lx", hr );
477 /* Build and Run the Graph. If a Tuner device is in use the graph will
478 * fail to run. Repeated calls to build will check successive tuner
485 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
486 "Cannot Build the Graph: hr=0x%8lx", hr );
496 /*****************************************************************************
497 * Submit a DVB-S Tune Request
498 ******************************************************************************/
499 int BDAGraph::SubmitDVBSTuneRequest()
506 IDVBTuneRequest* p_dvbs_tune_request;
507 IDVBSLocator* p_dvbs_locator;
508 IDVBSTuningSpace* p_dvbs_tuning_space;
509 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
510 p_dvbs_tuning_space(NULL) {};
513 if( p_dvbs_tuning_space )
514 p_dvbs_tuning_space->Release();
515 if( p_dvbs_tune_request )
516 p_dvbs_tune_request->Release();
518 p_dvbs_locator->Release();
521 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
522 long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
523 char* psz_polarisation;
524 Polarisation i_polar;
525 SpectralInversion i_inversion;
528 l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
529 l_lnb_lof1 = l_lnb_lof2 = l_lnb_slof = l_inversion = l_network_id = -1;
530 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
531 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
532 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
533 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
534 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
535 l_lnb_lof1 = var_GetInteger( p_access, "dvb-lnb-lof1" );
536 l_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
537 l_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
538 psz_polarisation = var_GetNonEmptyString( p_access, "dvb-polarisation" );
539 l_inversion = var_GetInteger( p_access, "dvb-inversion" );
540 l_network_id = var_GetInteger( p_access, "dvb-network_id" );
542 b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
544 i_polar = BDA_POLARISATION_NOT_SET;
545 if( psz_polarisation != NULL )
546 switch( toupper( psz_polarisation[0] ) )
549 i_polar = BDA_POLARISATION_LINEAR_H;
552 i_polar = BDA_POLARISATION_LINEAR_V;
555 i_polar = BDA_POLARISATION_CIRCULAR_L;
558 i_polar = BDA_POLARISATION_CIRCULAR_R;
562 i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
563 if( l_inversion == 0 )
564 i_inversion = BDA_SPECTRAL_INVERSION_NORMAL;
565 if( l_inversion == 1 )
566 i_inversion = BDA_SPECTRAL_INVERSION_INVERTED;
567 if( l_inversion == 2 )
568 i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC;
570 guid_network_type = CLSID_DVBSNetworkProvider;
571 hr = CreateTuneRequest();
574 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
575 "Cannot create Tune Request: hr=0x%8lx", hr );
579 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
580 (void**)&l.p_dvbs_tune_request );
583 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
584 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
587 l.p_dvbs_tune_request->put_ONID( -1 );
588 l.p_dvbs_tune_request->put_SID( -1 );
589 l.p_dvbs_tune_request->put_TSID( -1 );
591 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
592 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
595 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
596 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
600 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
601 (void**)&l.p_dvbs_tuning_space );
604 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
605 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
610 if( l_frequency > 0 )
611 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
612 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
613 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
614 if( SUCCEEDED( hr ) && l_azimuth > 0 )
615 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
616 if( SUCCEEDED( hr ) && l_elevation > 0 )
617 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
618 if( SUCCEEDED( hr ) )
619 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
620 if( SUCCEEDED( hr ) )
621 hr = l.p_dvbs_locator->put_WestPosition( b_west );
622 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
623 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
624 if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
625 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
626 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
627 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
628 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
629 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
630 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
631 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
632 if( SUCCEEDED( hr ) && l_network_id > 0 )
633 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
636 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
637 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
641 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
644 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
645 "Cannot put the locator: hr=0x%8lx", hr );
649 /* Build and Run the Graph. If a Tuner device is in use the graph will
650 * fail to run. Repeated calls to build will check successive tuner
657 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
658 "Cannot Build the Graph: hr=0x%8lx", hr );
668 /*****************************************************************************
669 * Load the Tuning Space from System Tuning Spaces according to the
670 * Network Type requested
671 ******************************************************************************/
672 HRESULT BDAGraph::CreateTuneRequest()
675 GUID guid_this_network_type;
679 ITuningSpaceContainer* p_tuning_space_container;
680 IEnumTuningSpaces* p_tuning_space_enum;
681 ITuningSpace* p_this_tuning_space;
682 localComPtr(): p_tuning_space_container(NULL),
683 p_tuning_space_enum(NULL), p_this_tuning_space(NULL) {};
686 if( p_tuning_space_container )
687 p_tuning_space_container->Release();
688 if( p_tuning_space_enum )
689 p_tuning_space_enum->Release();
690 if( p_this_tuning_space )
691 p_this_tuning_space->Release();
695 /* A Tuning Space may already have been set up. If it is for the same
696 * network type then all is well. Otherwise, reset the Tuning Space and get
700 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
701 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
702 if( guid_this_network_type == guid_network_type )
708 p_tuning_space->Release();
709 p_tuning_space = NULL;
713 /* Force use of the first available Tuner Device during Build */
716 /* Get the SystemTuningSpaces container to enumerate through all the
717 * defined tuning spaces */
718 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
719 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
722 msg_Warn( p_access, "CreateTuneRequest: "\
723 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
727 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
728 &l.p_tuning_space_enum );
731 msg_Warn( p_access, "CreateTuneRequest: "\
732 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
736 while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
739 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
741 /* GUID_NULL means a non-BDA network was found e.g analog
742 * Ignore failures and non-BDA networks and keep looking */
743 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
745 if( guid_this_network_type == guid_network_type )
747 hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
748 (void**)&p_tuning_space );
751 msg_Warn( p_access, "CreateTuneRequest: "\
752 "Cannot QI Tuning Space: hr=0x%8lx", hr );
755 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
758 msg_Warn( p_access, "CreateTuneRequest: "\
759 "Cannot Create Tune Request: hr=0x%8lx", hr );
768 msg_Warn( p_access, "CreateTuneRequest: "\
769 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
775 /******************************************************************************
777 * Step 4: Build the Filter Graph
778 * Build sets up devices, adds and connects filters
779 ******************************************************************************/
780 HRESULT BDAGraph::Build()
783 long l_capture_used, l_tif_used;
784 AM_MEDIA_TYPE grabber_media_type;
786 /* If we have already have a filter graph, rebuild it*/
789 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
790 IID_IGraphBuilder, (void**)&p_filter_graph );
793 msg_Warn( p_access, "Build: "\
794 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
798 /* First filter in the graph is the Network Provider and
799 * its Scanning Tuner which takes the Tune Request*/
800 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
801 IID_IBaseFilter, (void**)&p_network_provider);
804 msg_Warn( p_access, "Build: "\
805 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
808 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
811 msg_Warn( p_access, "Build: "\
812 "Cannot load network provider: hr=0x%8lx", hr );
816 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
817 (void**)&p_scanning_tuner );
820 msg_Warn( p_access, "Build: "\
821 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
825 hr = p_scanning_tuner->Validate( p_tune_request );
828 msg_Warn( p_access, "Build: "\
829 "Tune Request is invalid: hr=0x%8lx", hr );
832 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
835 msg_Warn( p_access, "Build: "\
836 "Cannot submit the tune request: hr=0x%8lx", hr );
840 /* Add the Network Tuner to the Network Provider. On subsequent calls,
841 * l_tuner_used will cause a different tuner to be selected */
842 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
843 p_network_provider, &p_tuner_device );
846 msg_Warn( p_access, "Build: "\
847 "Cannot load tuner device and connect network provider: "\
852 /* Always look for all capture devices to match the Network Tuner */
854 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
855 p_tuner_device, &p_capture_device );
858 /* Some BDA drivers do not provide a Capture Device Filter so force
859 * the Sample Grabber to connect directly to the Tuner Device */
860 p_capture_device = p_tuner_device;
861 p_tuner_device = NULL;
862 msg_Warn( p_access, "Build: "\
863 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
866 /* Insert the Sample Grabber to tap into the Transport Stream. */
867 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
868 IID_IBaseFilter, (void**)&p_sample_grabber );
871 msg_Warn( p_access, "Build: "\
872 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
875 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
878 msg_Warn( p_access, "Build: "\
879 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
883 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
884 (void**)&p_grabber );
887 msg_Warn( p_access, "Build: "\
888 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
892 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
893 grabber_media_type.majortype == MEDIATYPE_Stream;
894 grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
895 hr = p_grabber->SetMediaType( &grabber_media_type );
898 msg_Warn( p_access, "Build: "\
899 "Cannot set media type on grabber filter: hr=0x%8lx", hr );
902 hr = Connect( p_capture_device, p_sample_grabber );
905 msg_Warn( p_access, "Build: "\
906 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
910 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
911 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
912 * the Network Provider filter to set up the stream */
913 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
914 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
917 msg_Warn( p_access, "Build: "\
918 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
921 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
924 msg_Warn( p_access, "Build: "\
925 "Cannot add demux filter to graph: hr=0x%8lx", hr );
929 hr = Connect( p_sample_grabber, p_mpeg_demux );
932 msg_Warn( p_access, "Build: "\
933 "Cannot connect demux to grabber: hr=0x%8lx", hr );
937 /* Always look for the Transform Information Filter from the start
938 * of the collection*/
940 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
941 p_mpeg_demux, &p_transport_info );
944 msg_Warn( p_access, "Build: "\
945 "Cannot load TIF onto demux: hr=0x%8lx", hr );
949 /* Configure the Sample Grabber to buffer the samples continuously */
950 hr = p_grabber->SetBufferSamples( TRUE );
953 msg_Warn( p_access, "Build: "\
954 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
957 hr = p_grabber->SetOneShot( FALSE );
960 msg_Warn( p_access, "Build: "\
961 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
964 hr = p_grabber->SetCallback( this, 0 );
967 msg_Warn( p_access, "Build: "\
968 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
975 d_graph_register = 0;
978 /* The Media Control is used to Run and Stop the Graph */
979 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
980 (void**)&p_media_control );
983 msg_Warn( p_access, "Build: "\
984 "Cannot QI Media Control: hr=0x%8lx", hr );
990 /******************************************************************************
992 * Looks up all filters in a category and connects to the upstream filter until
993 * a successful match is found. The index of the connected filter is returned.
994 * On subsequent calls, this can be used to start from that point to find
996 * This is used when the graph does not run because a tuner device is in use so
997 * another one needs to be slected.
998 ******************************************************************************/
999 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
1000 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
1003 int i_moniker_index = -1;
1007 IMoniker* p_moniker;
1008 IEnumMoniker* p_moniker_enum;
1009 IBaseFilter* p_filter;
1010 IPropertyBag* p_property_bag;
1014 p_moniker_enum(NULL),
1016 p_property_bag(NULL)
1017 { ::VariantInit(&var_bstr); };
1021 p_moniker->Release();
1022 if( p_moniker_enum )
1023 p_moniker_enum->Release();
1025 p_filter->Release();
1026 if( p_property_bag )
1027 p_property_bag->Release();
1028 ::VariantClear(&var_bstr);
1032 if( !p_system_dev_enum )
1034 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1035 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1038 msg_Warn( p_access, "FindFilter: "\
1039 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1044 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1045 &l.p_moniker_enum, 0 );
1048 msg_Warn( p_access, "FindFilter: "\
1049 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1052 while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
1056 /* Skip over devices already found on previous calls */
1057 if( i_moniker_index <= *i_moniker_used ) continue;
1058 *i_moniker_used = i_moniker_index;
1060 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1061 (void**)&l.p_filter );
1065 l.p_moniker->Release();
1068 l.p_filter->Release();
1073 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1074 (void**)&l.p_property_bag );
1077 msg_Warn( p_access, "FindFilter: "\
1078 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1082 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1085 msg_Warn( p_access, "FindFilter: "\
1086 "Cannot read filter friendly name: hr=0x%8lx", hr );
1090 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1093 msg_Warn( p_access, "FindFilter: "\
1094 "Cannot add filter: hr=0x%8lx", hr );
1098 hr = Connect( p_upstream, l.p_filter );
1099 if( SUCCEEDED( hr ) )
1101 msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
1102 l.p_filter->QueryInterface( IID_IBaseFilter,
1103 (void**)p_p_downstream );
1106 /* Not the filter we want so unload and try the next one */
1107 hr = p_filter_graph->RemoveFilter( l.p_filter );
1110 msg_Warn( p_access, "FindFilter: "\
1111 "Failed unloading Filter: hr=0x%8lx", hr );
1116 l.p_moniker->Release();
1119 l.p_filter->Release();
1124 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1128 /*****************************************************************************
1129 * Connect is called from Build to enumerate and connect pins
1130 *****************************************************************************/
1131 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1133 HRESULT hr = E_FAIL;
1137 IPin* p_pin_upstream;
1138 IPin* p_pin_downstream;
1139 IEnumPins* p_pin_upstream_enum;
1140 IEnumPins* p_pin_downstream_enum;
1142 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1143 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1144 p_pin_temp(NULL) { };
1147 if( p_pin_upstream )
1148 p_pin_upstream->Release();
1149 if( p_pin_downstream )
1150 p_pin_downstream->Release();
1151 if( p_pin_upstream_enum )
1152 p_pin_upstream_enum->Release();
1153 if( p_pin_downstream_enum )
1154 p_pin_downstream_enum->Release();
1156 p_pin_temp->Release();
1160 PIN_INFO pin_info_upstream;
1161 PIN_INFO pin_info_downstream;
1163 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1166 msg_Warn( p_access, "Connect: "\
1167 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1170 while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
1172 hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
1175 msg_Warn( p_access, "Connect: "\
1176 "Cannot get upstream filter pin information: hr=0x%8lx", hr );
1179 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1181 l.p_pin_downstream->Release();
1182 if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1184 msg_Warn( p_access, "Connect: "\
1185 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1188 if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
1189 ( hr == VFW_E_NOT_CONNECTED ) )
1191 /* The upstream pin is not yet connected so check each pin on the
1192 * downstream filter */
1193 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1196 msg_Warn( p_access, "Connect: Cannot get "\
1197 "downstream filter enumerator: hr=0x%8lx", hr );
1200 while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
1203 hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
1206 msg_Warn( p_access, "Connect: Cannot get "\
1207 "downstream filter pin information: hr=0x%8lx", hr );
1211 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1212 if( hr == S_OK ) l.p_pin_temp->Release();
1213 if( hr != VFW_E_NOT_CONNECTED )
1217 msg_Warn( p_access, "Connect: Cannot check "\
1218 "downstream filter connection: hr=0x%8lx", hr );
1222 if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
1223 ( hr == VFW_E_NOT_CONNECTED ) )
1225 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1226 l.p_pin_downstream, NULL );
1227 if( SUCCEEDED( hr ) )
1229 pin_info_downstream.pFilter->Release();
1230 pin_info_upstream.pFilter->Release();
1234 /* If we fall out here it means this downstream pin was not
1235 * suitable so try the next downstream pin */
1236 l.p_pin_downstream = NULL;
1237 pin_info_downstream.pFilter->Release();
1241 /* If we fall out here it means we did not find any suitable downstream
1242 * pin so try the next upstream pin */
1243 l.p_pin_upstream = NULL;
1244 pin_info_upstream.pFilter->Release();
1247 /* If we fall out here it means we did not find any pair of suitable pins */
1251 /*****************************************************************************
1252 * Start uses MediaControl to start the graph
1253 *****************************************************************************/
1254 HRESULT BDAGraph::Start()
1257 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1259 if( !p_media_control )
1261 msg_Dbg( p_access, "Start: Media Control has not been created" );
1264 hr = p_media_control->Run();
1268 /* Query the state of the graph - timeout after 100 milliseconds */
1269 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1274 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1278 if( i_state == State_Running )
1281 /* The Graph is not running so stop it and return an error */
1282 msg_Warn( p_access, "Start: Graph not started: %d", i_state );
1283 hr = p_media_control->Stop();
1287 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1293 /*****************************************************************************
1294 * Read the stream of data - query the buffer size required
1295 *****************************************************************************/
1296 long BDAGraph::GetBufferSize()
1298 long l_buffer_size = 0;
1303 for( int i_timer = 0; queue_sample.empty() && i_timer < 200; i_timer++ )
1306 l_queue_size = queue_sample.size();
1307 if( l_queue_size <= 0 )
1309 msg_Warn( p_access, "BDA GetBufferSize: Timed Out waiting for sample" );
1313 /* Establish the length of the queue as it grows quickly. If the queue
1314 * size is checked dynamically there is a risk of not exiting the loop */
1315 for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1317 l_buffer_size += queue_sample.front()->GetActualDataLength();
1318 queue_buffer.push( queue_sample.front() );
1321 return l_buffer_size;
1324 /*****************************************************************************
1325 * Read the stream of data - Retrieve from the buffer queue
1326 ******************************************************************************/
1327 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1334 while( !queue_buffer.empty() )
1336 queue_buffer.front()->GetPointer( &p_buff_temp );
1337 hr = queue_buffer.front()->IsDiscontinuity();
1340 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1341 memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1342 queue_buffer.front()->GetActualDataLength() );
1343 *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1344 queue_buffer.front()->Release();
1348 return *pl_buffer_len;
1351 /******************************************************************************
1352 * SampleCB - Callback when the Sample Grabber has a sample
1353 ******************************************************************************/
1354 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1359 queue_sample.push( p_sample );
1363 msg_Warn( p_access, "BDA SampleCB: Not ready - dropped sample" );
1368 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1374 /******************************************************************************
1375 * removes each filter from the graph
1376 ******************************************************************************/
1377 HRESULT BDAGraph::Destroy()
1381 if( p_media_control )
1382 hr = p_media_control->Stop();
1384 if( p_transport_info )
1386 p_filter_graph->RemoveFilter( p_transport_info );
1387 p_transport_info->Release();
1388 p_transport_info = NULL;
1392 p_filter_graph->RemoveFilter( p_mpeg_demux );
1393 p_mpeg_demux->Release();
1394 p_mpeg_demux = NULL;
1396 if( p_sample_grabber )
1398 p_filter_graph->RemoveFilter( p_sample_grabber );
1399 p_sample_grabber->Release();
1400 p_sample_grabber = NULL;
1402 if( p_capture_device )
1404 p_filter_graph->RemoveFilter( p_capture_device );
1405 p_capture_device->Release();
1406 p_capture_device = NULL;
1408 if( p_tuner_device )
1410 p_filter_graph->RemoveFilter( p_tuner_device );
1411 p_tuner_device->Release();
1412 p_tuner_device = NULL;
1414 if( p_network_provider )
1416 p_filter_graph->RemoveFilter( p_network_provider );
1417 p_network_provider->Release();
1418 p_network_provider = NULL;
1421 if( p_scanning_tuner )
1423 p_scanning_tuner->Release();
1424 p_scanning_tuner = NULL;
1426 if( p_media_control )
1428 p_media_control->Release();
1429 p_media_control = NULL;
1431 if( p_filter_graph )
1433 p_filter_graph->Release();
1434 p_filter_graph = NULL;
1437 if( d_graph_register )
1445 /*****************************************************************************
1446 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1447 * Allows GraphEdit to "spy" on a remote filter graph.
1448 ******************************************************************************/
1449 HRESULT BDAGraph::Register()
1454 IMoniker* p_moniker;
1455 IRunningObjectTable* p_ro_table;
1456 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1460 p_moniker->Release();
1462 p_ro_table->Release();
1465 WCHAR psz_w_graph_name[128];
1468 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1471 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1475 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1476 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1477 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1480 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1483 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1484 p_filter_graph, l.p_moniker, &d_graph_register );
1487 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1490 msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1494 void BDAGraph::Deregister()
1497 IRunningObjectTable* p_ro_table;
1498 hr = ::GetRunningObjectTable( 0, &p_ro_table );
1499 if( SUCCEEDED( hr ) )
1500 p_ro_table->Revoke( d_graph_register );
1501 d_graph_register = 0;
1502 p_ro_table->Release();