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_SubmitATSCTuneRequest( access_t* p_access )
46 if( p_access->p_sys->p_bda_module )
47 return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
51 int dvb_SubmitDVBTTuneRequest( access_t* p_access )
53 if( p_access->p_sys->p_bda_module )
54 return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
58 int dvb_SubmitDVBCTuneRequest( access_t* p_access )
60 if( p_access->p_sys->p_bda_module )
61 return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
65 int dvb_SubmitDVBSTuneRequest( access_t* p_access )
67 if( p_access->p_sys->p_bda_module )
68 return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
72 long dvb_GetBufferSize( access_t* p_access )
74 if( p_access->p_sys->p_bda_module )
75 return p_access->p_sys->p_bda_module->GetBufferSize();
79 long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
81 if( p_access->p_sys->p_bda_module )
82 return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
88 /*****************************************************************************
90 *****************************************************************************/
91 BDAGraph::BDAGraph( access_t* p_this ):
93 guid_network_type(GUID_NULL),
98 p_tuning_space = NULL;
99 p_tune_request = NULL;
100 p_media_control = NULL;
101 p_filter_graph = NULL;
102 p_system_dev_enum = NULL;
103 p_network_provider = p_tuner_device = p_capture_device = NULL;
104 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
105 p_scanning_tuner = NULL;
108 /* Initialize COM - MS says to use CoInitializeEx in preference to
110 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
113 /*****************************************************************************
115 *****************************************************************************/
116 BDAGraph::~BDAGraph()
122 /*****************************************************************************
123 * Submit an ATSC Tune Request
124 *****************************************************************************/
125 int BDAGraph::SubmitATSCTuneRequest()
131 IATSCChannelTuneRequest* p_atsc_tune_request;
132 IATSCLocator* p_atsc_locator;
133 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
136 if( p_atsc_tune_request )
137 p_atsc_tune_request->Release();
139 p_atsc_locator->Release();
142 long l_major_channel, l_minor_channel, l_physical_channel;
145 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
146 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
147 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
148 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
150 guid_network_type = CLSID_ATSCNetworkProvider;
151 hr = CreateTuneRequest();
154 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
155 "Cannot create Tuning Space: hr=0x%8lx", hr );
159 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
160 (void**)&l.p_atsc_tune_request );
163 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
164 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
167 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
168 IID_IATSCLocator, (void**)&l.p_atsc_locator );
171 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
172 "Cannot create the ATSC locator: hr=0x%8lx", hr );
177 if( l_frequency > 0 )
178 hr = l.p_atsc_locator->put_CarrierFrequency( l_frequency );
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 IDVBTuningSpace2* p_dvb_tuning_space;
231 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL),
232 p_dvb_tuning_space(NULL) {};
235 if( p_dvbt_tune_request )
236 p_dvbt_tune_request->Release();
238 p_dvbt_locator->Release();
239 if( p_dvb_tuning_space )
240 p_dvb_tuning_space->Release();
243 long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
244 long l_transmission, l_hierarchy;
245 BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
246 GuardInterval i_guard;
247 TransmissionMode i_transmission;
248 HierarchyAlpha i_hierarchy;
250 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
251 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
252 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
253 l_lp_fec = var_GetInteger( p_access, "dvb-code-rate-lp" );
254 l_guard = var_GetInteger( p_access, "dvb-guard" );
255 l_transmission = var_GetInteger( p_access, "dvb-transmission" );
256 l_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
261 i_hp_fec = BDA_BCC_RATE_1_2; break;
263 i_hp_fec = BDA_BCC_RATE_2_3; break;
265 i_hp_fec = BDA_BCC_RATE_3_4; break;
267 i_hp_fec = BDA_BCC_RATE_5_6; break;
269 i_hp_fec = BDA_BCC_RATE_7_8;break;
271 i_hp_fec = BDA_BCC_RATE_NOT_SET;
277 i_lp_fec = BDA_BCC_RATE_1_2; break;
279 i_lp_fec = BDA_BCC_RATE_2_3; break;
281 i_lp_fec = BDA_BCC_RATE_3_4; break;
283 i_lp_fec = BDA_BCC_RATE_5_6; break;
285 i_lp_fec = BDA_BCC_RATE_7_8; break;
287 i_lp_fec = BDA_BCC_RATE_NOT_SET;
293 i_guard = BDA_GUARD_1_32; break;
295 i_guard = BDA_GUARD_1_16; break;
297 i_guard = BDA_GUARD_1_8; break;
299 i_guard = BDA_GUARD_1_4; break;
301 i_guard = BDA_GUARD_NOT_SET;
304 switch( l_transmission )
307 i_transmission = BDA_XMIT_MODE_2K; break;
309 i_transmission = BDA_XMIT_MODE_8K; break;
311 i_transmission = BDA_XMIT_MODE_NOT_SET;
314 switch( l_hierarchy )
317 i_hierarchy = BDA_HALPHA_1; break;
319 i_hierarchy = BDA_HALPHA_2; break;
321 i_hierarchy = BDA_HALPHA_4; break;
323 i_hierarchy = BDA_HALPHA_NOT_SET;
326 guid_network_type = CLSID_DVBTNetworkProvider;
327 hr = CreateTuneRequest();
330 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
331 "Cannot create Tune Request: hr=0x%8lx", hr );
335 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
336 (void**)&l.p_dvbt_tune_request );
339 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
340 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
343 l.p_dvbt_tune_request->put_ONID( -1 );
344 l.p_dvbt_tune_request->put_SID( -1 );
345 l.p_dvbt_tune_request->put_TSID( -1 );
347 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
348 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
351 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
352 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
355 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
356 (void**)&l.p_dvb_tuning_space );
359 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
360 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
365 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
367 if( SUCCEEDED( hr ) && l_frequency > 0 )
368 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
369 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
370 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
371 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
372 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
373 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
374 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
375 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
376 hr = l.p_dvbt_locator->put_Guard( i_guard );
377 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
378 hr = l.p_dvbt_locator->put_Mode( i_transmission );
379 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
380 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
383 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
384 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
388 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
391 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
392 "Cannot put the locator: hr=0x%8lx", hr );
396 /* Build and Run the Graph. If a Tuner device is in use the graph will
397 * fail to run. Repeated calls to build will check successive tuner
404 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
405 "Cannot Build the Graph: hr=0x%8lx", hr );
415 /*****************************************************************************
416 * Submit a DVB-C Tune Request
417 ******************************************************************************/
418 int BDAGraph::SubmitDVBCTuneRequest()
425 IDVBTuneRequest* p_dvbc_tune_request;
426 IDVBCLocator* p_dvbc_locator;
427 IDVBTuningSpace2* p_dvb_tuning_space;
429 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL),
430 p_dvb_tuning_space(NULL) {};
433 if( p_dvbc_tune_request )
434 p_dvbc_tune_request->Release();
436 p_dvbc_locator->Release();
437 if( p_dvb_tuning_space )
438 p_dvb_tuning_space->Release();
442 long l_frequency, l_symbolrate;
444 ModulationType i_qam_mod;
446 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
447 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
448 i_qam = var_GetInteger( p_access, "dvb-modulation" );
453 i_qam_mod = BDA_MOD_16QAM; break;
455 i_qam_mod = BDA_MOD_32QAM; break;
457 i_qam_mod = BDA_MOD_64QAM; break;
459 i_qam_mod = BDA_MOD_128QAM; break;
461 i_qam_mod = BDA_MOD_256QAM; break;
463 i_qam_mod = BDA_MOD_NOT_SET;
466 guid_network_type = CLSID_DVBCNetworkProvider;
467 hr = CreateTuneRequest();
470 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
471 "Cannot create Tune Request: hr=0x%8lx", hr );
475 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
476 (void**)&l.p_dvbc_tune_request );
479 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
480 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
483 l.p_dvbc_tune_request->put_ONID( -1 );
484 l.p_dvbc_tune_request->put_SID( -1 );
485 l.p_dvbc_tune_request->put_TSID( -1 );
487 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
488 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
491 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
492 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
495 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
496 (void**)&l.p_dvb_tuning_space );
499 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
500 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
505 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
507 if( SUCCEEDED( hr ) && l_frequency > 0 )
508 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
509 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
510 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
511 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
512 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
516 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
517 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
521 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
524 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
525 "Cannot put the locator: hr=0x%8lx", hr );
529 /* Build and Run the Graph. If a Tuner device is in use the graph will
530 * fail to run. Repeated calls to build will check successive tuner
537 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
538 "Cannot Build the Graph: hr=0x%8lx", hr );
548 /*****************************************************************************
549 * Submit a DVB-S Tune Request
550 ******************************************************************************/
551 int BDAGraph::SubmitDVBSTuneRequest()
558 IDVBTuneRequest* p_dvbs_tune_request;
559 IDVBSLocator* p_dvbs_locator;
560 IDVBSTuningSpace* p_dvbs_tuning_space;
561 char* psz_polarisation;
562 char* psz_input_range;
563 BSTR bstr_input_range;
564 WCHAR* pwsz_input_range;
566 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
567 p_dvbs_tuning_space(NULL), bstr_input_range(NULL),
568 pwsz_input_range(NULL), i_range_len(0), psz_polarisation(NULL),
569 psz_input_range(NULL) {};
572 if( p_dvbs_tuning_space )
573 p_dvbs_tuning_space->Release();
574 if( p_dvbs_tune_request )
575 p_dvbs_tune_request->Release();
577 p_dvbs_locator->Release();
578 SysFreeString( bstr_input_range );
579 delete pwsz_input_range;
580 free( psz_input_range );
581 free( psz_polarisation );
584 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
585 long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
588 Polarisation i_polar;
589 SpectralInversion i_inversion;
591 BinaryConvolutionCodeRate i_hp_fec;
592 ModulationType i_mod_typ;
594 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
595 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
596 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
597 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
598 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
599 l_lnb_lof1 = var_GetInteger( p_access, "dvb-lnb-lof1" );
600 l_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
601 l_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
602 i_mod = var_GetInteger( p_access, "dvb-modulation" );
603 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
604 l_inversion = var_GetInteger( p_access, "dvb-inversion" );
605 l_network_id = var_GetInteger( p_access, "dvb-network-id" );
607 l.psz_input_range = var_GetNonEmptyString( p_access, "dvb-range" );
608 l.psz_polarisation = var_GetNonEmptyString( p_access, "dvb-polarisation" );
610 b_west = ( l_longitude < 0 );
612 i_polar = BDA_POLARISATION_NOT_SET;
613 if( l.psz_polarisation != NULL )
615 switch( toupper( l.psz_polarisation[0] ) )
618 i_polar = BDA_POLARISATION_LINEAR_H;
621 i_polar = BDA_POLARISATION_LINEAR_V;
624 i_polar = BDA_POLARISATION_CIRCULAR_L;
627 i_polar = BDA_POLARISATION_CIRCULAR_R;
632 switch( l_inversion )
635 i_inversion = BDA_SPECTRAL_INVERSION_NORMAL; break;
637 i_inversion = BDA_SPECTRAL_INVERSION_INVERTED; break;
639 i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC; break;
641 i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
647 i_mod_typ = BDA_MOD_16QAM; break;
649 i_mod_typ = BDA_MOD_128QAM; break;
651 i_mod_typ = BDA_MOD_256QAM; break;
653 i_mod_typ = BDA_MOD_QPSK; break;
655 i_mod_typ = BDA_MOD_NOT_SET;
661 i_hp_fec = BDA_BCC_RATE_1_2; break;
663 i_hp_fec = BDA_BCC_RATE_2_3; break;
665 i_hp_fec = BDA_BCC_RATE_3_4; break;
667 i_hp_fec = BDA_BCC_RATE_5_6; break;
669 i_hp_fec = BDA_BCC_RATE_7_8; break;
671 i_hp_fec = BDA_BCC_RATE_NOT_SET;
674 l.i_range_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
675 l.psz_input_range, -1, l.pwsz_input_range, 0 );
676 if( l.i_range_len > 0 )
678 l.pwsz_input_range = new WCHAR[l.i_range_len];
679 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
680 l.psz_input_range, -1, l.pwsz_input_range, l.i_range_len );
681 l.bstr_input_range=SysAllocString( l.pwsz_input_range );
684 guid_network_type = CLSID_DVBSNetworkProvider;
685 hr = CreateTuneRequest();
688 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
689 "Cannot create Tune Request: hr=0x%8lx", hr );
693 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
694 (void**)&l.p_dvbs_tune_request );
697 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
698 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
701 l.p_dvbs_tune_request->put_ONID( -1 );
702 l.p_dvbs_tune_request->put_SID( -1 );
703 l.p_dvbs_tune_request->put_TSID( -1 );
705 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
706 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
709 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
710 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
714 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
715 (void**)&l.p_dvbs_tuning_space );
718 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
719 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
724 hr = l.p_dvbs_tuning_space->put_SystemType( DVB_Satellite );
725 if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
726 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
727 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
728 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
729 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
730 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
731 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
732 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
733 if( SUCCEEDED( hr ) && l_network_id > 0 )
734 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
735 if( SUCCEEDED( hr ) && l.i_range_len > 0 )
736 hr = l.p_dvbs_tuning_space->put_InputRange( l.bstr_input_range );
738 if( SUCCEEDED( hr ) && l_frequency > 0 )
739 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
740 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
741 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
742 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
743 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
744 if( SUCCEEDED( hr ) && i_mod_typ != BDA_MOD_NOT_SET )
745 hr = l.p_dvbs_locator->put_Modulation( i_mod_typ );
746 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
747 hr = l.p_dvbs_locator->put_InnerFECRate( i_hp_fec );
749 if( SUCCEEDED( hr ) && l_azimuth > 0 )
750 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
751 if( SUCCEEDED( hr ) && l_elevation > 0 )
752 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
753 if( SUCCEEDED( hr ) )
754 hr = l.p_dvbs_locator->put_WestPosition( b_west );
755 if( SUCCEEDED( hr ) )
756 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
759 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
760 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
764 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
767 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
768 "Cannot put the locator: hr=0x%8lx", hr );
772 /* Build and Run the Graph. If a Tuner device is in use the graph will
773 * fail to run. Repeated calls to build will check successive tuner
780 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
781 "Cannot Build the Graph: hr=0x%8lx", hr );
791 /*****************************************************************************
792 * Load the Tuning Space from System Tuning Spaces according to the
793 * Network Type requested
794 ******************************************************************************/
795 HRESULT BDAGraph::CreateTuneRequest()
798 GUID guid_this_network_type;
802 ITuningSpaceContainer* p_tuning_space_container;
803 IEnumTuningSpaces* p_tuning_space_enum;
804 ITuningSpace* p_this_tuning_space;
805 IDVBTuningSpace2* p_dvb_tuning_space;
807 char * psz_network_name;
808 char * psz_create_name;
809 char * psz_bstr_name;
810 WCHAR * wpsz_create_name;
812 localComPtr(): p_tuning_space_container(NULL),
813 p_tuning_space_enum(NULL), p_this_tuning_space(NULL),
814 p_dvb_tuning_space(NULL),
815 i_name_len(0), psz_network_name(NULL), wpsz_create_name(NULL),
816 psz_create_name(NULL), bstr_name(NULL), psz_bstr_name(NULL) {};
819 if( p_tuning_space_enum )
820 p_tuning_space_enum->Release();
821 if( p_tuning_space_container )
822 p_tuning_space_container->Release();
823 if( p_this_tuning_space )
824 p_this_tuning_space->Release();
825 if( p_dvb_tuning_space )
826 p_dvb_tuning_space->Release();
827 SysFreeString( bstr_name );
828 delete[] psz_bstr_name;
829 delete[] wpsz_create_name;
830 free( psz_network_name );
831 free( psz_create_name );
835 /* We shall test for a specific Tuning space name supplied on the command
836 * line as dvb-networkname=xxx.
837 * For some users with multiple cards and/or multiple networks this could
838 * be useful. This allows us to reasonably safely apply updates to the
839 * System Tuning Space in the registry without disrupting other streams. */
840 l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-network-name" );
841 if( l.psz_network_name )
843 msg_Dbg( p_access, "CreateTuneRequest: Find Tuning Space: %s",
844 l.psz_network_name );
848 l.psz_network_name = new char[1];
849 *l.psz_network_name = '\0';
852 /* A Tuning Space may already have been set up. If it is for the same
853 * network type then all is well. Otherwise, reset the Tuning Space and get
857 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
858 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
859 if( guid_this_network_type == guid_network_type )
861 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
864 msg_Warn( p_access, "CreateTuneRequest: "\
865 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
868 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
869 l.psz_bstr_name, 0, NULL, NULL );
870 l.psz_bstr_name = new char[ l.i_name_len ];
871 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
872 l.psz_bstr_name, l.i_name_len, NULL, NULL );
874 /* Test for a specific Tuning space name supplied on the command
875 * line as dvb-networkname=xxx */
876 if( strlen( l.psz_network_name ) == 0 ||
877 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
879 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
880 l.psz_network_name );
884 /* else different guid_network_type */
886 p_tuning_space->Release();
888 p_tune_request->Release();
889 p_tuning_space = NULL;
890 p_tune_request = NULL;
893 /* Force use of the first available Tuner Device during Build */
896 /* Get the SystemTuningSpaces container to enumerate through all the
897 * defined tuning spaces.
898 * l.p_tuning_space_container->Refcount = 1 */
899 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
900 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
903 msg_Warn( p_access, "CreateTuneRequest: "\
904 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
908 /* Get the SystemTuningSpaces container to enumerate through all the
909 * defined tuning spaces.
910 * l.p_tuning_space_container->Refcount = 2
911 * l.p_tuning_space_enum->Refcount = 1 */
912 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
913 &l.p_tuning_space_enum );
916 msg_Warn( p_access, "CreateTuneRequest: "\
917 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
923 /* l.p_this_tuning_space->RefCount = 1 after the first pass
924 * Release before overwriting with Next */
925 if( l.p_this_tuning_space )
926 l.p_this_tuning_space->Release();
927 l.p_this_tuning_space = NULL;
928 SysFreeString( l.bstr_name );
930 hr = l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL );
931 if( hr != S_OK ) break;
933 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
935 /* GUID_NULL means a non-BDA network was found e.g analog
936 * Ignore failures and non-BDA networks and keep looking */
937 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
939 if( guid_this_network_type == guid_network_type )
941 /* QueryInterface to clone l.p_this_tuning_space
942 * l.p_this_tuning_space->RefCount = 2 */
943 hr = l.p_this_tuning_space->Clone( &p_tuning_space );
946 msg_Warn( p_access, "CreateTuneRequest: "\
947 "Cannot QI Tuning Space: hr=0x%8lx", hr );
950 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
953 msg_Warn( p_access, "CreateTuneRequest: "\
954 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
958 /* Test for a specific Tuning space name supplied on the command
959 * line as dvb-networkname=xxx */
960 delete[] l.psz_bstr_name;
961 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
962 l.psz_bstr_name, 0, NULL, NULL );
963 l.psz_bstr_name = new char[ l.i_name_len ];
964 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
965 l.psz_bstr_name, l.i_name_len, NULL, NULL );
966 if( strlen( l.psz_network_name ) == 0 ||
967 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
969 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
972 /* CreateTuneRequest adds TuneRequest to p_tuning_space
973 * p_tune_request->RefCount = 1 */
974 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
976 msg_Warn( p_access, "CreateTuneRequest: "\
977 "Cannot Create Tune Request: hr=0x%8lx", hr );
981 p_tuning_space->Release();
982 p_tuning_space = NULL;
987 /* No tuning space was found. If the create-name parameter was set then
988 * create a tuning space. By rights should use the same name used in
990 * Also would be nice to copy a tuning space but we only come here if we do
992 l.psz_create_name = var_GetNonEmptyString( p_access, "dvb-create-name" );
993 if( !l.psz_create_name || strlen( l.psz_create_name ) <= 0 )
996 msg_Warn( p_access, "CreateTuneRequest: "\
997 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
1000 if( strcmp( l.psz_create_name, l.psz_network_name ) )
1003 msg_Warn( p_access, "CreateTuneRequest: "\
1004 "dvb-create-name %s must match dvb-network-name %s",
1005 l.psz_create_name, l.psz_network_name );
1009 /* Need to use DVBSTuningSpace for DVB-S and ATSCTuningSpace for ATSC */
1011 CLSID cls_tuning_space;
1013 if( IsEqualCLSID( guid_network_type, CLSID_ATSCNetworkProvider ) )
1014 cls_tuning_space = CLSID_ATSCTuningSpace;
1015 if( IsEqualCLSID( guid_network_type, CLSID_DVBTNetworkProvider ) )
1016 cls_tuning_space = CLSID_DVBTuningSpace;
1017 if( IsEqualCLSID( guid_network_type, CLSID_DVBCNetworkProvider ) )
1018 cls_tuning_space = CLSID_DVBTuningSpace;
1019 if( IsEqualCLSID( guid_network_type, CLSID_DVBSNetworkProvider ) )
1020 cls_tuning_space = CLSID_DVBSTuningSpace;
1022 l.i_name_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
1023 l.psz_create_name, -1, l.wpsz_create_name, 0 );
1024 if( l.i_name_len <= 0 )
1027 msg_Warn( p_access, "CreateTuneRequest: "\
1028 "Cannot convert zero length dvb-create-name %s",
1029 l.psz_create_name );
1032 l.wpsz_create_name = new WCHAR[l.i_name_len];
1033 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, l.psz_create_name, -1,
1034 l.wpsz_create_name, l.i_name_len );
1036 SysFreeString( l.bstr_name );
1037 l.bstr_name = SysAllocString( l.wpsz_create_name );
1039 msg_Dbg( p_access, "CreateTuneRequest: Create Tuning Space: %s",
1040 l.psz_create_name );
1042 hr = ::CoCreateInstance( cls_tuning_space, 0, CLSCTX_INPROC,
1043 IID_ITuningSpace, (void**)&p_tuning_space );
1046 msg_Warn( p_access, "CreateTuneRequest: "\
1047 "Cannot CoCreate new TuningSpace: hr=0x%8lx", hr );
1048 if( SUCCEEDED( hr ) )
1049 hr = p_tuning_space->put__NetworkType( guid_network_type );
1051 msg_Warn( p_access, "CreateTuneRequest: "\
1052 "Cannot Put Network Type: hr=0x%8lx", hr );
1053 if( SUCCEEDED( hr ) )
1054 hr = p_tuning_space->put_UniqueName( l.bstr_name );
1056 msg_Warn( p_access, "CreateTuneRequest: "\
1057 "Cannot Put Unique Name: hr=0x%8lx", hr );
1058 if( SUCCEEDED( hr ) )
1059 hr = p_tuning_space->put_FriendlyName( l.bstr_name );
1061 msg_Warn( p_access, "CreateTuneRequest: "\
1062 "Cannot Put Friendly Name: hr=0x%8lx", hr );
1063 if( guid_network_type == CLSID_DVBTNetworkProvider ||
1064 guid_network_type == CLSID_DVBCNetworkProvider ||
1065 guid_network_type == CLSID_DVBSNetworkProvider )
1067 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
1068 (void**)&l.p_dvb_tuning_space );
1071 msg_Warn( p_access, "CreateTuneRequest: "\
1072 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
1075 if( guid_network_type == CLSID_DVBTNetworkProvider )
1076 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
1077 if( guid_network_type == CLSID_DVBCNetworkProvider )
1078 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
1079 if( guid_network_type == CLSID_DVBSNetworkProvider )
1080 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Satellite );
1083 if( SUCCEEDED( hr ) )
1084 hr = l.p_tuning_space_container->Add( p_tuning_space, &var_id );
1088 msg_Warn( p_access, "CreateTuneRequest: "\
1089 "Cannot Create new TuningSpace: hr=0x%8lx", hr );
1093 msg_Dbg( p_access, "CreateTuneRequest: Tuning Space: %s created",
1094 l.psz_create_name );
1096 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
1098 msg_Warn( p_access, "CreateTuneRequest: "\
1099 "Cannot Create Tune Request: hr=0x%8lx", hr );
1104 /******************************************************************************
1106 * Step 4: Build the Filter Graph
1107 * Build sets up devices, adds and connects filters
1108 ******************************************************************************/
1109 HRESULT BDAGraph::Build()
1112 long l_capture_used, l_tif_used;
1113 VARIANT l_tuning_space_id;
1114 AM_MEDIA_TYPE grabber_media_type;
1118 ITuningSpaceContainer* p_tuning_space_container;
1119 localComPtr(): p_tuning_space_container(NULL) {};
1122 if( p_tuning_space_container )
1123 p_tuning_space_container->Release();
1127 /* Get the SystemTuningSpaces container to save the Tuning space */
1128 l_tuning_space_id.vt = VT_I4;
1129 l_tuning_space_id.lVal = 0L;
1130 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
1131 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
1134 msg_Warn( p_access, "Build: "\
1135 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
1138 hr = l.p_tuning_space_container->FindID( p_tuning_space,
1139 &l_tuning_space_id.lVal );
1142 msg_Warn( p_access, "Build: "\
1143 "Cannot Find Tuning Space ID: hr=0x%8lx", hr );
1146 msg_Dbg( p_access, "Build: Using Tuning Space ID %d",
1147 l_tuning_space_id.lVal );
1148 hr = l.p_tuning_space_container->put_Item( l_tuning_space_id,
1152 msg_Warn( p_access, "Build: "\
1153 "Cannot save Tuning Space: hr=0x%8lx", hr );
1157 /* If we have already have a filter graph, rebuild it*/
1160 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1161 IID_IGraphBuilder, (void**)&p_filter_graph );
1164 msg_Warn( p_access, "Build: "\
1165 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
1169 /* First filter in the graph is the Network Provider and
1170 * its Scanning Tuner which takes the Tune Request*/
1171 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
1172 IID_IBaseFilter, (void**)&p_network_provider);
1175 msg_Warn( p_access, "Build: "\
1176 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
1179 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
1182 msg_Warn( p_access, "Build: "\
1183 "Cannot load network provider: hr=0x%8lx", hr );
1187 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
1188 (void**)&p_scanning_tuner );
1191 msg_Warn( p_access, "Build: "\
1192 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
1196 hr = p_scanning_tuner->Validate( p_tune_request );
1199 msg_Warn( p_access, "Build: "\
1200 "Tune Request is invalid: hr=0x%8lx", hr );
1203 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
1206 msg_Warn( p_access, "Build: "\
1207 "Cannot submit the tune request: hr=0x%8lx", hr );
1211 /* Add the Network Tuner to the Network Provider. On subsequent calls,
1212 * l_tuner_used will cause a different tuner to be selected
1213 * To select a specific device first get the parameter that nominates the
1214 * device (dvb-adapter) and use the value to initialise l_tuner_used.
1215 * When FindFilter returns check the contents of l_tuner_used.
1216 * If it is not what was selected then the requested device was not
1217 * available so return with an error. */
1219 long l_adapter = -1;
1220 l_adapter = var_GetInteger( p_access, "dvb-adapter" );
1221 if( l_tuner_used < 0 && l_adapter >= 0 )
1222 l_tuner_used = l_adapter - 1;
1224 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
1225 p_network_provider, &p_tuner_device );
1228 msg_Warn( p_access, "Build: "\
1229 "Cannot load tuner device and connect network provider: "\
1233 if( l_adapter > 0 && l_tuner_used != l_adapter )
1235 msg_Warn( p_access, "Build: "\
1236 "Tuner device %d is not available", l_adapter );
1239 msg_Dbg( p_access, "BDAGraph: Using adapter %d", l_tuner_used );
1241 /* VLC 1.0 works reliably up this point then crashes
1242 * Obvious candidate is FindFilter */
1243 /* Always look for all capture devices to match the Network Tuner */
1244 l_capture_used = -1;
1245 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
1246 p_tuner_device, &p_capture_device );
1249 /* Some BDA drivers do not provide a Capture Device Filter so force
1250 * the Sample Grabber to connect directly to the Tuner Device */
1251 p_capture_device = p_tuner_device;
1252 p_tuner_device = NULL;
1253 msg_Warn( p_access, "Build: "\
1254 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
1256 if( p_sample_grabber )
1257 p_sample_grabber->Release();
1258 p_sample_grabber = NULL;
1259 /* Insert the Sample Grabber to tap into the Transport Stream. */
1260 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
1261 IID_IBaseFilter, (void**)&p_sample_grabber );
1264 msg_Warn( p_access, "Build: "\
1265 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
1268 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
1271 msg_Warn( p_access, "Build: "\
1272 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
1277 p_grabber->Release();
1279 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
1280 (void**)&p_grabber );
1283 msg_Warn( p_access, "Build: "\
1284 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
1288 /* Try the possible stream type */
1290 for( int i = 0; i < 2; i++ )
1292 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
1293 grabber_media_type.majortype = MEDIATYPE_Stream;
1294 grabber_media_type.subtype = i == 0 ? MEDIASUBTYPE_MPEG2_TRANSPORT : KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT;
1295 msg_Dbg( p_access, "Build: "
1296 "Trying connecting with subtype %s",
1297 i == 0 ? "MEDIASUBTYPE_MPEG2_TRANSPORT" : "KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT" );
1298 hr = p_grabber->SetMediaType( &grabber_media_type );
1299 if( SUCCEEDED( hr ) )
1301 hr = Connect( p_capture_device, p_sample_grabber );
1302 if( SUCCEEDED( hr ) )
1304 msg_Warn( p_access, "Build: "\
1305 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr, 1+i );
1309 msg_Warn( p_access, "Build: "\
1310 "Cannot set media type on grabber filter: hr=0x%8lx (try %d/2", hr, 1+i );
1316 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
1317 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
1318 * the Network Provider filter to set up the stream */
1319 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
1320 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
1323 msg_Warn( p_access, "Build: "\
1324 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
1327 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
1330 msg_Warn( p_access, "Build: "\
1331 "Cannot add demux filter to graph: hr=0x%8lx", hr );
1334 hr = Connect( p_sample_grabber, p_mpeg_demux );
1337 msg_Warn( p_access, "Build: "\
1338 "Cannot connect demux to grabber: hr=0x%8lx", hr );
1342 /* Always look for the Transform Information Filter from the start
1343 * of the collection*/
1345 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
1346 p_mpeg_demux, &p_transport_info );
1349 msg_Warn( p_access, "Build: "\
1350 "Cannot load TIF onto demux: hr=0x%8lx", hr );
1353 /* Configure the Sample Grabber to buffer the samples continuously */
1354 hr = p_grabber->SetBufferSamples( true );
1357 msg_Warn( p_access, "Build: "\
1358 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
1361 hr = p_grabber->SetOneShot( false );
1364 msg_Warn( p_access, "Build: "\
1365 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
1368 hr = p_grabber->SetCallback( this, 0 );
1371 msg_Warn( p_access, "Build: "\
1372 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
1379 d_graph_register = 0;
1382 /* The Media Control is used to Run and Stop the Graph */
1383 if( p_media_control )
1384 p_media_control->Release();
1385 p_media_control = NULL;
1386 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
1387 (void**)&p_media_control );
1390 msg_Warn( p_access, "Build: "\
1391 "Cannot QI Media Control: hr=0x%8lx", hr );
1399 /******************************************************************************
1401 * Looks up all filters in a category and connects to the upstream filter until
1402 * a successful match is found. The index of the connected filter is returned.
1403 * On subsequent calls, this can be used to start from that point to find
1405 * This is used when the graph does not run because a tuner device is in use so
1406 * another one needs to be selected.
1407 ******************************************************************************/
1408 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
1409 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
1412 int i_moniker_index = -1;
1416 IMoniker* p_moniker;
1417 IEnumMoniker* p_moniker_enum;
1418 IBaseFilter* p_filter;
1419 IPropertyBag* p_property_bag;
1425 p_moniker_enum(NULL),
1427 p_property_bag(NULL),
1429 { ::VariantInit(&var_bstr); };
1432 if( p_property_bag )
1433 p_property_bag->Release();
1435 p_filter->Release();
1437 p_moniker->Release();
1438 if( p_moniker_enum )
1439 p_moniker_enum->Release();
1440 ::VariantClear(&var_bstr);
1445 if( !p_system_dev_enum )
1447 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1448 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1451 msg_Warn( p_access, "FindFilter: "\
1452 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1457 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1458 &l.p_moniker_enum, 0 );
1461 msg_Warn( p_access, "FindFilter: "\
1462 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1468 /* We are overwriting l.p_moniker so we should Release and nullify
1469 * It is important that p_moniker and p_property_bag are fully released
1470 * l.p_filter may not be dereferenced so we could force to NULL */
1471 if( l.p_property_bag )
1472 l.p_property_bag->Release();
1473 l.p_property_bag = NULL;
1475 l.p_filter->Release();
1478 l.p_moniker->Release();
1481 hr = l.p_moniker_enum->Next( 1, &l.p_moniker, 0 );
1482 if( hr != S_OK ) break;
1485 /* Skip over devices already found on previous calls */
1486 if( i_moniker_index <= *i_moniker_used ) continue;
1487 *i_moniker_used = i_moniker_index;
1489 /* l.p_filter is Released at the top of the loop */
1490 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1491 (void**)&l.p_filter );
1496 /* l.p_property_bag is released at the top of the loop */
1497 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1498 (void**)&l.p_property_bag );
1501 msg_Warn( p_access, "FindFilter: "\
1502 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1505 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1508 msg_Warn( p_access, "FindFilter: "\
1509 "Cannot read filter friendly name: hr=0x%8lx", hr );
1513 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1516 msg_Warn( p_access, "FindFilter: "\
1517 "Cannot add filter: hr=0x%8lx", hr );
1520 hr = Connect( p_upstream, l.p_filter );
1521 if( SUCCEEDED( hr ) )
1523 /* p_p_downstream has not been touched yet so no release needed */
1524 delete[] l.psz_bstr;
1525 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1526 l.var_bstr.bstrVal, -1, l.psz_bstr, 0, NULL, NULL );
1527 l.psz_bstr = new char[l.i_bstr_len];
1528 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1529 l.var_bstr.bstrVal, -1, l.psz_bstr, l.i_bstr_len, NULL, NULL );
1530 msg_Dbg( p_access, "FindFilter: Connected %s", l.psz_bstr );
1531 l.p_filter->QueryInterface( IID_IBaseFilter,
1532 (void**)p_p_downstream );
1535 /* Not the filter we want so unload and try the next one */
1536 hr = p_filter_graph->RemoveFilter( l.p_filter );
1539 msg_Warn( p_access, "FindFilter: "\
1540 "Failed unloading Filter: hr=0x%8lx", hr );
1548 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1552 /*****************************************************************************
1553 * Connect is called from Build to enumerate and connect pins
1554 *****************************************************************************/
1555 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1557 HRESULT hr = E_FAIL;
1561 IPin* p_pin_upstream;
1562 IPin* p_pin_downstream;
1563 IEnumPins* p_pin_upstream_enum;
1564 IEnumPins* p_pin_downstream_enum;
1566 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1567 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1568 p_pin_temp(NULL) { };
1572 p_pin_temp->Release();
1573 if( p_pin_downstream )
1574 p_pin_downstream->Release();
1575 if( p_pin_upstream )
1576 p_pin_upstream->Release();
1577 if( p_pin_downstream_enum )
1578 p_pin_downstream_enum->Release();
1579 if( p_pin_upstream_enum )
1580 p_pin_upstream_enum->Release();
1584 PIN_DIRECTION pin_dir;
1586 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1589 msg_Warn( p_access, "Connect: "\
1590 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1596 /* Release l.p_pin_upstream before next iteration */
1597 if( l.p_pin_upstream )
1598 l.p_pin_upstream ->Release();
1599 l.p_pin_upstream = NULL;
1600 hr = l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 );
1601 if( hr != S_OK ) break;
1603 hr = l.p_pin_upstream->QueryDirection( &pin_dir );
1606 msg_Warn( p_access, "Connect: "\
1607 "Cannot get upstream filter pin direction: hr=0x%8lx", hr );
1610 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1611 if( SUCCEEDED( hr ) )
1613 l.p_pin_downstream->Release();
1614 l.p_pin_downstream = NULL;
1616 if( FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1618 msg_Warn( p_access, "Connect: "\
1619 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1622 if( ( pin_dir == PINDIR_OUTPUT ) && ( hr == VFW_E_NOT_CONNECTED ) )
1624 /* The upstream pin is not yet connected so check each pin on the
1625 * downstream filter */
1626 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1629 msg_Warn( p_access, "Connect: Cannot get "\
1630 "downstream filter enumerator: hr=0x%8lx", hr );
1635 /* Release l.p_pin_downstream before next iteration */
1636 if( l.p_pin_downstream )
1637 l.p_pin_downstream ->Release();
1638 l.p_pin_downstream = NULL;
1640 hr = l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 );
1641 if( hr != S_OK ) break;
1643 hr = l.p_pin_downstream->QueryDirection( &pin_dir );
1646 msg_Warn( p_access, "Connect: Cannot get "\
1647 "downstream filter pin direction: hr=0x%8lx", hr );
1651 /* Looking for a free Pin to connect to
1652 * A connected Pin may have an reference count > 1
1653 * so Release and nullify the pointer */
1654 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1655 if( SUCCEEDED( hr ) )
1657 l.p_pin_temp->Release();
1658 l.p_pin_temp = NULL;
1660 if( hr != VFW_E_NOT_CONNECTED )
1664 msg_Warn( p_access, "Connect: Cannot check "\
1665 "downstream filter connection: hr=0x%8lx", hr );
1669 if( ( pin_dir == PINDIR_INPUT ) &&
1670 ( hr == VFW_E_NOT_CONNECTED ) )
1672 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1673 l.p_pin_downstream, NULL );
1674 if( SUCCEEDED( hr ) )
1676 /* If we arrive here then we have a matching pair of
1681 /* If we arrive here it means this downstream pin is not
1682 * suitable so try the next downstream pin.
1683 * l.p_pin_downstream is released at the top of the loop */
1686 /* If we arrive here then we ran out of pins before we found a
1687 * suitable one. Release outstanding refcounts */
1688 if( l.p_pin_downstream_enum )
1689 l.p_pin_downstream_enum->Release();
1690 l.p_pin_downstream_enum = NULL;
1691 if( l.p_pin_downstream )
1692 l.p_pin_downstream->Release();
1693 l.p_pin_downstream = NULL;
1695 /* If we arrive here it means this upstream pin is not suitable
1696 * so try the next upstream pin
1697 * l.p_pin_upstream is released at the top of the loop */
1700 /* If we arrive here it means we did not find any pair of suitable pins
1701 * Outstanding refcounts are released in the destructor */
1705 /*****************************************************************************
1706 * Start uses MediaControl to start the graph
1707 *****************************************************************************/
1708 HRESULT BDAGraph::Start()
1711 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1713 if( !p_media_control )
1715 msg_Dbg( p_access, "Start: Media Control has not been created" );
1718 hr = p_media_control->Run();
1719 msg_Dbg( p_access, "Graph started hr=0x%lx", hr );
1723 /* Query the state of the graph - timeout after 100 milliseconds */
1724 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1729 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1733 if( i_state == State_Running )
1736 /* The Graph is not running so stop it and return an error */
1737 msg_Warn( p_access, "Start: Graph not started: %d", i_state );
1738 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
1742 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1748 /*****************************************************************************
1749 * Read the stream of data - query the buffer size required
1750 *****************************************************************************/
1751 long BDAGraph::GetBufferSize()
1753 long l_buffer_size = 0;
1758 for( int i_timer = 0; queue_sample.empty() && i_timer < 200; i_timer++ )
1761 l_queue_size = queue_sample.size();
1762 if( l_queue_size <= 0 )
1764 msg_Warn( p_access, "BDA GetBufferSize: Timed Out waiting for sample" );
1768 /* Establish the length of the queue as it grows quickly. If the queue
1769 * size is checked dynamically there is a risk of not exiting the loop */
1770 for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1772 l_buffer_size += queue_sample.front()->GetActualDataLength();
1773 queue_buffer.push( queue_sample.front() );
1776 return l_buffer_size;
1779 /*****************************************************************************
1780 * Read the stream of data - Retrieve from the buffer queue
1781 ******************************************************************************/
1782 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1789 while( !queue_buffer.empty() )
1791 queue_buffer.front()->GetPointer( &p_buff_temp );
1792 hr = queue_buffer.front()->IsDiscontinuity();
1795 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1796 memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1797 queue_buffer.front()->GetActualDataLength() );
1798 *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1799 queue_buffer.front()->Release();
1803 return *pl_buffer_len;
1806 /******************************************************************************
1807 * SampleCB - Callback when the Sample Grabber has a sample
1808 ******************************************************************************/
1809 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1814 queue_sample.push( p_sample );
1818 msg_Warn( p_access, "BDA SampleCB: Not ready - dropped sample" );
1823 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1829 /******************************************************************************
1830 * removes each filter from the graph
1831 ******************************************************************************/
1832 HRESULT BDAGraph::Destroy()
1835 ULONG ul_refcount = 0;
1837 if( p_media_control )
1838 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
1840 if( d_graph_register )
1845 /* We need to empty the buffers of any unprocessed data */
1846 msg_Dbg( p_access, "Queue sample size = %d", queue_sample.size() );
1847 while( !queue_sample.empty() )
1849 ul_refcount = queue_sample.front()->Release();
1852 msg_Warn( p_access, "BDAGraph: Non-zero Ref: %d", ul_refcount );
1854 msg_Dbg( p_access, "Queue buffer size = %d", queue_buffer.size() );
1855 while( !queue_buffer.empty() )
1857 ul_refcount = queue_buffer.front()->Release();
1860 msg_Warn( p_access, "BDAGraph: Non-zero Ref: %d", ul_refcount );
1864 p_grabber->Release();
1868 if( p_transport_info )
1870 p_filter_graph->RemoveFilter( p_transport_info );
1871 p_transport_info->Release();
1872 p_transport_info = NULL;
1876 p_filter_graph->RemoveFilter( p_mpeg_demux );
1877 p_mpeg_demux->Release();
1878 p_mpeg_demux = NULL;
1880 if( p_sample_grabber )
1882 p_filter_graph->RemoveFilter( p_sample_grabber );
1883 p_sample_grabber->Release();
1884 p_sample_grabber = NULL;
1886 if( p_capture_device )
1888 p_filter_graph->RemoveFilter( p_capture_device );
1889 p_capture_device->Release();
1890 p_capture_device = NULL;
1892 if( p_tuner_device )
1894 p_filter_graph->RemoveFilter( p_tuner_device );
1895 p_tuner_device->Release();
1896 p_tuner_device = NULL;
1898 if( p_scanning_tuner )
1900 p_scanning_tuner->Release();
1901 p_scanning_tuner = NULL;
1903 if( p_network_provider )
1905 p_filter_graph->RemoveFilter( p_network_provider );
1906 p_network_provider->Release();
1907 p_network_provider = NULL;
1910 if( p_media_control )
1912 p_media_control->Release();
1913 p_media_control = NULL;
1915 if( p_filter_graph )
1917 p_filter_graph->Release();
1918 p_filter_graph = NULL;
1920 if( p_system_dev_enum )
1922 p_system_dev_enum->Release();
1923 p_system_dev_enum = NULL;
1929 /*****************************************************************************
1930 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1931 * Allows GraphEdit to "spy" on a remote filter graph.
1932 ******************************************************************************/
1933 HRESULT BDAGraph::Register()
1938 IMoniker* p_moniker;
1939 IRunningObjectTable* p_ro_table;
1940 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1944 p_moniker->Release();
1946 p_ro_table->Release();
1949 WCHAR psz_w_graph_name[128];
1952 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1955 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1959 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1960 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1961 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1964 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1967 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1968 p_filter_graph, l.p_moniker, &d_graph_register );
1971 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1974 // msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1978 void BDAGraph::Deregister()
1981 IRunningObjectTable* p_ro_table;
1982 hr = ::GetRunningObjectTable( 0, &p_ro_table );
1983 if( SUCCEEDED( hr ) )
1984 p_ro_table->Revoke( d_graph_register );
1985 d_graph_register = 0;
1986 p_ro_table->Release();