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 block_t *dvb_Pop( access_t* p_access )
74 if( p_access->p_sys->p_bda_module )
75 return p_access->p_sys->p_bda_module->Pop();
80 /*****************************************************************************
82 *****************************************************************************/
83 BDAOutput::BDAOutput( access_t *p_access ) :
84 p_access(p_access), p_first(NULL), pp_next(&p_first)
86 vlc_mutex_init( &lock );
87 vlc_cond_init( &wait );
89 BDAOutput::~BDAOutput()
92 vlc_mutex_destroy( &lock );
93 vlc_cond_destroy( &wait );
95 void BDAOutput::Push( block_t *p_block )
97 vlc_mutex_locker l( &lock );
99 block_ChainLastAppend( &pp_next, p_block );
100 vlc_cond_signal( &wait );
102 block_t *BDAOutput::Pop()
104 vlc_mutex_locker l( &lock );
107 vlc_cond_timedwait( &wait, &lock, mdate() + 250*1000 );
109 block_t *p_ret = p_first;
116 void BDAOutput::Empty()
118 vlc_mutex_locker l( &lock );
121 block_ChainRelease( p_first );
126 /*****************************************************************************
128 *****************************************************************************/
129 BDAGraph::BDAGraph( access_t* p_this ):
131 guid_network_type(GUID_NULL),
133 d_graph_register( 0 ),
136 p_tuning_space = NULL;
137 p_tune_request = NULL;
138 p_media_control = NULL;
139 p_filter_graph = NULL;
140 p_system_dev_enum = NULL;
141 p_network_provider = p_tuner_device = p_capture_device = NULL;
142 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
143 p_scanning_tuner = NULL;
146 /* Initialize COM - MS says to use CoInitializeEx in preference to
148 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
151 /*****************************************************************************
153 *****************************************************************************/
154 BDAGraph::~BDAGraph()
160 /*****************************************************************************
161 * Submit an ATSC Tune Request
162 *****************************************************************************/
163 int BDAGraph::SubmitATSCTuneRequest()
169 IATSCChannelTuneRequest* p_atsc_tune_request;
170 IATSCLocator* p_atsc_locator;
171 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
174 if( p_atsc_tune_request )
175 p_atsc_tune_request->Release();
177 p_atsc_locator->Release();
180 long l_major_channel, l_minor_channel, l_physical_channel;
183 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
184 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
185 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
186 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
188 guid_network_type = CLSID_ATSCNetworkProvider;
189 hr = CreateTuneRequest();
192 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
193 "Cannot create Tuning Space: hr=0x%8lx", hr );
197 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
198 (void**)&l.p_atsc_tune_request );
201 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
202 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
205 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
206 IID_IATSCLocator, (void**)&l.p_atsc_locator );
209 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
210 "Cannot create the ATSC locator: hr=0x%8lx", hr );
215 if( l_frequency > 0 )
216 hr = l.p_atsc_locator->put_CarrierFrequency( l_frequency );
217 if( l_major_channel > 0 )
218 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
219 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
220 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
221 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
222 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
225 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
226 "Cannot set tuning parameters: hr=0x%8lx", hr );
230 hr = p_tune_request->put_Locator( l.p_atsc_locator );
233 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
234 "Cannot put the locator: hr=0x%8lx", hr );
238 /* Build and Run the Graph. If a Tuner device is in use the graph will
239 * fail to run. Repeated calls to build will check successive tuner
246 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
247 "Cannot Build the Graph: hr=0x%8lx", hr );
257 /*****************************************************************************
258 * Submit a DVB-T Tune Request
259 ******************************************************************************/
260 int BDAGraph::SubmitDVBTTuneRequest()
266 IDVBTuneRequest* p_dvbt_tune_request;
267 IDVBTLocator* p_dvbt_locator;
268 IDVBTuningSpace2* p_dvb_tuning_space;
269 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL),
270 p_dvb_tuning_space(NULL) {};
273 if( p_dvbt_tune_request )
274 p_dvbt_tune_request->Release();
276 p_dvbt_locator->Release();
277 if( p_dvb_tuning_space )
278 p_dvb_tuning_space->Release();
281 long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
282 long l_transmission, l_hierarchy;
283 BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
284 GuardInterval i_guard;
285 TransmissionMode i_transmission;
286 HierarchyAlpha i_hierarchy;
288 l_frequency = var_GetInteger( p_access, "dvb-frequency" ) / 1000;
289 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
290 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
291 l_lp_fec = var_GetInteger( p_access, "dvb-code-rate-lp" );
292 l_guard = var_GetInteger( p_access, "dvb-guard" );
293 l_transmission = var_GetInteger( p_access, "dvb-transmission" );
294 l_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
299 i_hp_fec = BDA_BCC_RATE_1_2; break;
301 i_hp_fec = BDA_BCC_RATE_2_3; break;
303 i_hp_fec = BDA_BCC_RATE_3_4; break;
305 i_hp_fec = BDA_BCC_RATE_5_6; break;
307 i_hp_fec = BDA_BCC_RATE_7_8;break;
309 i_hp_fec = BDA_BCC_RATE_NOT_SET;
315 i_lp_fec = BDA_BCC_RATE_1_2; break;
317 i_lp_fec = BDA_BCC_RATE_2_3; break;
319 i_lp_fec = BDA_BCC_RATE_3_4; break;
321 i_lp_fec = BDA_BCC_RATE_5_6; break;
323 i_lp_fec = BDA_BCC_RATE_7_8; break;
325 i_lp_fec = BDA_BCC_RATE_NOT_SET;
331 i_guard = BDA_GUARD_1_32; break;
333 i_guard = BDA_GUARD_1_16; break;
335 i_guard = BDA_GUARD_1_8; break;
337 i_guard = BDA_GUARD_1_4; break;
339 i_guard = BDA_GUARD_NOT_SET;
342 switch( l_transmission )
345 i_transmission = BDA_XMIT_MODE_2K; break;
347 i_transmission = BDA_XMIT_MODE_8K; break;
349 i_transmission = BDA_XMIT_MODE_NOT_SET;
352 switch( l_hierarchy )
355 i_hierarchy = BDA_HALPHA_1; break;
357 i_hierarchy = BDA_HALPHA_2; break;
359 i_hierarchy = BDA_HALPHA_4; break;
361 i_hierarchy = BDA_HALPHA_NOT_SET;
364 guid_network_type = CLSID_DVBTNetworkProvider;
365 hr = CreateTuneRequest();
368 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
369 "Cannot create Tune Request: hr=0x%8lx", hr );
373 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
374 (void**)&l.p_dvbt_tune_request );
377 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
378 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
381 l.p_dvbt_tune_request->put_ONID( -1 );
382 l.p_dvbt_tune_request->put_SID( -1 );
383 l.p_dvbt_tune_request->put_TSID( -1 );
385 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
386 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
389 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
390 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
393 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
394 (void**)&l.p_dvb_tuning_space );
397 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
398 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
403 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
405 if( SUCCEEDED( hr ) && l_frequency > 0 )
406 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
407 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
408 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
409 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
410 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
411 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
412 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
413 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
414 hr = l.p_dvbt_locator->put_Guard( i_guard );
415 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
416 hr = l.p_dvbt_locator->put_Mode( i_transmission );
417 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
418 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
421 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
422 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
426 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
429 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
430 "Cannot put the locator: hr=0x%8lx", hr );
434 /* Build and Run the Graph. If a Tuner device is in use the graph will
435 * fail to run. Repeated calls to build will check successive tuner
442 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
443 "Cannot Build the Graph: hr=0x%8lx", hr );
453 /*****************************************************************************
454 * Submit a DVB-C Tune Request
455 ******************************************************************************/
456 int BDAGraph::SubmitDVBCTuneRequest()
463 IDVBTuneRequest* p_dvbc_tune_request;
464 IDVBCLocator* p_dvbc_locator;
465 IDVBTuningSpace2* p_dvb_tuning_space;
467 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL),
468 p_dvb_tuning_space(NULL) {};
471 if( p_dvbc_tune_request )
472 p_dvbc_tune_request->Release();
474 p_dvbc_locator->Release();
475 if( p_dvb_tuning_space )
476 p_dvb_tuning_space->Release();
480 long l_frequency, l_symbolrate;
482 ModulationType i_qam_mod;
484 l_frequency = var_GetInteger( p_access, "dvb-frequency" ) / 1000;
485 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
486 i_qam = var_GetInteger( p_access, "dvb-modulation" );
491 i_qam_mod = BDA_MOD_16QAM; break;
493 i_qam_mod = BDA_MOD_32QAM; break;
495 i_qam_mod = BDA_MOD_64QAM; break;
497 i_qam_mod = BDA_MOD_128QAM; break;
499 i_qam_mod = BDA_MOD_256QAM; break;
501 i_qam_mod = BDA_MOD_NOT_SET;
504 guid_network_type = CLSID_DVBCNetworkProvider;
505 hr = CreateTuneRequest();
508 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
509 "Cannot create Tune Request: hr=0x%8lx", hr );
513 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
514 (void**)&l.p_dvbc_tune_request );
517 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
518 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
521 l.p_dvbc_tune_request->put_ONID( -1 );
522 l.p_dvbc_tune_request->put_SID( -1 );
523 l.p_dvbc_tune_request->put_TSID( -1 );
525 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
526 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
529 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
530 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
533 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
534 (void**)&l.p_dvb_tuning_space );
537 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
538 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
543 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
545 if( SUCCEEDED( hr ) && l_frequency > 0 )
546 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
547 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
548 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
549 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
550 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
554 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
555 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
559 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
562 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
563 "Cannot put the locator: hr=0x%8lx", hr );
567 /* Build and Run the Graph. If a Tuner device is in use the graph will
568 * fail to run. Repeated calls to build will check successive tuner
575 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
576 "Cannot Build the Graph: hr=0x%8lx", hr );
586 /*****************************************************************************
587 * Submit a DVB-S Tune Request
588 ******************************************************************************/
589 int BDAGraph::SubmitDVBSTuneRequest()
596 IDVBTuneRequest* p_dvbs_tune_request;
597 IDVBSLocator* p_dvbs_locator;
598 IDVBSTuningSpace* p_dvbs_tuning_space;
599 char* psz_polarisation;
600 char* psz_input_range;
601 BSTR bstr_input_range;
602 WCHAR* pwsz_input_range;
604 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
605 p_dvbs_tuning_space(NULL), bstr_input_range(NULL),
606 pwsz_input_range(NULL), i_range_len(0), psz_polarisation(NULL),
607 psz_input_range(NULL) {};
610 if( p_dvbs_tuning_space )
611 p_dvbs_tuning_space->Release();
612 if( p_dvbs_tune_request )
613 p_dvbs_tune_request->Release();
615 p_dvbs_locator->Release();
616 SysFreeString( bstr_input_range );
617 delete pwsz_input_range;
618 free( psz_input_range );
619 free( psz_polarisation );
622 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
623 long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
626 Polarisation i_polar;
627 SpectralInversion i_inversion;
629 BinaryConvolutionCodeRate i_hp_fec;
630 ModulationType i_mod_typ;
632 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
633 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
634 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
635 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
636 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
637 l_lnb_lof1 = var_GetInteger( p_access, "dvb-lnb-lof1" );
638 l_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
639 l_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
640 i_mod = var_GetInteger( p_access, "dvb-modulation" );
641 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
642 l_inversion = var_GetInteger( p_access, "dvb-inversion" );
643 l_network_id = var_GetInteger( p_access, "dvb-network-id" );
645 l.psz_input_range = var_GetNonEmptyString( p_access, "dvb-range" );
646 l.psz_polarisation = var_GetNonEmptyString( p_access, "dvb-polarisation" );
648 b_west = ( l_longitude < 0 );
650 i_polar = BDA_POLARISATION_NOT_SET;
651 if( l.psz_polarisation != NULL )
653 switch( toupper( l.psz_polarisation[0] ) )
656 i_polar = BDA_POLARISATION_LINEAR_H;
659 i_polar = BDA_POLARISATION_LINEAR_V;
662 i_polar = BDA_POLARISATION_CIRCULAR_L;
665 i_polar = BDA_POLARISATION_CIRCULAR_R;
670 switch( l_inversion )
673 i_inversion = BDA_SPECTRAL_INVERSION_NORMAL; break;
675 i_inversion = BDA_SPECTRAL_INVERSION_INVERTED; break;
677 i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC; break;
679 i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
685 i_mod_typ = BDA_MOD_16QAM; break;
687 i_mod_typ = BDA_MOD_128QAM; break;
689 i_mod_typ = BDA_MOD_256QAM; break;
691 i_mod_typ = BDA_MOD_QPSK; break;
693 i_mod_typ = BDA_MOD_NOT_SET;
699 i_hp_fec = BDA_BCC_RATE_1_2; break;
701 i_hp_fec = BDA_BCC_RATE_2_3; break;
703 i_hp_fec = BDA_BCC_RATE_3_4; break;
705 i_hp_fec = BDA_BCC_RATE_5_6; break;
707 i_hp_fec = BDA_BCC_RATE_7_8; break;
709 i_hp_fec = BDA_BCC_RATE_NOT_SET;
712 l.i_range_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
713 l.psz_input_range, -1, l.pwsz_input_range, 0 );
714 if( l.i_range_len > 0 )
716 l.pwsz_input_range = new WCHAR[l.i_range_len];
717 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
718 l.psz_input_range, -1, l.pwsz_input_range, l.i_range_len );
719 l.bstr_input_range=SysAllocString( l.pwsz_input_range );
722 guid_network_type = CLSID_DVBSNetworkProvider;
723 hr = CreateTuneRequest();
726 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
727 "Cannot create Tune Request: hr=0x%8lx", hr );
731 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
732 (void**)&l.p_dvbs_tune_request );
735 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
736 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
739 l.p_dvbs_tune_request->put_ONID( -1 );
740 l.p_dvbs_tune_request->put_SID( -1 );
741 l.p_dvbs_tune_request->put_TSID( -1 );
743 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
744 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
747 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
748 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
752 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
753 (void**)&l.p_dvbs_tuning_space );
756 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
757 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
762 hr = l.p_dvbs_tuning_space->put_SystemType( DVB_Satellite );
763 if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
764 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
765 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
766 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
767 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
768 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
769 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
770 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
771 if( SUCCEEDED( hr ) && l_network_id > 0 )
772 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
773 if( SUCCEEDED( hr ) && l.i_range_len > 0 )
774 hr = l.p_dvbs_tuning_space->put_InputRange( l.bstr_input_range );
776 if( SUCCEEDED( hr ) && l_frequency > 0 )
777 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
778 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
779 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
780 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
781 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
782 if( SUCCEEDED( hr ) && i_mod_typ != BDA_MOD_NOT_SET )
783 hr = l.p_dvbs_locator->put_Modulation( i_mod_typ );
784 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
785 hr = l.p_dvbs_locator->put_InnerFECRate( i_hp_fec );
787 if( SUCCEEDED( hr ) && l_azimuth > 0 )
788 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
789 if( SUCCEEDED( hr ) && l_elevation > 0 )
790 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
791 if( SUCCEEDED( hr ) )
792 hr = l.p_dvbs_locator->put_WestPosition( b_west );
793 if( SUCCEEDED( hr ) )
794 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
797 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
798 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
802 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
805 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
806 "Cannot put the locator: hr=0x%8lx", hr );
810 /* Build and Run the Graph. If a Tuner device is in use the graph will
811 * fail to run. Repeated calls to build will check successive tuner
818 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
819 "Cannot Build the Graph: hr=0x%8lx", hr );
829 /*****************************************************************************
830 * Load the Tuning Space from System Tuning Spaces according to the
831 * Network Type requested
832 ******************************************************************************/
833 HRESULT BDAGraph::CreateTuneRequest()
836 GUID guid_this_network_type;
840 ITuningSpaceContainer* p_tuning_space_container;
841 IEnumTuningSpaces* p_tuning_space_enum;
842 ITuningSpace* p_this_tuning_space;
843 IDVBTuningSpace2* p_dvb_tuning_space;
845 char * psz_network_name;
846 char * psz_create_name;
847 char * psz_bstr_name;
848 WCHAR * wpsz_create_name;
850 localComPtr(): p_tuning_space_container(NULL),
851 p_tuning_space_enum(NULL), p_this_tuning_space(NULL),
852 p_dvb_tuning_space(NULL),
853 i_name_len(0), psz_network_name(NULL), wpsz_create_name(NULL),
854 psz_create_name(NULL), bstr_name(NULL), psz_bstr_name(NULL) {};
857 if( p_tuning_space_enum )
858 p_tuning_space_enum->Release();
859 if( p_tuning_space_container )
860 p_tuning_space_container->Release();
861 if( p_this_tuning_space )
862 p_this_tuning_space->Release();
863 if( p_dvb_tuning_space )
864 p_dvb_tuning_space->Release();
865 SysFreeString( bstr_name );
866 delete[] psz_bstr_name;
867 delete[] wpsz_create_name;
868 free( psz_network_name );
869 free( psz_create_name );
873 /* We shall test for a specific Tuning space name supplied on the command
874 * line as dvb-networkname=xxx.
875 * For some users with multiple cards and/or multiple networks this could
876 * be useful. This allows us to reasonably safely apply updates to the
877 * System Tuning Space in the registry without disrupting other streams. */
878 l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-network-name" );
879 if( l.psz_network_name )
881 msg_Dbg( p_access, "CreateTuneRequest: Find Tuning Space: %s",
882 l.psz_network_name );
886 l.psz_network_name = new char[1];
887 *l.psz_network_name = '\0';
890 /* A Tuning Space may already have been set up. If it is for the same
891 * network type then all is well. Otherwise, reset the Tuning Space and get
895 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
896 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
897 if( guid_this_network_type == guid_network_type )
899 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
902 msg_Warn( p_access, "CreateTuneRequest: "\
903 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
906 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
907 l.psz_bstr_name, 0, NULL, NULL );
908 l.psz_bstr_name = new char[ l.i_name_len ];
909 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
910 l.psz_bstr_name, l.i_name_len, NULL, NULL );
912 /* Test for a specific Tuning space name supplied on the command
913 * line as dvb-networkname=xxx */
914 if( *l.psz_network_name == '\0' ||
915 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
917 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
918 l.psz_network_name );
922 /* else different guid_network_type */
924 p_tuning_space->Release();
926 p_tune_request->Release();
927 p_tuning_space = NULL;
928 p_tune_request = NULL;
931 /* Force use of the first available Tuner Device during Build */
934 /* Get the SystemTuningSpaces container to enumerate through all the
935 * defined tuning spaces.
936 * l.p_tuning_space_container->Refcount = 1 */
937 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
938 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
941 msg_Warn( p_access, "CreateTuneRequest: "\
942 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
946 /* Get the SystemTuningSpaces container to enumerate through all the
947 * defined tuning spaces.
948 * l.p_tuning_space_container->Refcount = 2
949 * l.p_tuning_space_enum->Refcount = 1 */
950 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
951 &l.p_tuning_space_enum );
954 msg_Warn( p_access, "CreateTuneRequest: "\
955 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
961 /* l.p_this_tuning_space->RefCount = 1 after the first pass
962 * Release before overwriting with Next */
963 if( l.p_this_tuning_space )
964 l.p_this_tuning_space->Release();
965 l.p_this_tuning_space = NULL;
966 SysFreeString( l.bstr_name );
968 hr = l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL );
969 if( hr != S_OK ) break;
971 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
973 /* GUID_NULL means a non-BDA network was found e.g analog
974 * Ignore failures and non-BDA networks and keep looking */
975 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
977 if( guid_this_network_type == guid_network_type )
979 /* QueryInterface to clone l.p_this_tuning_space
980 * l.p_this_tuning_space->RefCount = 2 */
981 hr = l.p_this_tuning_space->Clone( &p_tuning_space );
984 msg_Warn( p_access, "CreateTuneRequest: "\
985 "Cannot QI Tuning Space: hr=0x%8lx", hr );
988 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
991 msg_Warn( p_access, "CreateTuneRequest: "\
992 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
996 /* Test for a specific Tuning space name supplied on the command
997 * line as dvb-networkname=xxx */
998 delete[] l.psz_bstr_name;
999 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1000 l.psz_bstr_name, 0, NULL, NULL );
1001 l.psz_bstr_name = new char[ l.i_name_len ];
1002 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1003 l.psz_bstr_name, l.i_name_len, NULL, NULL );
1004 if( *l.psz_network_name == '\0' ||
1005 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
1007 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
1010 /* CreateTuneRequest adds TuneRequest to p_tuning_space
1011 * p_tune_request->RefCount = 1 */
1012 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
1014 msg_Warn( p_access, "CreateTuneRequest: "\
1015 "Cannot Create Tune Request: hr=0x%8lx", hr );
1018 if( p_tuning_space )
1019 p_tuning_space->Release();
1020 p_tuning_space = NULL;
1025 /* No tuning space was found. If the create-name parameter was set then
1026 * create a tuning space. By rights should use the same name used in
1028 * Also would be nice to copy a tuning space but we only come here if we do
1030 l.psz_create_name = var_GetNonEmptyString( p_access, "dvb-create-name" );
1031 if( !l.psz_create_name || strlen( l.psz_create_name ) <= 0 )
1034 msg_Warn( p_access, "CreateTuneRequest: "\
1035 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
1038 if( strcmp( l.psz_create_name, l.psz_network_name ) )
1041 msg_Warn( p_access, "CreateTuneRequest: "\
1042 "dvb-create-name %s must match dvb-network-name %s",
1043 l.psz_create_name, l.psz_network_name );
1047 /* Need to use DVBSTuningSpace for DVB-S and ATSCTuningSpace for ATSC */
1049 CLSID cls_tuning_space;
1051 if( IsEqualCLSID( guid_network_type, CLSID_ATSCNetworkProvider ) )
1052 cls_tuning_space = CLSID_ATSCTuningSpace;
1053 if( IsEqualCLSID( guid_network_type, CLSID_DVBTNetworkProvider ) )
1054 cls_tuning_space = CLSID_DVBTuningSpace;
1055 if( IsEqualCLSID( guid_network_type, CLSID_DVBCNetworkProvider ) )
1056 cls_tuning_space = CLSID_DVBTuningSpace;
1057 if( IsEqualCLSID( guid_network_type, CLSID_DVBSNetworkProvider ) )
1058 cls_tuning_space = CLSID_DVBSTuningSpace;
1060 l.i_name_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
1061 l.psz_create_name, -1, l.wpsz_create_name, 0 );
1062 if( l.i_name_len <= 0 )
1065 msg_Warn( p_access, "CreateTuneRequest: "\
1066 "Cannot convert zero length dvb-create-name %s",
1067 l.psz_create_name );
1070 l.wpsz_create_name = new WCHAR[l.i_name_len];
1071 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, l.psz_create_name, -1,
1072 l.wpsz_create_name, l.i_name_len );
1074 SysFreeString( l.bstr_name );
1075 l.bstr_name = SysAllocString( l.wpsz_create_name );
1077 msg_Dbg( p_access, "CreateTuneRequest: Create Tuning Space: %s",
1078 l.psz_create_name );
1080 hr = ::CoCreateInstance( cls_tuning_space, 0, CLSCTX_INPROC,
1081 IID_ITuningSpace, (void**)&p_tuning_space );
1084 msg_Warn( p_access, "CreateTuneRequest: "\
1085 "Cannot CoCreate new TuningSpace: hr=0x%8lx", hr );
1086 if( SUCCEEDED( hr ) )
1087 hr = p_tuning_space->put__NetworkType( guid_network_type );
1089 msg_Warn( p_access, "CreateTuneRequest: "\
1090 "Cannot Put Network Type: hr=0x%8lx", hr );
1091 if( SUCCEEDED( hr ) )
1092 hr = p_tuning_space->put_UniqueName( l.bstr_name );
1094 msg_Warn( p_access, "CreateTuneRequest: "\
1095 "Cannot Put Unique Name: hr=0x%8lx", hr );
1096 if( SUCCEEDED( hr ) )
1097 hr = p_tuning_space->put_FriendlyName( l.bstr_name );
1099 msg_Warn( p_access, "CreateTuneRequest: "\
1100 "Cannot Put Friendly Name: hr=0x%8lx", hr );
1101 if( guid_network_type == CLSID_DVBTNetworkProvider ||
1102 guid_network_type == CLSID_DVBCNetworkProvider ||
1103 guid_network_type == CLSID_DVBSNetworkProvider )
1105 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
1106 (void**)&l.p_dvb_tuning_space );
1109 msg_Warn( p_access, "CreateTuneRequest: "\
1110 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
1113 if( guid_network_type == CLSID_DVBTNetworkProvider )
1114 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
1115 if( guid_network_type == CLSID_DVBCNetworkProvider )
1116 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
1117 if( guid_network_type == CLSID_DVBSNetworkProvider )
1118 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Satellite );
1121 if( SUCCEEDED( hr ) )
1122 hr = l.p_tuning_space_container->Add( p_tuning_space, &var_id );
1126 msg_Warn( p_access, "CreateTuneRequest: "\
1127 "Cannot Create new TuningSpace: hr=0x%8lx", hr );
1131 msg_Dbg( p_access, "CreateTuneRequest: Tuning Space: %s created",
1132 l.psz_create_name );
1134 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
1136 msg_Warn( p_access, "CreateTuneRequest: "\
1137 "Cannot Create Tune Request: hr=0x%8lx", hr );
1142 /******************************************************************************
1144 * Step 4: Build the Filter Graph
1145 * Build sets up devices, adds and connects filters
1146 ******************************************************************************/
1147 HRESULT BDAGraph::Build()
1150 long l_capture_used, l_tif_used;
1151 VARIANT l_tuning_space_id;
1152 AM_MEDIA_TYPE grabber_media_type;
1156 ITuningSpaceContainer* p_tuning_space_container;
1157 localComPtr(): p_tuning_space_container(NULL) {};
1160 if( p_tuning_space_container )
1161 p_tuning_space_container->Release();
1165 /* Get the SystemTuningSpaces container to save the Tuning space */
1166 l_tuning_space_id.vt = VT_I4;
1167 l_tuning_space_id.lVal = 0L;
1168 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
1169 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
1172 msg_Warn( p_access, "Build: "\
1173 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
1176 hr = l.p_tuning_space_container->FindID( p_tuning_space,
1177 &l_tuning_space_id.lVal );
1180 msg_Warn( p_access, "Build: "\
1181 "Cannot Find Tuning Space ID: hr=0x%8lx", hr );
1184 msg_Dbg( p_access, "Build: Using Tuning Space ID %d",
1185 l_tuning_space_id.lVal );
1186 hr = l.p_tuning_space_container->put_Item( l_tuning_space_id,
1190 msg_Warn( p_access, "Build: "\
1191 "Cannot save Tuning Space: hr=0x%8lx (ignored)", hr );
1194 /* If we have already have a filter graph, rebuild it*/
1197 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1198 IID_IGraphBuilder, (void**)&p_filter_graph );
1201 msg_Warn( p_access, "Build: "\
1202 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
1206 /* First filter in the graph is the Network Provider and
1207 * its Scanning Tuner which takes the Tune Request
1208 * Try to build the Win 7 Universal Network Provider first*/
1209 hr = ::CoCreateInstance( CLSID_NetworkProvider, NULL, CLSCTX_INPROC_SERVER,
1210 IID_IBaseFilter, (void**)&p_network_provider);
1213 msg_Warn( p_access, "Build: "\
1214 "Cannot CoCreate the Universal Network Provider, trying the old way...");
1215 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
1216 IID_IBaseFilter, (void**)&p_network_provider);
1219 msg_Warn( p_access, "Build: "\
1220 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
1224 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
1227 msg_Warn( p_access, "Build: "\
1228 "Cannot load network provider: hr=0x%8lx", hr );
1232 /* Add the Network Tuner to the Network Provider. On subsequent calls,
1233 * l_tuner_used will cause a different tuner to be selected
1234 * To select a specific device first get the parameter that nominates the
1235 * device (dvb-adapter) and use the value to initialise l_tuner_used.
1236 * When FindFilter returns check the contents of l_tuner_used.
1237 * If it is not what was selected then the requested device was not
1238 * available so return with an error. */
1240 long l_adapter = -1;
1241 l_adapter = var_GetInteger( p_access, "dvb-adapter" );
1242 if( l_tuner_used < 0 && l_adapter >= 0 )
1243 l_tuner_used = l_adapter - 1;
1245 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
1246 p_network_provider, &p_tuner_device );
1249 msg_Warn( p_access, "Build: "\
1250 "Cannot load tuner device and connect network provider: "\
1254 if( l_adapter > 0 && l_tuner_used != l_adapter )
1256 msg_Warn( p_access, "Build: "\
1257 "Tuner device %d is not available", l_adapter );
1260 msg_Dbg( p_access, "BDAGraph: Using adapter %d", l_tuner_used );
1262 /* VLC 1.0 works reliably up this point then crashes
1263 * Obvious candidate is FindFilter */
1264 /* Always look for all capture devices to match the Network Tuner */
1265 l_capture_used = -1;
1266 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
1267 p_tuner_device, &p_capture_device );
1270 /* Some BDA drivers do not provide a Capture Device Filter so force
1271 * the Sample Grabber to connect directly to the Tuner Device */
1272 p_capture_device = p_tuner_device;
1273 p_tuner_device = NULL;
1274 msg_Warn( p_access, "Build: "\
1275 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
1278 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
1279 (void**)&p_scanning_tuner );
1282 msg_Warn( p_access, "Build: "\
1283 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
1287 hr = p_scanning_tuner->Validate( p_tune_request );
1290 msg_Warn( p_access, "Build: "\
1291 "Tune Request is invalid: hr=0x%8lx", hr );
1292 //return hr; it is not mandatory to validate. Validate fails, but the request is successfully accepted
1294 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
1297 msg_Warn( p_access, "Build: "\
1298 "Cannot submit the tune request: hr=0x%8lx", hr );
1302 if( p_sample_grabber )
1303 p_sample_grabber->Release();
1304 p_sample_grabber = NULL;
1305 /* Insert the Sample Grabber to tap into the Transport Stream. */
1306 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
1307 IID_IBaseFilter, (void**)&p_sample_grabber );
1310 msg_Warn( p_access, "Build: "\
1311 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
1314 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
1317 msg_Warn( p_access, "Build: "\
1318 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
1323 p_grabber->Release();
1325 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
1326 (void**)&p_grabber );
1329 msg_Warn( p_access, "Build: "\
1330 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
1334 /* Try the possible stream type */
1336 for( int i = 0; i < 2; i++ )
1338 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
1339 grabber_media_type.majortype = MEDIATYPE_Stream;
1340 grabber_media_type.subtype = i == 0 ? MEDIASUBTYPE_MPEG2_TRANSPORT : KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT;
1341 msg_Dbg( p_access, "Build: "
1342 "Trying connecting with subtype %s",
1343 i == 0 ? "MEDIASUBTYPE_MPEG2_TRANSPORT" : "KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT" );
1344 hr = p_grabber->SetMediaType( &grabber_media_type );
1345 if( SUCCEEDED( hr ) )
1347 hr = Connect( p_capture_device, p_sample_grabber );
1348 if( SUCCEEDED( hr ) )
1350 msg_Warn( p_access, "Build: "\
1351 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr, 1+i );
1355 msg_Warn( p_access, "Build: "\
1356 "Cannot set media type on grabber filter: hr=0x%8lx (try %d/2", hr, 1+i );
1362 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
1363 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
1364 * the Network Provider filter to set up the stream */
1365 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
1366 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
1369 msg_Warn( p_access, "Build: "\
1370 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
1373 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
1376 msg_Warn( p_access, "Build: "\
1377 "Cannot add demux filter to graph: hr=0x%8lx", hr );
1380 hr = Connect( p_sample_grabber, p_mpeg_demux );
1383 msg_Warn( p_access, "Build: "\
1384 "Cannot connect demux to grabber: hr=0x%8lx", hr );
1388 /* Always look for the Transform Information Filter from the start
1389 * of the collection*/
1391 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
1392 p_mpeg_demux, &p_transport_info );
1395 msg_Warn( p_access, "Build: "\
1396 "Cannot load TIF onto demux: hr=0x%8lx", hr );
1399 /* Configure the Sample Grabber to buffer the samples continuously */
1400 hr = p_grabber->SetBufferSamples( true );
1403 msg_Warn( p_access, "Build: "\
1404 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
1407 hr = p_grabber->SetOneShot( false );
1410 msg_Warn( p_access, "Build: "\
1411 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
1414 hr = p_grabber->SetCallback( this, 0 );
1417 msg_Warn( p_access, "Build: "\
1418 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
1425 d_graph_register = 0;
1428 /* The Media Control is used to Run and Stop the Graph */
1429 if( p_media_control )
1430 p_media_control->Release();
1431 p_media_control = NULL;
1432 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
1433 (void**)&p_media_control );
1436 msg_Warn( p_access, "Build: "\
1437 "Cannot QI Media Control: hr=0x%8lx", hr );
1445 /******************************************************************************
1447 * Looks up all filters in a category and connects to the upstream filter until
1448 * a successful match is found. The index of the connected filter is returned.
1449 * On subsequent calls, this can be used to start from that point to find
1451 * This is used when the graph does not run because a tuner device is in use so
1452 * another one needs to be selected.
1453 ******************************************************************************/
1454 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
1455 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
1458 int i_moniker_index = -1;
1462 IMoniker* p_moniker;
1463 IEnumMoniker* p_moniker_enum;
1464 IBaseFilter* p_filter;
1465 IPropertyBag* p_property_bag;
1471 p_moniker_enum(NULL),
1473 p_property_bag(NULL),
1475 { ::VariantInit(&var_bstr); };
1478 if( p_property_bag )
1479 p_property_bag->Release();
1481 p_filter->Release();
1483 p_moniker->Release();
1484 if( p_moniker_enum )
1485 p_moniker_enum->Release();
1486 ::VariantClear(&var_bstr);
1491 if( !p_system_dev_enum )
1493 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1494 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1497 msg_Warn( p_access, "FindFilter: "\
1498 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1503 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1504 &l.p_moniker_enum, 0 );
1507 msg_Warn( p_access, "FindFilter: "\
1508 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1514 /* We are overwriting l.p_moniker so we should Release and nullify
1515 * It is important that p_moniker and p_property_bag are fully released
1516 * l.p_filter may not be dereferenced so we could force to NULL */
1517 if( l.p_property_bag )
1518 l.p_property_bag->Release();
1519 l.p_property_bag = NULL;
1521 l.p_filter->Release();
1524 l.p_moniker->Release();
1527 hr = l.p_moniker_enum->Next( 1, &l.p_moniker, 0 );
1528 if( hr != S_OK ) break;
1531 /* Skip over devices already found on previous calls */
1532 if( i_moniker_index <= *i_moniker_used ) continue;
1533 *i_moniker_used = i_moniker_index;
1535 /* l.p_filter is Released at the top of the loop */
1536 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1537 (void**)&l.p_filter );
1542 /* l.p_property_bag is released at the top of the loop */
1543 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1544 (void**)&l.p_property_bag );
1547 msg_Warn( p_access, "FindFilter: "\
1548 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1551 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1554 msg_Warn( p_access, "FindFilter: "\
1555 "Cannot read filter friendly name: hr=0x%8lx", hr );
1559 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1562 msg_Warn( p_access, "FindFilter: "\
1563 "Cannot add filter: hr=0x%8lx", hr );
1566 hr = Connect( p_upstream, l.p_filter );
1567 if( SUCCEEDED( hr ) )
1569 /* p_p_downstream has not been touched yet so no release needed */
1570 delete[] l.psz_bstr;
1571 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1572 l.var_bstr.bstrVal, -1, l.psz_bstr, 0, NULL, NULL );
1573 l.psz_bstr = new char[l.i_bstr_len];
1574 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1575 l.var_bstr.bstrVal, -1, l.psz_bstr, l.i_bstr_len, NULL, NULL );
1576 msg_Dbg( p_access, "FindFilter: Connected %s", l.psz_bstr );
1577 l.p_filter->QueryInterface( IID_IBaseFilter,
1578 (void**)p_p_downstream );
1581 /* Not the filter we want so unload and try the next one */
1582 hr = p_filter_graph->RemoveFilter( l.p_filter );
1585 msg_Warn( p_access, "FindFilter: "\
1586 "Failed unloading Filter: hr=0x%8lx", hr );
1594 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1598 /*****************************************************************************
1599 * Connect is called from Build to enumerate and connect pins
1600 *****************************************************************************/
1601 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1603 HRESULT hr = E_FAIL;
1607 IPin* p_pin_upstream;
1608 IPin* p_pin_downstream;
1609 IEnumPins* p_pin_upstream_enum;
1610 IEnumPins* p_pin_downstream_enum;
1612 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1613 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1614 p_pin_temp(NULL) { };
1618 p_pin_temp->Release();
1619 if( p_pin_downstream )
1620 p_pin_downstream->Release();
1621 if( p_pin_upstream )
1622 p_pin_upstream->Release();
1623 if( p_pin_downstream_enum )
1624 p_pin_downstream_enum->Release();
1625 if( p_pin_upstream_enum )
1626 p_pin_upstream_enum->Release();
1630 PIN_DIRECTION pin_dir;
1632 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1635 msg_Warn( p_access, "Connect: "\
1636 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1642 /* Release l.p_pin_upstream before next iteration */
1643 if( l.p_pin_upstream )
1644 l.p_pin_upstream ->Release();
1645 l.p_pin_upstream = NULL;
1646 hr = l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 );
1647 if( hr != S_OK ) break;
1649 hr = l.p_pin_upstream->QueryDirection( &pin_dir );
1652 msg_Warn( p_access, "Connect: "\
1653 "Cannot get upstream filter pin direction: hr=0x%8lx", hr );
1656 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1657 if( SUCCEEDED( hr ) )
1659 l.p_pin_downstream->Release();
1660 l.p_pin_downstream = NULL;
1662 if( FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1664 msg_Warn( p_access, "Connect: "\
1665 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1668 if( ( pin_dir == PINDIR_OUTPUT ) && ( hr == VFW_E_NOT_CONNECTED ) )
1670 /* The upstream pin is not yet connected so check each pin on the
1671 * downstream filter */
1672 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1675 msg_Warn( p_access, "Connect: Cannot get "\
1676 "downstream filter enumerator: hr=0x%8lx", hr );
1681 /* Release l.p_pin_downstream before next iteration */
1682 if( l.p_pin_downstream )
1683 l.p_pin_downstream ->Release();
1684 l.p_pin_downstream = NULL;
1686 hr = l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 );
1687 if( hr != S_OK ) break;
1689 hr = l.p_pin_downstream->QueryDirection( &pin_dir );
1692 msg_Warn( p_access, "Connect: Cannot get "\
1693 "downstream filter pin direction: hr=0x%8lx", hr );
1697 /* Looking for a free Pin to connect to
1698 * A connected Pin may have an reference count > 1
1699 * so Release and nullify the pointer */
1700 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1701 if( SUCCEEDED( hr ) )
1703 l.p_pin_temp->Release();
1704 l.p_pin_temp = NULL;
1706 if( hr != VFW_E_NOT_CONNECTED )
1710 msg_Warn( p_access, "Connect: Cannot check "\
1711 "downstream filter connection: hr=0x%8lx", hr );
1715 if( ( pin_dir == PINDIR_INPUT ) &&
1716 ( hr == VFW_E_NOT_CONNECTED ) )
1718 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1719 l.p_pin_downstream, NULL );
1720 if( SUCCEEDED( hr ) )
1722 /* If we arrive here then we have a matching pair of
1727 /* If we arrive here it means this downstream pin is not
1728 * suitable so try the next downstream pin.
1729 * l.p_pin_downstream is released at the top of the loop */
1732 /* If we arrive here then we ran out of pins before we found a
1733 * suitable one. Release outstanding refcounts */
1734 if( l.p_pin_downstream_enum )
1735 l.p_pin_downstream_enum->Release();
1736 l.p_pin_downstream_enum = NULL;
1737 if( l.p_pin_downstream )
1738 l.p_pin_downstream->Release();
1739 l.p_pin_downstream = NULL;
1741 /* If we arrive here it means this upstream pin is not suitable
1742 * so try the next upstream pin
1743 * l.p_pin_upstream is released at the top of the loop */
1746 /* If we arrive here it means we did not find any pair of suitable pins
1747 * Outstanding refcounts are released in the destructor */
1751 /*****************************************************************************
1752 * Start uses MediaControl to start the graph
1753 *****************************************************************************/
1754 HRESULT BDAGraph::Start()
1757 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1759 if( !p_media_control )
1761 msg_Dbg( p_access, "Start: Media Control has not been created" );
1764 hr = p_media_control->Run();
1765 msg_Dbg( p_access, "Graph started hr=0x%lx", hr );
1769 /* Query the state of the graph - timeout after 100 milliseconds */
1770 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1775 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1779 if( i_state == State_Running )
1782 /* The Graph is not running so stop it and return an error */
1783 msg_Warn( p_access, "Start: Graph not started: %d", i_state );
1784 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
1788 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1794 /*****************************************************************************
1795 * Pop the stream of data
1796 *****************************************************************************/
1797 block_t *BDAGraph::Pop()
1799 return output.Pop();
1802 /******************************************************************************
1803 * SampleCB - Callback when the Sample Grabber has a sample
1804 ******************************************************************************/
1805 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1807 if( p_sample->IsDiscontinuity() == S_OK )
1808 msg_Warn( p_access, "BDA SampleCB: Sample Discontinuity.");
1810 const size_t i_sample_size = p_sample->GetActualDataLength();
1811 BYTE *p_sample_data;
1812 p_sample->GetPointer( &p_sample_data );
1814 if( i_sample_size > 0 && p_sample_data )
1816 block_t *p_block = block_New( p_access, i_sample_size );
1820 memcpy( p_block->p_buffer, p_sample_data, i_sample_size );
1821 output.Push( p_block );
1827 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1833 /******************************************************************************
1834 * removes each filter from the graph
1835 ******************************************************************************/
1836 HRESULT BDAGraph::Destroy()
1839 ULONG ul_refcount = 0;
1841 if( p_media_control )
1842 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
1844 if( d_graph_register )
1853 p_grabber->Release();
1857 if( p_transport_info )
1859 p_filter_graph->RemoveFilter( p_transport_info );
1860 p_transport_info->Release();
1861 p_transport_info = NULL;
1865 p_filter_graph->RemoveFilter( p_mpeg_demux );
1866 p_mpeg_demux->Release();
1867 p_mpeg_demux = NULL;
1869 if( p_sample_grabber )
1871 p_filter_graph->RemoveFilter( p_sample_grabber );
1872 p_sample_grabber->Release();
1873 p_sample_grabber = NULL;
1875 if( p_capture_device )
1877 p_filter_graph->RemoveFilter( p_capture_device );
1878 p_capture_device->Release();
1879 p_capture_device = NULL;
1881 if( p_tuner_device )
1883 p_filter_graph->RemoveFilter( p_tuner_device );
1884 p_tuner_device->Release();
1885 p_tuner_device = NULL;
1887 if( p_scanning_tuner )
1889 p_scanning_tuner->Release();
1890 p_scanning_tuner = NULL;
1892 if( p_network_provider )
1894 p_filter_graph->RemoveFilter( p_network_provider );
1895 p_network_provider->Release();
1896 p_network_provider = NULL;
1899 if( p_media_control )
1901 p_media_control->Release();
1902 p_media_control = NULL;
1904 if( p_filter_graph )
1906 p_filter_graph->Release();
1907 p_filter_graph = NULL;
1909 if( p_system_dev_enum )
1911 p_system_dev_enum->Release();
1912 p_system_dev_enum = NULL;
1918 /*****************************************************************************
1919 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1920 * Allows GraphEdit to "spy" on a remote filter graph.
1921 ******************************************************************************/
1922 HRESULT BDAGraph::Register()
1927 IMoniker* p_moniker;
1928 IRunningObjectTable* p_ro_table;
1929 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1933 p_moniker->Release();
1935 p_ro_table->Release();
1938 WCHAR psz_w_graph_name[128];
1941 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1944 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1948 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1949 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1950 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1953 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1956 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1957 p_filter_graph, l.p_moniker, &d_graph_register );
1960 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1963 // msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1967 void BDAGraph::Deregister()
1970 IRunningObjectTable* p_ro_table;
1971 hr = ::GetRunningObjectTable( 0, &p_ro_table );
1972 if( SUCCEEDED( hr ) )
1973 p_ro_table->Revoke( d_graph_register );
1974 d_graph_register = 0;
1975 p_ro_table->Release();