1 /*****************************************************************************
2 * bdagraph.cpp : DirectShow BDA graph for vlc
3 *****************************************************************************
4 * Copyright( C ) 2007 the VideoLAN team
6 * Author: Ken Self <kenself(at)optusnet(dot)com(dot)au>
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 delete p_access->p_sys->p_bda_module;
44 int dvb_SubmitCQAMTuneRequest( access_t* p_access )
46 if( p_access->p_sys->p_bda_module )
47 return p_access->p_sys->p_bda_module->SubmitCQAMTuneRequest();
51 int dvb_SubmitATSCTuneRequest( access_t* p_access )
53 if( p_access->p_sys->p_bda_module )
54 return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
58 int dvb_SubmitDVBTTuneRequest( access_t* p_access )
60 if( p_access->p_sys->p_bda_module )
61 return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
65 int dvb_SubmitDVBCTuneRequest( access_t* p_access )
67 if( p_access->p_sys->p_bda_module )
68 return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
72 int dvb_SubmitDVBSTuneRequest( access_t* p_access )
74 if( p_access->p_sys->p_bda_module )
75 return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
79 block_t *dvb_Pop( access_t* p_access )
81 if( p_access->p_sys->p_bda_module )
82 return p_access->p_sys->p_bda_module->Pop();
87 /*****************************************************************************
89 *****************************************************************************/
90 BDAOutput::BDAOutput( access_t *p_access ) :
91 p_access(p_access), p_first(NULL), pp_next(&p_first)
93 vlc_mutex_init( &lock );
94 vlc_cond_init( &wait );
96 BDAOutput::~BDAOutput()
99 vlc_mutex_destroy( &lock );
100 vlc_cond_destroy( &wait );
102 void BDAOutput::Push( block_t *p_block )
104 vlc_mutex_locker l( &lock );
106 block_ChainLastAppend( &pp_next, p_block );
107 vlc_cond_signal( &wait );
109 block_t *BDAOutput::Pop()
111 vlc_mutex_locker l( &lock );
114 vlc_cond_timedwait( &wait, &lock, mdate() + 250*1000 );
116 block_t *p_ret = p_first;
123 void BDAOutput::Empty()
125 vlc_mutex_locker l( &lock );
128 block_ChainRelease( p_first );
133 /*****************************************************************************
135 *****************************************************************************/
136 BDAGraph::BDAGraph( access_t* p_this ):
138 guid_network_type(GUID_NULL),
140 d_graph_register( 0 ),
143 p_tuning_space = NULL;
144 p_tune_request = NULL;
145 p_media_control = NULL;
146 p_filter_graph = NULL;
147 p_system_dev_enum = NULL;
148 p_network_provider = p_tuner_device = p_capture_device = NULL;
149 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
150 p_scanning_tuner = NULL;
153 /* Initialize COM - MS says to use CoInitializeEx in preference to
155 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
158 /*****************************************************************************
160 *****************************************************************************/
161 BDAGraph::~BDAGraph()
167 /*****************************************************************************
168 * Submit an Clear QAM Tune Request (US Cable Shit)
169 *****************************************************************************/
170 int BDAGraph::SubmitCQAMTuneRequest()
176 IDigitalCableTuneRequest* p_cqam_tune_request;
177 IDigitalCableLocator* p_cqam_locator;
178 localComPtr(): p_cqam_tune_request(NULL), p_cqam_locator(NULL) {};
181 if( p_cqam_tune_request )
182 p_cqam_tune_request->Release();
184 p_cqam_locator->Release();
187 long l_minor_channel, l_physical_channel, l_frequency;
189 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
190 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
191 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
193 guid_network_type = CLSID_DigitalCableNetworkType;
194 hr = CreateTuneRequest();
197 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
198 "Cannot create Tuning Space: hr=0x%8lx", hr );
202 hr = p_tune_request->QueryInterface( IID_IDigitalCableTuneRequest,
203 (void**)&l.p_cqam_tune_request );
206 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
207 "Cannot QI for IDigitalCableTuneRequest: hr=0x%8lx", hr );
210 hr = ::CoCreateInstance( CLSID_DigitalCableLocator, 0, CLSCTX_INPROC,
211 IID_IDigitalCableLocator, (void**)&l.p_cqam_locator );
214 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
215 "Cannot create the CQAM locator: hr=0x%8lx", hr );
220 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
221 hr = l.p_cqam_locator->put_PhysicalChannel( l_physical_channel );
222 if( SUCCEEDED( hr ) && l_frequency > 0 )
223 hr = l.p_cqam_locator->put_CarrierFrequency( l_frequency );
224 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
225 hr = l.p_cqam_tune_request->put_MinorChannel( l_minor_channel );
228 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
229 "Cannot set tuning parameters: hr=0x%8lx", hr );
233 hr = p_tune_request->put_Locator( l.p_cqam_locator );
236 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
237 "Cannot put the locator: hr=0x%8lx", hr );
241 /* Build and Run the Graph. If a Tuner device is in use the graph will
242 * fail to run. Repeated calls to build will check successive tuner
249 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
250 "Cannot Build the Graph: hr=0x%8lx", hr );
260 /*****************************************************************************
261 * Submit an ATSC Tune Request
262 *****************************************************************************/
263 int BDAGraph::SubmitATSCTuneRequest()
269 IATSCChannelTuneRequest* p_atsc_tune_request;
270 IATSCLocator* p_atsc_locator;
271 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
274 if( p_atsc_tune_request )
275 p_atsc_tune_request->Release();
277 p_atsc_locator->Release();
280 long l_major_channel, l_minor_channel, l_physical_channel;
283 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
284 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
285 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
286 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
288 guid_network_type = CLSID_ATSCNetworkProvider;
289 hr = CreateTuneRequest();
292 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
293 "Cannot create Tuning Space: hr=0x%8lx", hr );
297 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
298 (void**)&l.p_atsc_tune_request );
301 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
302 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
305 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
306 IID_IATSCLocator, (void**)&l.p_atsc_locator );
309 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
310 "Cannot create the ATSC locator: hr=0x%8lx", hr );
315 if( l_frequency > 0 )
316 hr = l.p_atsc_locator->put_CarrierFrequency( l_frequency );
317 if( l_major_channel > 0 )
318 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
319 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
320 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
321 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
322 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
325 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
326 "Cannot set tuning parameters: hr=0x%8lx", hr );
330 hr = p_tune_request->put_Locator( l.p_atsc_locator );
333 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
334 "Cannot put the locator: hr=0x%8lx", hr );
338 /* Build and Run the Graph. If a Tuner device is in use the graph will
339 * fail to run. Repeated calls to build will check successive tuner
346 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
347 "Cannot Build the Graph: hr=0x%8lx", hr );
357 /*****************************************************************************
358 * Submit a DVB-T Tune Request
359 ******************************************************************************/
360 int BDAGraph::SubmitDVBTTuneRequest()
366 IDVBTuneRequest* p_dvbt_tune_request;
367 IDVBTLocator* p_dvbt_locator;
368 IDVBTuningSpace2* p_dvb_tuning_space;
369 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL),
370 p_dvb_tuning_space(NULL) {};
373 if( p_dvbt_tune_request )
374 p_dvbt_tune_request->Release();
376 p_dvbt_locator->Release();
377 if( p_dvb_tuning_space )
378 p_dvb_tuning_space->Release();
381 long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
382 long l_transmission, l_hierarchy;
383 BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
384 GuardInterval i_guard;
385 TransmissionMode i_transmission;
386 HierarchyAlpha i_hierarchy;
388 l_frequency = var_GetInteger( p_access, "dvb-frequency" ) / 1000;
389 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
390 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
391 l_lp_fec = var_GetInteger( p_access, "dvb-code-rate-lp" );
392 l_guard = var_GetInteger( p_access, "dvb-guard" );
393 l_transmission = var_GetInteger( p_access, "dvb-transmission" );
394 l_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
399 i_hp_fec = BDA_BCC_RATE_1_2; break;
401 i_hp_fec = BDA_BCC_RATE_2_3; break;
403 i_hp_fec = BDA_BCC_RATE_3_4; break;
405 i_hp_fec = BDA_BCC_RATE_5_6; break;
407 i_hp_fec = BDA_BCC_RATE_7_8;break;
409 i_hp_fec = BDA_BCC_RATE_NOT_SET;
415 i_lp_fec = BDA_BCC_RATE_1_2; break;
417 i_lp_fec = BDA_BCC_RATE_2_3; break;
419 i_lp_fec = BDA_BCC_RATE_3_4; break;
421 i_lp_fec = BDA_BCC_RATE_5_6; break;
423 i_lp_fec = BDA_BCC_RATE_7_8; break;
425 i_lp_fec = BDA_BCC_RATE_NOT_SET;
431 i_guard = BDA_GUARD_1_32; break;
433 i_guard = BDA_GUARD_1_16; break;
435 i_guard = BDA_GUARD_1_8; break;
437 i_guard = BDA_GUARD_1_4; break;
439 i_guard = BDA_GUARD_NOT_SET;
442 switch( l_transmission )
445 i_transmission = BDA_XMIT_MODE_2K; break;
447 i_transmission = BDA_XMIT_MODE_8K; break;
449 i_transmission = BDA_XMIT_MODE_NOT_SET;
452 switch( l_hierarchy )
455 i_hierarchy = BDA_HALPHA_1; break;
457 i_hierarchy = BDA_HALPHA_2; break;
459 i_hierarchy = BDA_HALPHA_4; break;
461 i_hierarchy = BDA_HALPHA_NOT_SET;
464 guid_network_type = CLSID_DVBTNetworkProvider;
465 hr = CreateTuneRequest();
468 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
469 "Cannot create Tune Request: hr=0x%8lx", hr );
473 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
474 (void**)&l.p_dvbt_tune_request );
477 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
478 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
481 l.p_dvbt_tune_request->put_ONID( -1 );
482 l.p_dvbt_tune_request->put_SID( -1 );
483 l.p_dvbt_tune_request->put_TSID( -1 );
485 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
486 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
489 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
490 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
493 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
494 (void**)&l.p_dvb_tuning_space );
497 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
498 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
503 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
505 if( SUCCEEDED( hr ) && l_frequency > 0 )
506 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
507 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
508 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
509 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
510 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
511 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
512 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
513 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
514 hr = l.p_dvbt_locator->put_Guard( i_guard );
515 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
516 hr = l.p_dvbt_locator->put_Mode( i_transmission );
517 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
518 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
521 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
522 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
526 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
529 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
530 "Cannot put the locator: hr=0x%8lx", hr );
534 /* Build and Run the Graph. If a Tuner device is in use the graph will
535 * fail to run. Repeated calls to build will check successive tuner
542 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
543 "Cannot Build the Graph: hr=0x%8lx", hr );
553 /*****************************************************************************
554 * Submit a DVB-C Tune Request
555 ******************************************************************************/
556 int BDAGraph::SubmitDVBCTuneRequest()
563 IDVBTuneRequest* p_dvbc_tune_request;
564 IDVBCLocator* p_dvbc_locator;
565 IDVBTuningSpace2* p_dvb_tuning_space;
567 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL),
568 p_dvb_tuning_space(NULL) {};
571 if( p_dvbc_tune_request )
572 p_dvbc_tune_request->Release();
574 p_dvbc_locator->Release();
575 if( p_dvb_tuning_space )
576 p_dvb_tuning_space->Release();
580 long l_frequency, l_symbolrate;
582 ModulationType i_qam_mod;
584 l_frequency = var_GetInteger( p_access, "dvb-frequency" ) / 1000;
585 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
586 i_qam = var_GetInteger( p_access, "dvb-modulation" );
591 i_qam_mod = BDA_MOD_16QAM; break;
593 i_qam_mod = BDA_MOD_32QAM; break;
595 i_qam_mod = BDA_MOD_64QAM; break;
597 i_qam_mod = BDA_MOD_128QAM; break;
599 i_qam_mod = BDA_MOD_256QAM; break;
601 i_qam_mod = BDA_MOD_NOT_SET;
604 guid_network_type = CLSID_DVBCNetworkProvider;
605 hr = CreateTuneRequest();
608 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
609 "Cannot create Tune Request: hr=0x%8lx", hr );
613 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
614 (void**)&l.p_dvbc_tune_request );
617 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
618 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
621 l.p_dvbc_tune_request->put_ONID( -1 );
622 l.p_dvbc_tune_request->put_SID( -1 );
623 l.p_dvbc_tune_request->put_TSID( -1 );
625 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
626 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
629 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
630 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
633 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
634 (void**)&l.p_dvb_tuning_space );
637 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
638 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
643 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
645 if( SUCCEEDED( hr ) && l_frequency > 0 )
646 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
647 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
648 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
649 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
650 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
654 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
655 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
659 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
662 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
663 "Cannot put the locator: hr=0x%8lx", hr );
667 /* Build and Run the Graph. If a Tuner device is in use the graph will
668 * fail to run. Repeated calls to build will check successive tuner
675 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
676 "Cannot Build the Graph: hr=0x%8lx", hr );
686 /*****************************************************************************
687 * Submit a DVB-S Tune Request
688 ******************************************************************************/
689 int BDAGraph::SubmitDVBSTuneRequest()
696 IDVBTuneRequest* p_dvbs_tune_request;
697 IDVBSLocator* p_dvbs_locator;
698 IDVBSTuningSpace* p_dvbs_tuning_space;
699 char* psz_polarisation;
700 char* psz_input_range;
701 BSTR bstr_input_range;
702 WCHAR* pwsz_input_range;
704 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
705 p_dvbs_tuning_space(NULL), bstr_input_range(NULL),
706 pwsz_input_range(NULL), i_range_len(0), psz_polarisation(NULL),
707 psz_input_range(NULL) {};
710 if( p_dvbs_tuning_space )
711 p_dvbs_tuning_space->Release();
712 if( p_dvbs_tune_request )
713 p_dvbs_tune_request->Release();
715 p_dvbs_locator->Release();
716 SysFreeString( bstr_input_range );
717 delete pwsz_input_range;
718 free( psz_input_range );
719 free( psz_polarisation );
722 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
723 long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
726 Polarisation i_polar;
727 SpectralInversion i_inversion;
729 BinaryConvolutionCodeRate i_hp_fec;
730 ModulationType i_mod_typ;
732 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
733 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
734 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
735 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
736 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
737 l_lnb_lof1 = var_GetInteger( p_access, "dvb-lnb-lof1" );
738 l_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
739 l_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
740 i_mod = var_GetInteger( p_access, "dvb-modulation" );
741 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
742 l_inversion = var_GetInteger( p_access, "dvb-inversion" );
743 l_network_id = var_GetInteger( p_access, "dvb-network-id" );
745 l.psz_input_range = var_GetNonEmptyString( p_access, "dvb-range" );
746 l.psz_polarisation = var_GetNonEmptyString( p_access, "dvb-polarisation" );
748 b_west = ( l_longitude < 0 );
750 i_polar = BDA_POLARISATION_NOT_SET;
751 if( l.psz_polarisation != NULL )
753 switch( toupper( l.psz_polarisation[0] ) )
756 i_polar = BDA_POLARISATION_LINEAR_H;
759 i_polar = BDA_POLARISATION_LINEAR_V;
762 i_polar = BDA_POLARISATION_CIRCULAR_L;
765 i_polar = BDA_POLARISATION_CIRCULAR_R;
770 switch( l_inversion )
773 i_inversion = BDA_SPECTRAL_INVERSION_NORMAL; break;
775 i_inversion = BDA_SPECTRAL_INVERSION_INVERTED; break;
777 i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC; break;
779 i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
785 i_mod_typ = BDA_MOD_16QAM; break;
787 i_mod_typ = BDA_MOD_128QAM; break;
789 i_mod_typ = BDA_MOD_256QAM; break;
791 i_mod_typ = BDA_MOD_QPSK; break;
793 i_mod_typ = BDA_MOD_NOT_SET;
799 i_hp_fec = BDA_BCC_RATE_1_2; break;
801 i_hp_fec = BDA_BCC_RATE_2_3; break;
803 i_hp_fec = BDA_BCC_RATE_3_4; break;
805 i_hp_fec = BDA_BCC_RATE_5_6; break;
807 i_hp_fec = BDA_BCC_RATE_7_8; break;
809 i_hp_fec = BDA_BCC_RATE_NOT_SET;
812 l.i_range_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
813 l.psz_input_range, -1, l.pwsz_input_range, 0 );
814 if( l.i_range_len > 0 )
816 l.pwsz_input_range = new WCHAR[l.i_range_len];
817 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
818 l.psz_input_range, -1, l.pwsz_input_range, l.i_range_len );
819 l.bstr_input_range=SysAllocString( l.pwsz_input_range );
822 guid_network_type = CLSID_DVBSNetworkProvider;
823 hr = CreateTuneRequest();
826 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
827 "Cannot create Tune Request: hr=0x%8lx", hr );
831 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
832 (void**)&l.p_dvbs_tune_request );
835 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
836 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
839 l.p_dvbs_tune_request->put_ONID( -1 );
840 l.p_dvbs_tune_request->put_SID( -1 );
841 l.p_dvbs_tune_request->put_TSID( -1 );
843 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
844 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
847 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
848 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
852 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
853 (void**)&l.p_dvbs_tuning_space );
856 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
857 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
862 hr = l.p_dvbs_tuning_space->put_SystemType( DVB_Satellite );
863 if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
864 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
865 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
866 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
867 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
868 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
869 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
870 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
871 if( SUCCEEDED( hr ) && l_network_id > 0 )
872 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
873 if( SUCCEEDED( hr ) && l.i_range_len > 0 )
874 hr = l.p_dvbs_tuning_space->put_InputRange( l.bstr_input_range );
876 if( SUCCEEDED( hr ) && l_frequency > 0 )
877 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
878 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
879 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
880 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
881 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
882 if( SUCCEEDED( hr ) && i_mod_typ != BDA_MOD_NOT_SET )
883 hr = l.p_dvbs_locator->put_Modulation( i_mod_typ );
884 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
885 hr = l.p_dvbs_locator->put_InnerFECRate( i_hp_fec );
887 if( SUCCEEDED( hr ) && l_azimuth > 0 )
888 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
889 if( SUCCEEDED( hr ) && l_elevation > 0 )
890 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
891 if( SUCCEEDED( hr ) )
892 hr = l.p_dvbs_locator->put_WestPosition( b_west );
893 if( SUCCEEDED( hr ) )
894 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
897 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
898 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
902 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
905 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
906 "Cannot put the locator: hr=0x%8lx", hr );
910 /* Build and Run the Graph. If a Tuner device is in use the graph will
911 * fail to run. Repeated calls to build will check successive tuner
918 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
919 "Cannot Build the Graph: hr=0x%8lx", hr );
929 /*****************************************************************************
930 * Load the Tuning Space from System Tuning Spaces according to the
931 * Network Type requested
932 ******************************************************************************/
933 HRESULT BDAGraph::CreateTuneRequest()
936 GUID guid_this_network_type;
940 ITuningSpaceContainer* p_tuning_space_container;
941 IEnumTuningSpaces* p_tuning_space_enum;
942 ITuningSpace* p_this_tuning_space;
943 IDVBTuningSpace2* p_dvb_tuning_space;
945 char * psz_network_name;
946 char * psz_create_name;
947 char * psz_bstr_name;
948 WCHAR * wpsz_create_name;
950 localComPtr(): p_tuning_space_container(NULL),
951 p_tuning_space_enum(NULL), p_this_tuning_space(NULL),
952 p_dvb_tuning_space(NULL),
953 i_name_len(0), psz_network_name(NULL), wpsz_create_name(NULL),
954 psz_create_name(NULL), bstr_name(NULL), psz_bstr_name(NULL) {};
957 if( p_tuning_space_enum )
958 p_tuning_space_enum->Release();
959 if( p_tuning_space_container )
960 p_tuning_space_container->Release();
961 if( p_this_tuning_space )
962 p_this_tuning_space->Release();
963 if( p_dvb_tuning_space )
964 p_dvb_tuning_space->Release();
965 SysFreeString( bstr_name );
966 delete[] psz_bstr_name;
967 delete[] wpsz_create_name;
968 free( psz_network_name );
969 free( psz_create_name );
973 /* We shall test for a specific Tuning space name supplied on the command
974 * line as dvb-networkname=xxx.
975 * For some users with multiple cards and/or multiple networks this could
976 * be useful. This allows us to reasonably safely apply updates to the
977 * System Tuning Space in the registry without disrupting other streams. */
978 l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-network-name" );
979 if( l.psz_network_name )
981 msg_Dbg( p_access, "CreateTuneRequest: Find Tuning Space: %s",
982 l.psz_network_name );
986 l.psz_network_name = new char[1];
987 *l.psz_network_name = '\0';
990 /* A Tuning Space may already have been set up. If it is for the same
991 * network type then all is well. Otherwise, reset the Tuning Space and get
995 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
996 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
997 if( guid_this_network_type == guid_network_type )
999 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
1002 msg_Warn( p_access, "CreateTuneRequest: "\
1003 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
1006 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1007 l.psz_bstr_name, 0, NULL, NULL );
1008 l.psz_bstr_name = new char[ l.i_name_len ];
1009 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1010 l.psz_bstr_name, l.i_name_len, NULL, NULL );
1012 /* Test for a specific Tuning space name supplied on the command
1013 * line as dvb-networkname=xxx */
1014 if( *l.psz_network_name == '\0' ||
1015 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
1017 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
1018 l.psz_network_name );
1022 /* else different guid_network_type */
1023 if( p_tuning_space )
1024 p_tuning_space->Release();
1025 if( p_tune_request )
1026 p_tune_request->Release();
1027 p_tuning_space = NULL;
1028 p_tune_request = NULL;
1031 /* Force use of the first available Tuner Device during Build */
1034 /* Get the SystemTuningSpaces container to enumerate through all the
1035 * defined tuning spaces.
1036 * l.p_tuning_space_container->Refcount = 1 */
1037 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
1038 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
1041 msg_Warn( p_access, "CreateTuneRequest: "\
1042 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
1046 /* Get the SystemTuningSpaces container to enumerate through all the
1047 * defined tuning spaces.
1048 * l.p_tuning_space_container->Refcount = 2
1049 * l.p_tuning_space_enum->Refcount = 1 */
1050 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
1051 &l.p_tuning_space_enum );
1054 msg_Warn( p_access, "CreateTuneRequest: "\
1055 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
1061 /* l.p_this_tuning_space->RefCount = 1 after the first pass
1062 * Release before overwriting with Next */
1063 if( l.p_this_tuning_space )
1064 l.p_this_tuning_space->Release();
1065 l.p_this_tuning_space = NULL;
1066 SysFreeString( l.bstr_name );
1068 hr = l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL );
1069 if( hr != S_OK ) break;
1071 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
1073 /* GUID_NULL means a non-BDA network was found e.g analog
1074 * Ignore failures and non-BDA networks and keep looking */
1075 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
1077 if( guid_this_network_type == guid_network_type )
1079 /* QueryInterface to clone l.p_this_tuning_space
1080 * l.p_this_tuning_space->RefCount = 2 */
1081 hr = l.p_this_tuning_space->Clone( &p_tuning_space );
1084 msg_Warn( p_access, "CreateTuneRequest: "\
1085 "Cannot QI Tuning Space: hr=0x%8lx", hr );
1088 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
1091 msg_Warn( p_access, "CreateTuneRequest: "\
1092 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
1096 /* Test for a specific Tuning space name supplied on the command
1097 * line as dvb-networkname=xxx */
1098 delete[] l.psz_bstr_name;
1099 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1100 l.psz_bstr_name, 0, NULL, NULL );
1101 l.psz_bstr_name = new char[ l.i_name_len ];
1102 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1103 l.psz_bstr_name, l.i_name_len, NULL, NULL );
1104 if( *l.psz_network_name == '\0' ||
1105 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
1107 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
1110 /* CreateTuneRequest adds TuneRequest to p_tuning_space
1111 * p_tune_request->RefCount = 1 */
1112 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
1114 msg_Warn( p_access, "CreateTuneRequest: "\
1115 "Cannot Create Tune Request: hr=0x%8lx", hr );
1118 if( p_tuning_space )
1119 p_tuning_space->Release();
1120 p_tuning_space = NULL;
1125 /* No tuning space was found. If the create-name parameter was set then
1126 * create a tuning space. By rights should use the same name used in
1128 * Also would be nice to copy a tuning space but we only come here if we do
1130 l.psz_create_name = var_GetNonEmptyString( p_access, "dvb-create-name" );
1131 if( !l.psz_create_name || strlen( l.psz_create_name ) <= 0 )
1134 msg_Warn( p_access, "CreateTuneRequest: "\
1135 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
1138 if( strcmp( l.psz_create_name, l.psz_network_name ) )
1141 msg_Warn( p_access, "CreateTuneRequest: "\
1142 "dvb-create-name %s must match dvb-network-name %s",
1143 l.psz_create_name, l.psz_network_name );
1147 /* Need to use DVBSTuningSpace for DVB-S and ATSCTuningSpace for ATSC */
1149 CLSID cls_tuning_space;
1151 if( IsEqualCLSID( guid_network_type, CLSID_ATSCNetworkProvider ) )
1152 cls_tuning_space = CLSID_ATSCTuningSpace;
1153 if( IsEqualCLSID( guid_network_type, CLSID_DVBTNetworkProvider ) )
1154 cls_tuning_space = CLSID_DVBTuningSpace;
1155 if( IsEqualCLSID( guid_network_type, CLSID_DVBCNetworkProvider ) )
1156 cls_tuning_space = CLSID_DVBTuningSpace;
1157 if( IsEqualCLSID( guid_network_type, CLSID_DVBSNetworkProvider ) )
1158 cls_tuning_space = CLSID_DVBSTuningSpace;
1160 l.i_name_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
1161 l.psz_create_name, -1, l.wpsz_create_name, 0 );
1162 if( l.i_name_len <= 0 )
1165 msg_Warn( p_access, "CreateTuneRequest: "\
1166 "Cannot convert zero length dvb-create-name %s",
1167 l.psz_create_name );
1170 l.wpsz_create_name = new WCHAR[l.i_name_len];
1171 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, l.psz_create_name, -1,
1172 l.wpsz_create_name, l.i_name_len );
1174 SysFreeString( l.bstr_name );
1175 l.bstr_name = SysAllocString( l.wpsz_create_name );
1177 msg_Dbg( p_access, "CreateTuneRequest: Create Tuning Space: %s",
1178 l.psz_create_name );
1180 hr = ::CoCreateInstance( cls_tuning_space, 0, CLSCTX_INPROC,
1181 IID_ITuningSpace, (void**)&p_tuning_space );
1184 msg_Warn( p_access, "CreateTuneRequest: "\
1185 "Cannot CoCreate new TuningSpace: hr=0x%8lx", hr );
1186 if( SUCCEEDED( hr ) )
1187 hr = p_tuning_space->put__NetworkType( guid_network_type );
1189 msg_Warn( p_access, "CreateTuneRequest: "\
1190 "Cannot Put Network Type: hr=0x%8lx", hr );
1191 if( SUCCEEDED( hr ) )
1192 hr = p_tuning_space->put_UniqueName( l.bstr_name );
1194 msg_Warn( p_access, "CreateTuneRequest: "\
1195 "Cannot Put Unique Name: hr=0x%8lx", hr );
1196 if( SUCCEEDED( hr ) )
1197 hr = p_tuning_space->put_FriendlyName( l.bstr_name );
1199 msg_Warn( p_access, "CreateTuneRequest: "\
1200 "Cannot Put Friendly Name: hr=0x%8lx", hr );
1201 if( guid_network_type == CLSID_DVBTNetworkProvider ||
1202 guid_network_type == CLSID_DVBCNetworkProvider ||
1203 guid_network_type == CLSID_DVBSNetworkProvider )
1205 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
1206 (void**)&l.p_dvb_tuning_space );
1209 msg_Warn( p_access, "CreateTuneRequest: "\
1210 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
1213 if( guid_network_type == CLSID_DVBTNetworkProvider )
1214 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
1215 if( guid_network_type == CLSID_DVBCNetworkProvider )
1216 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
1217 if( guid_network_type == CLSID_DVBSNetworkProvider )
1218 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Satellite );
1221 if( SUCCEEDED( hr ) )
1222 hr = l.p_tuning_space_container->Add( p_tuning_space, &var_id );
1226 msg_Warn( p_access, "CreateTuneRequest: "\
1227 "Cannot Create new TuningSpace: hr=0x%8lx", hr );
1231 msg_Dbg( p_access, "CreateTuneRequest: Tuning Space: %s created",
1232 l.psz_create_name );
1234 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
1236 msg_Warn( p_access, "CreateTuneRequest: "\
1237 "Cannot Create Tune Request: hr=0x%8lx", hr );
1242 /******************************************************************************
1244 * Step 4: Build the Filter Graph
1245 * Build sets up devices, adds and connects filters
1246 ******************************************************************************/
1247 HRESULT BDAGraph::Build()
1250 long l_capture_used, l_tif_used;
1251 VARIANT l_tuning_space_id;
1252 AM_MEDIA_TYPE grabber_media_type;
1256 ITuningSpaceContainer* p_tuning_space_container;
1257 localComPtr(): p_tuning_space_container(NULL) {};
1260 if( p_tuning_space_container )
1261 p_tuning_space_container->Release();
1265 /* Get the SystemTuningSpaces container to save the Tuning space */
1266 l_tuning_space_id.vt = VT_I4;
1267 l_tuning_space_id.lVal = 0L;
1268 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
1269 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
1272 msg_Warn( p_access, "Build: "\
1273 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
1276 hr = l.p_tuning_space_container->FindID( p_tuning_space,
1277 &l_tuning_space_id.lVal );
1280 msg_Warn( p_access, "Build: "\
1281 "Cannot Find Tuning Space ID: hr=0x%8lx", hr );
1284 msg_Dbg( p_access, "Build: Using Tuning Space ID %d",
1285 l_tuning_space_id.lVal );
1286 hr = l.p_tuning_space_container->put_Item( l_tuning_space_id,
1290 msg_Warn( p_access, "Build: "\
1291 "Cannot save Tuning Space: hr=0x%8lx (ignored)", hr );
1294 /* If we have already have a filter graph, rebuild it*/
1297 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1298 IID_IGraphBuilder, (void**)&p_filter_graph );
1301 msg_Warn( p_access, "Build: "\
1302 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
1306 /* First filter in the graph is the Network Provider and
1307 * its Scanning Tuner which takes the Tune Request
1308 * Try to build the Win 7 Universal Network Provider first*/
1309 hr = ::CoCreateInstance( CLSID_NetworkProvider, NULL, CLSCTX_INPROC_SERVER,
1310 IID_IBaseFilter, (void**)&p_network_provider);
1313 msg_Warn( p_access, "Build: "\
1314 "Cannot CoCreate the Universal Network Provider, trying the old way...");
1315 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
1316 IID_IBaseFilter, (void**)&p_network_provider);
1319 msg_Warn( p_access, "Build: "\
1320 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
1324 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
1327 msg_Warn( p_access, "Build: "\
1328 "Cannot load network provider: hr=0x%8lx", hr );
1332 /* Add the Network Tuner to the Network Provider. On subsequent calls,
1333 * l_tuner_used will cause a different tuner to be selected
1334 * To select a specific device first get the parameter that nominates the
1335 * device (dvb-adapter) and use the value to initialise l_tuner_used.
1336 * When FindFilter returns check the contents of l_tuner_used.
1337 * If it is not what was selected then the requested device was not
1338 * available so return with an error. */
1340 long l_adapter = -1;
1341 l_adapter = var_GetInteger( p_access, "dvb-adapter" );
1342 if( l_tuner_used < 0 && l_adapter >= 0 )
1343 l_tuner_used = l_adapter - 1;
1345 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
1346 p_network_provider, &p_tuner_device );
1349 msg_Warn( p_access, "Build: "\
1350 "Cannot load tuner device and connect network provider: "\
1354 if( l_adapter > 0 && l_tuner_used != l_adapter )
1356 msg_Warn( p_access, "Build: "\
1357 "Tuner device %d is not available", l_adapter );
1360 msg_Dbg( p_access, "BDAGraph: Using adapter %d", l_tuner_used );
1362 /* VLC 1.0 works reliably up this point then crashes
1363 * Obvious candidate is FindFilter */
1364 /* Always look for all capture devices to match the Network Tuner */
1365 l_capture_used = -1;
1366 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
1367 p_tuner_device, &p_capture_device );
1370 /* Some BDA drivers do not provide a Capture Device Filter so force
1371 * the Sample Grabber to connect directly to the Tuner Device */
1372 p_capture_device = p_tuner_device;
1373 p_tuner_device = NULL;
1374 msg_Warn( p_access, "Build: "\
1375 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
1378 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
1379 (void**)&p_scanning_tuner );
1382 msg_Warn( p_access, "Build: "\
1383 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
1387 hr = p_scanning_tuner->Validate( p_tune_request );
1390 msg_Warn( p_access, "Build: "\
1391 "Tune Request is invalid: hr=0x%8lx", hr );
1392 //return hr; it is not mandatory to validate. Validate fails, but the request is successfully accepted
1394 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
1397 msg_Warn( p_access, "Build: "\
1398 "Cannot submit the tune request: hr=0x%8lx", hr );
1402 if( p_sample_grabber )
1403 p_sample_grabber->Release();
1404 p_sample_grabber = NULL;
1405 /* Insert the Sample Grabber to tap into the Transport Stream. */
1406 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
1407 IID_IBaseFilter, (void**)&p_sample_grabber );
1410 msg_Warn( p_access, "Build: "\
1411 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
1414 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
1417 msg_Warn( p_access, "Build: "\
1418 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
1423 p_grabber->Release();
1425 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
1426 (void**)&p_grabber );
1429 msg_Warn( p_access, "Build: "\
1430 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
1434 /* Try the possible stream type */
1436 for( int i = 0; i < 2; i++ )
1438 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
1439 grabber_media_type.majortype = MEDIATYPE_Stream;
1440 grabber_media_type.subtype = i == 0 ? MEDIASUBTYPE_MPEG2_TRANSPORT : KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT;
1441 msg_Dbg( p_access, "Build: "
1442 "Trying connecting with subtype %s",
1443 i == 0 ? "MEDIASUBTYPE_MPEG2_TRANSPORT" : "KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT" );
1444 hr = p_grabber->SetMediaType( &grabber_media_type );
1445 if( SUCCEEDED( hr ) )
1447 hr = Connect( p_capture_device, p_sample_grabber );
1448 if( SUCCEEDED( hr ) )
1450 msg_Warn( p_access, "Build: "\
1451 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr, 1+i );
1455 msg_Warn( p_access, "Build: "\
1456 "Cannot set media type on grabber filter: hr=0x%8lx (try %d/2", hr, 1+i );
1462 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
1463 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
1464 * the Network Provider filter to set up the stream */
1465 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
1466 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
1469 msg_Warn( p_access, "Build: "\
1470 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
1473 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
1476 msg_Warn( p_access, "Build: "\
1477 "Cannot add demux filter to graph: hr=0x%8lx", hr );
1480 hr = Connect( p_sample_grabber, p_mpeg_demux );
1483 msg_Warn( p_access, "Build: "\
1484 "Cannot connect demux to grabber: hr=0x%8lx", hr );
1488 /* Always look for the Transform Information Filter from the start
1489 * of the collection*/
1491 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
1492 p_mpeg_demux, &p_transport_info );
1495 msg_Warn( p_access, "Build: "\
1496 "Cannot load TIF onto demux: hr=0x%8lx", hr );
1499 /* Configure the Sample Grabber to buffer the samples continuously */
1500 hr = p_grabber->SetBufferSamples( true );
1503 msg_Warn( p_access, "Build: "\
1504 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
1507 hr = p_grabber->SetOneShot( false );
1510 msg_Warn( p_access, "Build: "\
1511 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
1514 hr = p_grabber->SetCallback( this, 0 );
1517 msg_Warn( p_access, "Build: "\
1518 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
1525 d_graph_register = 0;
1528 /* The Media Control is used to Run and Stop the Graph */
1529 if( p_media_control )
1530 p_media_control->Release();
1531 p_media_control = NULL;
1532 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
1533 (void**)&p_media_control );
1536 msg_Warn( p_access, "Build: "\
1537 "Cannot QI Media Control: hr=0x%8lx", hr );
1545 /******************************************************************************
1547 * Looks up all filters in a category and connects to the upstream filter until
1548 * a successful match is found. The index of the connected filter is returned.
1549 * On subsequent calls, this can be used to start from that point to find
1551 * This is used when the graph does not run because a tuner device is in use so
1552 * another one needs to be selected.
1553 ******************************************************************************/
1554 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
1555 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
1558 int i_moniker_index = -1;
1562 IMoniker* p_moniker;
1563 IEnumMoniker* p_moniker_enum;
1564 IBaseFilter* p_filter;
1565 IPropertyBag* p_property_bag;
1571 p_moniker_enum(NULL),
1573 p_property_bag(NULL),
1575 { ::VariantInit(&var_bstr); };
1578 if( p_property_bag )
1579 p_property_bag->Release();
1581 p_filter->Release();
1583 p_moniker->Release();
1584 if( p_moniker_enum )
1585 p_moniker_enum->Release();
1586 ::VariantClear(&var_bstr);
1591 if( !p_system_dev_enum )
1593 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1594 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1597 msg_Warn( p_access, "FindFilter: "\
1598 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1603 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1604 &l.p_moniker_enum, 0 );
1607 msg_Warn( p_access, "FindFilter: "\
1608 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1614 /* We are overwriting l.p_moniker so we should Release and nullify
1615 * It is important that p_moniker and p_property_bag are fully released
1616 * l.p_filter may not be dereferenced so we could force to NULL */
1617 if( l.p_property_bag )
1618 l.p_property_bag->Release();
1619 l.p_property_bag = NULL;
1621 l.p_filter->Release();
1624 l.p_moniker->Release();
1627 hr = l.p_moniker_enum->Next( 1, &l.p_moniker, 0 );
1628 if( hr != S_OK ) break;
1631 /* Skip over devices already found on previous calls */
1632 if( i_moniker_index <= *i_moniker_used ) continue;
1633 *i_moniker_used = i_moniker_index;
1635 /* l.p_filter is Released at the top of the loop */
1636 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1637 (void**)&l.p_filter );
1642 /* l.p_property_bag is released at the top of the loop */
1643 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1644 (void**)&l.p_property_bag );
1647 msg_Warn( p_access, "FindFilter: "\
1648 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1651 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1654 msg_Warn( p_access, "FindFilter: "\
1655 "Cannot read filter friendly name: hr=0x%8lx", hr );
1659 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1662 msg_Warn( p_access, "FindFilter: "\
1663 "Cannot add filter: hr=0x%8lx", hr );
1666 hr = Connect( p_upstream, l.p_filter );
1667 if( SUCCEEDED( hr ) )
1669 /* p_p_downstream has not been touched yet so no release needed */
1670 delete[] l.psz_bstr;
1671 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1672 l.var_bstr.bstrVal, -1, l.psz_bstr, 0, NULL, NULL );
1673 l.psz_bstr = new char[l.i_bstr_len];
1674 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1675 l.var_bstr.bstrVal, -1, l.psz_bstr, l.i_bstr_len, NULL, NULL );
1676 msg_Dbg( p_access, "FindFilter: Connected %s", l.psz_bstr );
1677 l.p_filter->QueryInterface( IID_IBaseFilter,
1678 (void**)p_p_downstream );
1681 /* Not the filter we want so unload and try the next one */
1682 hr = p_filter_graph->RemoveFilter( l.p_filter );
1685 msg_Warn( p_access, "FindFilter: "\
1686 "Failed unloading Filter: hr=0x%8lx", hr );
1694 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1698 /*****************************************************************************
1699 * Connect is called from Build to enumerate and connect pins
1700 *****************************************************************************/
1701 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1703 HRESULT hr = E_FAIL;
1707 IPin* p_pin_upstream;
1708 IPin* p_pin_downstream;
1709 IEnumPins* p_pin_upstream_enum;
1710 IEnumPins* p_pin_downstream_enum;
1712 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1713 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1714 p_pin_temp(NULL) { };
1718 p_pin_temp->Release();
1719 if( p_pin_downstream )
1720 p_pin_downstream->Release();
1721 if( p_pin_upstream )
1722 p_pin_upstream->Release();
1723 if( p_pin_downstream_enum )
1724 p_pin_downstream_enum->Release();
1725 if( p_pin_upstream_enum )
1726 p_pin_upstream_enum->Release();
1730 PIN_DIRECTION pin_dir;
1732 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1735 msg_Warn( p_access, "Connect: "\
1736 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1742 /* Release l.p_pin_upstream before next iteration */
1743 if( l.p_pin_upstream )
1744 l.p_pin_upstream ->Release();
1745 l.p_pin_upstream = NULL;
1746 hr = l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 );
1747 if( hr != S_OK ) break;
1749 hr = l.p_pin_upstream->QueryDirection( &pin_dir );
1752 msg_Warn( p_access, "Connect: "\
1753 "Cannot get upstream filter pin direction: hr=0x%8lx", hr );
1756 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1757 if( SUCCEEDED( hr ) )
1759 l.p_pin_downstream->Release();
1760 l.p_pin_downstream = NULL;
1762 if( FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1764 msg_Warn( p_access, "Connect: "\
1765 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1768 if( ( pin_dir == PINDIR_OUTPUT ) && ( hr == VFW_E_NOT_CONNECTED ) )
1770 /* The upstream pin is not yet connected so check each pin on the
1771 * downstream filter */
1772 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1775 msg_Warn( p_access, "Connect: Cannot get "\
1776 "downstream filter enumerator: hr=0x%8lx", hr );
1781 /* Release l.p_pin_downstream before next iteration */
1782 if( l.p_pin_downstream )
1783 l.p_pin_downstream ->Release();
1784 l.p_pin_downstream = NULL;
1786 hr = l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 );
1787 if( hr != S_OK ) break;
1789 hr = l.p_pin_downstream->QueryDirection( &pin_dir );
1792 msg_Warn( p_access, "Connect: Cannot get "\
1793 "downstream filter pin direction: hr=0x%8lx", hr );
1797 /* Looking for a free Pin to connect to
1798 * A connected Pin may have an reference count > 1
1799 * so Release and nullify the pointer */
1800 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1801 if( SUCCEEDED( hr ) )
1803 l.p_pin_temp->Release();
1804 l.p_pin_temp = NULL;
1806 if( hr != VFW_E_NOT_CONNECTED )
1810 msg_Warn( p_access, "Connect: Cannot check "\
1811 "downstream filter connection: hr=0x%8lx", hr );
1815 if( ( pin_dir == PINDIR_INPUT ) &&
1816 ( hr == VFW_E_NOT_CONNECTED ) )
1818 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1819 l.p_pin_downstream, NULL );
1820 if( SUCCEEDED( hr ) )
1822 /* If we arrive here then we have a matching pair of
1827 /* If we arrive here it means this downstream pin is not
1828 * suitable so try the next downstream pin.
1829 * l.p_pin_downstream is released at the top of the loop */
1832 /* If we arrive here then we ran out of pins before we found a
1833 * suitable one. Release outstanding refcounts */
1834 if( l.p_pin_downstream_enum )
1835 l.p_pin_downstream_enum->Release();
1836 l.p_pin_downstream_enum = NULL;
1837 if( l.p_pin_downstream )
1838 l.p_pin_downstream->Release();
1839 l.p_pin_downstream = NULL;
1841 /* If we arrive here it means this upstream pin is not suitable
1842 * so try the next upstream pin
1843 * l.p_pin_upstream is released at the top of the loop */
1846 /* If we arrive here it means we did not find any pair of suitable pins
1847 * Outstanding refcounts are released in the destructor */
1851 /*****************************************************************************
1852 * Start uses MediaControl to start the graph
1853 *****************************************************************************/
1854 HRESULT BDAGraph::Start()
1857 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1859 if( !p_media_control )
1861 msg_Dbg( p_access, "Start: Media Control has not been created" );
1864 hr = p_media_control->Run();
1865 msg_Dbg( p_access, "Graph started hr=0x%lx", hr );
1869 /* Query the state of the graph - timeout after 100 milliseconds */
1870 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1875 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1879 if( i_state == State_Running )
1882 /* The Graph is not running so stop it and return an error */
1883 msg_Warn( p_access, "Start: Graph not started: %d", i_state );
1884 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
1888 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1894 /*****************************************************************************
1895 * Pop the stream of data
1896 *****************************************************************************/
1897 block_t *BDAGraph::Pop()
1899 return output.Pop();
1902 /******************************************************************************
1903 * SampleCB - Callback when the Sample Grabber has a sample
1904 ******************************************************************************/
1905 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1907 if( p_sample->IsDiscontinuity() == S_OK )
1908 msg_Warn( p_access, "BDA SampleCB: Sample Discontinuity.");
1910 const size_t i_sample_size = p_sample->GetActualDataLength();
1911 BYTE *p_sample_data;
1912 p_sample->GetPointer( &p_sample_data );
1914 if( i_sample_size > 0 && p_sample_data )
1916 block_t *p_block = block_New( p_access, i_sample_size );
1920 memcpy( p_block->p_buffer, p_sample_data, i_sample_size );
1921 output.Push( p_block );
1927 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1933 /******************************************************************************
1934 * removes each filter from the graph
1935 ******************************************************************************/
1936 HRESULT BDAGraph::Destroy()
1939 ULONG ul_refcount = 0;
1941 if( p_media_control )
1942 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
1944 if( d_graph_register )
1953 p_grabber->Release();
1957 if( p_transport_info )
1959 p_filter_graph->RemoveFilter( p_transport_info );
1960 p_transport_info->Release();
1961 p_transport_info = NULL;
1965 p_filter_graph->RemoveFilter( p_mpeg_demux );
1966 p_mpeg_demux->Release();
1967 p_mpeg_demux = NULL;
1969 if( p_sample_grabber )
1971 p_filter_graph->RemoveFilter( p_sample_grabber );
1972 p_sample_grabber->Release();
1973 p_sample_grabber = NULL;
1975 if( p_capture_device )
1977 p_filter_graph->RemoveFilter( p_capture_device );
1978 p_capture_device->Release();
1979 p_capture_device = NULL;
1981 if( p_tuner_device )
1983 p_filter_graph->RemoveFilter( p_tuner_device );
1984 p_tuner_device->Release();
1985 p_tuner_device = NULL;
1987 if( p_scanning_tuner )
1989 p_scanning_tuner->Release();
1990 p_scanning_tuner = NULL;
1992 if( p_network_provider )
1994 p_filter_graph->RemoveFilter( p_network_provider );
1995 p_network_provider->Release();
1996 p_network_provider = NULL;
1999 if( p_media_control )
2001 p_media_control->Release();
2002 p_media_control = NULL;
2004 if( p_filter_graph )
2006 p_filter_graph->Release();
2007 p_filter_graph = NULL;
2009 if( p_system_dev_enum )
2011 p_system_dev_enum->Release();
2012 p_system_dev_enum = NULL;
2018 /*****************************************************************************
2019 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
2020 * Allows GraphEdit to "spy" on a remote filter graph.
2021 ******************************************************************************/
2022 HRESULT BDAGraph::Register()
2027 IMoniker* p_moniker;
2028 IRunningObjectTable* p_ro_table;
2029 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
2033 p_moniker->Release();
2035 p_ro_table->Release();
2038 WCHAR psz_w_graph_name[128];
2041 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
2044 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
2048 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
2049 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
2050 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
2053 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
2056 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
2057 p_filter_graph, l.p_moniker, &d_graph_register );
2060 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
2063 // msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
2067 void BDAGraph::Deregister()
2070 IRunningObjectTable* p_ro_table;
2071 hr = ::GetRunningObjectTable( 0, &p_ro_table );
2072 if( SUCCEEDED( hr ) )
2073 p_ro_table->Revoke( d_graph_register );
2074 d_graph_register = 0;
2075 p_ro_table->Release();