1 /*****************************************************************************
2 * bdagraph.cpp : DirectShow BDA graph for vlc
3 *****************************************************************************
4 * Copyright( C ) 2007 the VideoLAN team
6 * Author: Ken Self <kens@campoz.fslife.co.uk>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 *( at your option ) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
29 /****************************************************************************
30 * Interfaces for calls from C
31 ****************************************************************************/
34 void dvb_newBDAGraph( access_t* p_access )
36 p_access->p_sys->p_bda_module = new BDAGraph( p_access );
39 void dvb_deleteBDAGraph( access_t* p_access )
41 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 = l_minor_channel = l_physical_channel = -1;
147 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
148 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
149 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
150 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
152 guid_network_type = CLSID_ATSCNetworkProvider;
153 hr = CreateTuneRequest();
156 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
157 "Cannot create Tuning Space: hr=0x%8lx", hr );
161 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
162 (void**)&l.p_atsc_tune_request );
165 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
166 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
169 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
170 IID_IATSCLocator, (void**)&l.p_atsc_locator );
173 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
174 "Cannot create the ATSC locator: hr=0x%8lx", hr );
179 if( l_frequency > 0 )
180 hr = l.p_atsc_locator->put_CarrierFrequency( l_frequency );
181 if( l_major_channel > 0 )
182 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
183 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
184 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
185 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
186 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
189 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
190 "Cannot set tuning parameters: hr=0x%8lx", hr );
194 hr = p_tune_request->put_Locator( l.p_atsc_locator );
197 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
198 "Cannot put the locator: hr=0x%8lx", hr );
202 /* Build and Run the Graph. If a Tuner device is in use the graph will
203 * fail to run. Repeated calls to build will check successive tuner
210 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
211 "Cannot Build the Graph: hr=0x%8lx", hr );
221 /*****************************************************************************
222 * Submit a DVB-T Tune Request
223 ******************************************************************************/
224 int BDAGraph::SubmitDVBTTuneRequest()
230 IDVBTuneRequest* p_dvbt_tune_request;
231 IDVBTLocator* p_dvbt_locator;
232 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
235 if( p_dvbt_tune_request )
236 p_dvbt_tune_request->Release();
238 p_dvbt_locator->Release();
241 long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
242 long l_transmission, l_hierarchy;
243 BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
244 GuardInterval i_guard;
245 TransmissionMode i_transmission;
246 HierarchyAlpha i_hierarchy;
248 l_frequency = l_bandwidth = l_hp_fec = l_lp_fec = l_guard = -1;
249 l_transmission = l_hierarchy = -1;
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" );
258 i_hp_fec = BDA_BCC_RATE_NOT_SET;
260 i_hp_fec = BDA_BCC_RATE_1_2;
262 i_hp_fec = BDA_BCC_RATE_2_3;
264 i_hp_fec = BDA_BCC_RATE_3_4;
266 i_hp_fec = BDA_BCC_RATE_5_6;
268 i_hp_fec = BDA_BCC_RATE_7_8;
270 i_lp_fec = BDA_BCC_RATE_NOT_SET;
272 i_lp_fec = BDA_BCC_RATE_1_2;
274 i_lp_fec = BDA_BCC_RATE_2_3;
276 i_lp_fec = BDA_BCC_RATE_3_4;
278 i_lp_fec = BDA_BCC_RATE_5_6;
280 i_lp_fec = BDA_BCC_RATE_7_8;
282 i_guard = BDA_GUARD_NOT_SET;
284 i_guard = BDA_GUARD_1_32;
286 i_guard = BDA_GUARD_1_16;
288 i_guard = BDA_GUARD_1_8;
290 i_guard = BDA_GUARD_1_4;
292 i_transmission = BDA_XMIT_MODE_NOT_SET;
293 if( l_transmission == 2 )
294 i_transmission = BDA_XMIT_MODE_2K;
295 if( l_transmission == 8 )
296 i_transmission = BDA_XMIT_MODE_8K;
298 i_hierarchy = BDA_HALPHA_NOT_SET;
299 if( l_hierarchy == 1 )
300 i_hierarchy = BDA_HALPHA_1;
301 if( l_hierarchy == 2 )
302 i_hierarchy = BDA_HALPHA_2;
303 if( l_hierarchy == 4 )
304 i_hierarchy = BDA_HALPHA_4;
306 guid_network_type = CLSID_DVBTNetworkProvider;
307 hr = CreateTuneRequest();
310 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
311 "Cannot create Tune Request: hr=0x%8lx", hr );
315 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
316 (void**)&l.p_dvbt_tune_request );
319 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
320 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
323 l.p_dvbt_tune_request->put_ONID( -1 );
324 l.p_dvbt_tune_request->put_SID( -1 );
325 l.p_dvbt_tune_request->put_TSID( -1 );
327 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
328 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
331 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
332 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
337 if( l_frequency > 0 )
338 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
339 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
340 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
341 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
342 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
343 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
344 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
345 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
346 hr = l.p_dvbt_locator->put_Guard( i_guard );
347 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
348 hr = l.p_dvbt_locator->put_Mode( i_transmission );
349 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
350 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
353 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
354 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
358 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
361 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
362 "Cannot put the locator: hr=0x%8lx", hr );
366 /* Build and Run the Graph. If a Tuner device is in use the graph will
367 * fail to run. Repeated calls to build will check successive tuner
374 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
375 "Cannot Build the Graph: hr=0x%8lx", hr );
385 /*****************************************************************************
386 * Submit a DVB-C Tune Request
387 ******************************************************************************/
388 int BDAGraph::SubmitDVBCTuneRequest()
395 IDVBTuneRequest* p_dvbc_tune_request;
396 IDVBCLocator* p_dvbc_locator;
397 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
400 if( p_dvbc_tune_request )
401 p_dvbc_tune_request->Release();
403 p_dvbc_locator->Release();
407 long l_frequency, l_symbolrate;
409 ModulationType i_qam_mod;
411 l_frequency = l_symbolrate = i_qam = -1;
412 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
413 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
414 i_qam = var_GetInteger( p_access, "dvb-modulation" );
415 i_qam_mod = BDA_MOD_NOT_SET;
417 i_qam_mod = BDA_MOD_16QAM;
419 i_qam_mod = BDA_MOD_32QAM;
421 i_qam_mod = BDA_MOD_64QAM;
423 i_qam_mod = BDA_MOD_128QAM;
425 i_qam_mod = BDA_MOD_256QAM;
427 guid_network_type = CLSID_DVBCNetworkProvider;
428 hr = CreateTuneRequest();
431 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
432 "Cannot create Tune Request: hr=0x%8lx", hr );
436 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
437 (void**)&l.p_dvbc_tune_request );
440 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
441 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
444 l.p_dvbc_tune_request->put_ONID( -1 );
445 l.p_dvbc_tune_request->put_SID( -1 );
446 l.p_dvbc_tune_request->put_TSID( -1 );
448 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
449 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
452 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
453 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
458 if( l_frequency > 0 )
459 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
460 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
461 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
462 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
463 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
466 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
467 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
471 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
474 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
475 "Cannot put the locator: hr=0x%8lx", hr );
479 /* Build and Run the Graph. If a Tuner device is in use the graph will
480 * fail to run. Repeated calls to build will check successive tuner
487 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
488 "Cannot Build the Graph: hr=0x%8lx", hr );
498 /*****************************************************************************
499 * Submit a DVB-S Tune Request
500 ******************************************************************************/
501 int BDAGraph::SubmitDVBSTuneRequest()
508 IDVBTuneRequest* p_dvbs_tune_request;
509 IDVBSLocator* p_dvbs_locator;
510 IDVBSTuningSpace* p_dvbs_tuning_space;
511 char* psz_polarisation;
512 char* psz_input_range;
513 BSTR bstr_input_range;
514 WCHAR* pwsz_input_range;
516 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
517 p_dvbs_tuning_space(NULL), bstr_input_range(NULL),
518 pwsz_input_range(NULL), i_range_len(NULL), psz_polarisation(NULL),
519 psz_input_range(NULL) {};
522 if( p_dvbs_tuning_space )
523 p_dvbs_tuning_space->Release();
524 if( p_dvbs_tune_request )
525 p_dvbs_tune_request->Release();
527 p_dvbs_locator->Release();
528 SysFreeString( bstr_input_range );
529 delete pwsz_input_range;
530 free(pwsz_input_range);
531 free(pwsz_input_range);
534 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
535 long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
536 long l_input_range, l_hp_fec;
538 Polarisation i_polar;
539 SpectralInversion i_inversion;
541 BinaryConvolutionCodeRate i_hp_fec;
542 ModulationType i_mod_typ;
544 l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
545 l_lnb_lof1 = l_lnb_lof2 = l_lnb_slof = l_inversion = l_network_id = -1;
546 l_input_range = l_hp_fec = i_mod = -1;
547 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
548 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
549 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
550 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
551 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
552 l_lnb_lof1 = var_GetInteger( p_access, "dvb-lnb-lof1" );
553 l_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
554 l_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
555 l.psz_polarisation = var_GetNonEmptyString( p_access, "dvb-polarisation" );
556 i_mod = var_GetInteger( p_access, "dvb-modulation" );
557 l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
558 l_inversion = var_GetInteger( p_access, "dvb-inversion" );
559 l_network_id = var_GetInteger( p_access, "dvb-network-id" );
560 l.psz_input_range = var_GetNonEmptyString( p_access, "dvb-range" );
562 b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
564 i_polar = BDA_POLARISATION_NOT_SET;
565 if( l.psz_polarisation != NULL )
566 switch( toupper( l.psz_polarisation[0] ) )
569 i_polar = BDA_POLARISATION_LINEAR_H;
572 i_polar = BDA_POLARISATION_LINEAR_V;
575 i_polar = BDA_POLARISATION_CIRCULAR_L;
578 i_polar = BDA_POLARISATION_CIRCULAR_R;
582 i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
583 if( l_inversion == 0 )
584 i_inversion = BDA_SPECTRAL_INVERSION_NORMAL;
585 if( l_inversion == 1 )
586 i_inversion = BDA_SPECTRAL_INVERSION_INVERTED;
587 if( l_inversion == 2 )
588 i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC;
590 i_mod_typ = BDA_MOD_NOT_SET;
592 i_mod_typ = BDA_MOD_16QAM;
594 i_mod_typ = BDA_MOD_128QAM;
596 i_mod_typ = BDA_MOD_256QAM;
598 i_mod_typ = BDA_MOD_QPSK;
600 i_hp_fec = BDA_BCC_RATE_NOT_SET;
602 i_hp_fec = BDA_BCC_RATE_1_2;
604 i_hp_fec = BDA_BCC_RATE_2_3;
606 i_hp_fec = BDA_BCC_RATE_3_4;
608 i_hp_fec = BDA_BCC_RATE_5_6;
610 i_hp_fec = BDA_BCC_RATE_7_8;
612 l.i_range_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
613 l.psz_input_range, -1, l.pwsz_input_range, 0 );
614 if( l.i_range_len > 0 )
616 l.pwsz_input_range = new WCHAR[l.i_range_len];
617 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
618 l.psz_input_range, -1, l.pwsz_input_range, l.i_range_len );
619 l.bstr_input_range=SysAllocString( l.pwsz_input_range );
622 guid_network_type = CLSID_DVBSNetworkProvider;
623 hr = CreateTuneRequest();
626 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
627 "Cannot create Tune Request: hr=0x%8lx", hr );
631 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
632 (void**)&l.p_dvbs_tune_request );
635 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
636 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
639 l.p_dvbs_tune_request->put_ONID( -1 );
640 l.p_dvbs_tune_request->put_SID( -1 );
641 l.p_dvbs_tune_request->put_TSID( -1 );
643 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
644 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
647 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
648 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
652 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
653 (void**)&l.p_dvbs_tuning_space );
656 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
657 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
663 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
664 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
665 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
666 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
667 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
668 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
669 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
670 if( SUCCEEDED( hr ) && l_network_id > 0 )
671 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
672 if( SUCCEEDED( hr ) && l.i_range_len > 0 )
673 hr = l.p_dvbs_tuning_space->put_InputRange( l.bstr_input_range );
675 if( SUCCEEDED( hr ) && l_frequency > 0 )
676 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
677 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
678 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
679 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
680 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
681 if( SUCCEEDED( hr ) && i_mod_typ != BDA_MOD_NOT_SET )
682 hr = l.p_dvbs_locator->put_Modulation( i_mod_typ );
683 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
684 hr = l.p_dvbs_locator->put_InnerFECRate( i_hp_fec );
686 if( SUCCEEDED( hr ) && l_azimuth > 0 )
687 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
688 if( SUCCEEDED( hr ) && l_elevation > 0 )
689 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
690 if( SUCCEEDED( hr ) )
691 hr = l.p_dvbs_locator->put_WestPosition( b_west );
692 if( SUCCEEDED( hr ) )
693 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
696 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
697 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
701 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
704 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
705 "Cannot put the locator: hr=0x%8lx", hr );
709 /* Build and Run the Graph. If a Tuner device is in use the graph will
710 * fail to run. Repeated calls to build will check successive tuner
717 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
718 "Cannot Build the Graph: hr=0x%8lx", hr );
728 /*****************************************************************************
729 * Load the Tuning Space from System Tuning Spaces according to the
730 * Network Type requested
731 ******************************************************************************/
732 HRESULT BDAGraph::CreateTuneRequest()
735 GUID guid_this_network_type;
739 ITuningSpaceContainer* p_tuning_space_container;
740 IEnumTuningSpaces* p_tuning_space_enum;
741 ITuningSpace* p_this_tuning_space;
743 char * psz_network_name;
744 WCHAR * wpsz_network_name;
746 localComPtr(): p_tuning_space_container(NULL),
747 p_tuning_space_enum(NULL), p_this_tuning_space(NULL),
748 i_name_len(0), psz_network_name(NULL), wpsz_network_name(NULL),
752 if( p_tuning_space_container )
753 p_tuning_space_container->Release();
754 if( p_tuning_space_enum )
755 p_tuning_space_enum->Release();
756 if( p_this_tuning_space )
757 p_this_tuning_space->Release();
758 SysFreeString( bstr_name );
759 delete wpsz_network_name;
760 free(psz_network_name);
764 /* We shall test for a specific Tuning space name supplied on the command
765 * line as dvb-networkname=xxx.
766 * For some users with multiple cards and/or multiple networks this could
767 * be useful. This allows us to reasonably safely apply updates to the
768 * System Tuning Space in the registry without disrupting other streams. */
769 l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-network-name" );
770 if( l.psz_network_name )
772 l.i_name_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
773 l.psz_network_name, -1, l.wpsz_network_name, 0 );
774 if( l.i_name_len > 0 )
776 l.wpsz_network_name = new WCHAR[l.i_name_len];
777 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, l.psz_network_name, -1,
778 l.wpsz_network_name, l.i_name_len );
779 msg_Dbg( p_access, "CreateTuneRequest: Find Tuning Space: %S",
780 l.wpsz_network_name );
784 /* A Tuning Space may already have been set up. If it is for the same
785 * network type then all is well. Otherwise, reset the Tuning Space and get
789 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
790 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
791 if( guid_this_network_type == guid_network_type )
793 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
796 msg_Warn( p_access, "CreateTuneRequest: "\
797 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
800 /* Test for a specific Tuning space name supplied on the command
801 * line as dvb-networkname=xxx */
802 if( l.i_name_len == 0 ||
803 lstrcmpW( l.wpsz_network_name, l.bstr_name ) == 0 )
805 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %S",
811 p_tuning_space->Release();
812 p_tuning_space = NULL;
815 /* Force use of the first available Tuner Device during Build */
818 /* Get the SystemTuningSpaces container to enumerate through all the
819 * defined tuning spaces */
820 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
821 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
824 msg_Warn( p_access, "CreateTuneRequest: "\
825 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
829 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
830 &l.p_tuning_space_enum );
833 msg_Warn( p_access, "CreateTuneRequest: "\
834 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
838 while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
841 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
843 /* GUID_NULL means a non-BDA network was found e.g analog
844 * Ignore failures and non-BDA networks and keep looking */
845 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
847 if( guid_this_network_type == guid_network_type )
849 hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
850 (void**)&p_tuning_space );
853 msg_Warn( p_access, "CreateTuneRequest: "\
854 "Cannot QI Tuning Space: hr=0x%8lx", hr );
857 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
860 msg_Warn( p_access, "CreateTuneRequest: "\
861 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
865 /* Test for a specific Tuning space name supplied on the command
866 * line as dvb-networkname=xxx */
867 if( l.i_name_len == 0 ||
868 lstrcmpW( l.wpsz_network_name, l.bstr_name ) == 0 )
870 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %S",
872 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
874 msg_Warn( p_access, "CreateTuneRequest: "\
875 "Cannot Create Tune Request: hr=0x%8lx", hr );
880 /* No tune request was found. If the create-name parameter was set then
881 * create a tuning space. By rights should use the same name used in
883 * Also would be nice to copy a tuning space but we only come here if we do
885 free( l.psz_network_name );
886 l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-create-name" );
887 if( !l.psz_network_name )
890 msg_Warn( p_access, "CreateTuneRequest: "\
891 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
895 /* Need to use DVBSTuningSpace for DVB-S and ATSCTuningSpace for ATSC */
897 CLSID cls_tuning_space;
899 if( IsEqualCLSID( guid_network_type, CLSID_ATSCNetworkProvider ) )
900 cls_tuning_space = CLSID_ATSCTuningSpace;
901 if( IsEqualCLSID( guid_network_type, CLSID_DVBTNetworkProvider ) )
902 cls_tuning_space = CLSID_DVBTuningSpace;
903 if( IsEqualCLSID( guid_network_type, CLSID_DVBCNetworkProvider ) )
904 cls_tuning_space = CLSID_DVBTuningSpace;
905 if( IsEqualCLSID( guid_network_type, CLSID_DVBSNetworkProvider ) )
906 cls_tuning_space = CLSID_DVBSTuningSpace;
908 delete l.wpsz_network_name;
909 l.i_name_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
910 l.psz_network_name, -1, l.wpsz_network_name, 0 );
911 if( l.i_name_len > 0 )
913 l.wpsz_network_name = new WCHAR[l.i_name_len];
914 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, l.psz_network_name, -1,
915 l.wpsz_network_name, l.i_name_len );
917 SysFreeString( l.bstr_name );
918 l.bstr_name = SysAllocString( l.wpsz_network_name );
919 msg_Dbg( p_access, "CreateTuneRequest: Create Tuning Space: %S",
922 hr = ::CoCreateInstance( cls_tuning_space, 0, CLSCTX_INPROC,
923 IID_ITuningSpace, (void**)&p_tuning_space );
925 msg_Warn( p_access, "CreateTuneRequest: "\
926 "Cannot CoCreate new TuningSpace: hr=0x%8lx", hr );
927 if( SUCCEEDED( hr ) )
928 hr = p_tuning_space->put__NetworkType( guid_network_type );
930 msg_Warn( p_access, "CreateTuneRequest: "\
931 "Cannot Put Network Type: hr=0x%8lx", hr );
932 if( SUCCEEDED( hr ) )
933 hr = p_tuning_space->put_UniqueName( l.bstr_name );
935 msg_Warn( p_access, "CreateTuneRequest: "\
936 "Cannot Put Unique Name: hr=0x%8lx", hr );
937 if( SUCCEEDED( hr ) )
938 hr = p_tuning_space->put_FriendlyName( l.bstr_name );
940 msg_Warn( p_access, "CreateTuneRequest: "\
941 "Cannot Put Friendly Name: hr=0x%8lx", hr );
942 if( SUCCEEDED( hr ) )
943 hr = l.p_tuning_space_container->Add( p_tuning_space, &var_id );
946 msg_Warn( p_access, "CreateTuneRequest: "\
947 "Cannot Create new TuningSpace: hr=0x%8lx", hr );
950 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
952 msg_Warn( p_access, "CreateTuneRequest: "\
953 "Cannot Create Tune Request: hr=0x%8lx", hr );
957 /******************************************************************************
959 * Step 4: Build the Filter Graph
960 * Build sets up devices, adds and connects filters
961 ******************************************************************************/
962 HRESULT BDAGraph::Build()
965 long l_capture_used, l_tif_used;
966 VARIANT l_tuning_space_id;
967 AM_MEDIA_TYPE grabber_media_type;
971 ITuningSpaceContainer* p_tuning_space_container;
972 localComPtr(): p_tuning_space_container(NULL) {};
975 if( p_tuning_space_container )
976 p_tuning_space_container->Release();
980 /* Get the SystemTuningSpaces container to save the Tuning space */
981 l_tuning_space_id.vt = VT_I4;
982 l_tuning_space_id.lVal = 0L;
983 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
984 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
987 msg_Warn( p_access, "Build: "\
988 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
991 hr = l.p_tuning_space_container->FindID( p_tuning_space,
992 &l_tuning_space_id.lVal );
995 msg_Warn( p_access, "Build: "\
996 "Cannot Find Tuning Space ID: hr=0x%8lx", hr );
999 msg_Dbg( p_access, "Build: Using Tuning Space ID %d",
1000 l_tuning_space_id.lVal );
1001 hr = l.p_tuning_space_container->put_Item( l_tuning_space_id,
1005 msg_Warn( p_access, "Build: "\
1006 "Cannot save Tuning Space: hr=0x%8lx", hr );
1010 /* If we have already have a filter graph, rebuild it*/
1013 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1014 IID_IGraphBuilder, (void**)&p_filter_graph );
1017 msg_Warn( p_access, "Build: "\
1018 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
1022 /* First filter in the graph is the Network Provider and
1023 * its Scanning Tuner which takes the Tune Request*/
1024 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
1025 IID_IBaseFilter, (void**)&p_network_provider);
1028 msg_Warn( p_access, "Build: "\
1029 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
1032 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
1035 msg_Warn( p_access, "Build: "\
1036 "Cannot load network provider: hr=0x%8lx", hr );
1040 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
1041 (void**)&p_scanning_tuner );
1044 msg_Warn( p_access, "Build: "\
1045 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
1049 hr = p_scanning_tuner->Validate( p_tune_request );
1052 msg_Warn( p_access, "Build: "\
1053 "Tune Request is invalid: hr=0x%8lx", hr );
1056 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
1059 msg_Warn( p_access, "Build: "\
1060 "Cannot submit the tune request: hr=0x%8lx", hr );
1064 /* Add the Network Tuner to the Network Provider. On subsequent calls,
1065 * l_tuner_used will cause a different tuner to be selected */
1066 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
1067 p_network_provider, &p_tuner_device );
1070 msg_Warn( p_access, "Build: "\
1071 "Cannot load tuner device and connect network provider: "\
1076 /* Always look for all capture devices to match the Network Tuner */
1077 l_capture_used = -1;
1078 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
1079 p_tuner_device, &p_capture_device );
1082 /* Some BDA drivers do not provide a Capture Device Filter so force
1083 * the Sample Grabber to connect directly to the Tuner Device */
1084 p_capture_device = p_tuner_device;
1085 p_tuner_device = NULL;
1086 msg_Warn( p_access, "Build: "\
1087 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
1090 /* Insert the Sample Grabber to tap into the Transport Stream. */
1091 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
1092 IID_IBaseFilter, (void**)&p_sample_grabber );
1095 msg_Warn( p_access, "Build: "\
1096 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
1099 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
1102 msg_Warn( p_access, "Build: "\
1103 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
1107 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
1108 (void**)&p_grabber );
1111 msg_Warn( p_access, "Build: "\
1112 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
1116 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
1117 grabber_media_type.majortype == MEDIATYPE_Stream;
1118 grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
1119 hr = p_grabber->SetMediaType( &grabber_media_type );
1122 msg_Warn( p_access, "Build: "\
1123 "Cannot set media type on grabber filter: hr=0x%8lx", hr );
1126 hr = Connect( p_capture_device, p_sample_grabber );
1129 msg_Warn( p_access, "Build: "\
1130 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
1134 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
1135 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
1136 * the Network Provider filter to set up the stream */
1137 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
1138 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
1141 msg_Warn( p_access, "Build: "\
1142 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
1145 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
1148 msg_Warn( p_access, "Build: "\
1149 "Cannot add demux filter to graph: hr=0x%8lx", hr );
1153 hr = Connect( p_sample_grabber, p_mpeg_demux );
1156 msg_Warn( p_access, "Build: "\
1157 "Cannot connect demux to grabber: hr=0x%8lx", hr );
1161 /* Always look for the Transform Information Filter from the start
1162 * of the collection*/
1164 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
1165 p_mpeg_demux, &p_transport_info );
1168 msg_Warn( p_access, "Build: "\
1169 "Cannot load TIF onto demux: hr=0x%8lx", hr );
1173 /* Configure the Sample Grabber to buffer the samples continuously */
1174 hr = p_grabber->SetBufferSamples( TRUE );
1177 msg_Warn( p_access, "Build: "\
1178 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
1181 hr = p_grabber->SetOneShot( FALSE );
1184 msg_Warn( p_access, "Build: "\
1185 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
1188 hr = p_grabber->SetCallback( this, 0 );
1191 msg_Warn( p_access, "Build: "\
1192 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
1199 d_graph_register = 0;
1202 /* The Media Control is used to Run and Stop the Graph */
1203 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
1204 (void**)&p_media_control );
1207 msg_Warn( p_access, "Build: "\
1208 "Cannot QI Media Control: hr=0x%8lx", hr );
1214 /******************************************************************************
1216 * Looks up all filters in a category and connects to the upstream filter until
1217 * a successful match is found. The index of the connected filter is returned.
1218 * On subsequent calls, this can be used to start from that point to find
1220 * This is used when the graph does not run because a tuner device is in use so
1221 * another one needs to be selected.
1222 ******************************************************************************/
1223 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
1224 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
1227 int i_moniker_index = -1;
1231 IMoniker* p_moniker;
1232 IEnumMoniker* p_moniker_enum;
1233 IBaseFilter* p_filter;
1234 IPropertyBag* p_property_bag;
1238 p_moniker_enum(NULL),
1240 p_property_bag(NULL)
1241 { ::VariantInit(&var_bstr); };
1245 p_moniker->Release();
1246 if( p_moniker_enum )
1247 p_moniker_enum->Release();
1249 p_filter->Release();
1250 if( p_property_bag )
1251 p_property_bag->Release();
1252 ::VariantClear(&var_bstr);
1256 if( !p_system_dev_enum )
1258 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1259 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1262 msg_Warn( p_access, "FindFilter: "\
1263 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1268 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1269 &l.p_moniker_enum, 0 );
1272 msg_Warn( p_access, "FindFilter: "\
1273 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1276 while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
1280 /* Skip over devices already found on previous calls */
1281 if( i_moniker_index <= *i_moniker_used ) continue;
1282 *i_moniker_used = i_moniker_index;
1284 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1285 (void**)&l.p_filter );
1289 l.p_moniker->Release();
1292 l.p_filter->Release();
1297 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1298 (void**)&l.p_property_bag );
1301 msg_Warn( p_access, "FindFilter: "\
1302 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1306 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1309 msg_Warn( p_access, "FindFilter: "\
1310 "Cannot read filter friendly name: hr=0x%8lx", hr );
1314 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1317 msg_Warn( p_access, "FindFilter: "\
1318 "Cannot add filter: hr=0x%8lx", hr );
1322 hr = Connect( p_upstream, l.p_filter );
1323 if( SUCCEEDED( hr ) )
1325 msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
1326 l.p_filter->QueryInterface( IID_IBaseFilter,
1327 (void**)p_p_downstream );
1330 /* Not the filter we want so unload and try the next one */
1331 hr = p_filter_graph->RemoveFilter( l.p_filter );
1334 msg_Warn( p_access, "FindFilter: "\
1335 "Failed unloading Filter: hr=0x%8lx", hr );
1340 l.p_moniker->Release();
1343 l.p_filter->Release();
1348 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1352 /*****************************************************************************
1353 * Connect is called from Build to enumerate and connect pins
1354 *****************************************************************************/
1355 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1357 HRESULT hr = E_FAIL;
1361 IPin* p_pin_upstream;
1362 IPin* p_pin_downstream;
1363 IEnumPins* p_pin_upstream_enum;
1364 IEnumPins* p_pin_downstream_enum;
1366 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1367 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1368 p_pin_temp(NULL) { };
1371 if( p_pin_upstream )
1372 p_pin_upstream->Release();
1373 if( p_pin_downstream )
1374 p_pin_downstream->Release();
1375 if( p_pin_upstream_enum )
1376 p_pin_upstream_enum->Release();
1377 if( p_pin_downstream_enum )
1378 p_pin_downstream_enum->Release();
1380 p_pin_temp->Release();
1384 PIN_INFO pin_info_upstream;
1385 PIN_INFO pin_info_downstream;
1387 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1390 msg_Warn( p_access, "Connect: "\
1391 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1394 while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
1396 hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
1399 msg_Warn( p_access, "Connect: "\
1400 "Cannot get upstream filter pin information: hr=0x%8lx", hr );
1403 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1405 l.p_pin_downstream->Release();
1406 if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1408 msg_Warn( p_access, "Connect: "\
1409 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1412 if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
1413 ( hr == VFW_E_NOT_CONNECTED ) )
1415 /* The upstream pin is not yet connected so check each pin on the
1416 * downstream filter */
1417 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1420 msg_Warn( p_access, "Connect: Cannot get "\
1421 "downstream filter enumerator: hr=0x%8lx", hr );
1424 while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
1427 hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
1430 msg_Warn( p_access, "Connect: Cannot get "\
1431 "downstream filter pin information: hr=0x%8lx", hr );
1435 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1436 if( hr == S_OK ) l.p_pin_temp->Release();
1437 if( hr != VFW_E_NOT_CONNECTED )
1441 msg_Warn( p_access, "Connect: Cannot check "\
1442 "downstream filter connection: hr=0x%8lx", hr );
1446 if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
1447 ( hr == VFW_E_NOT_CONNECTED ) )
1449 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1450 l.p_pin_downstream, NULL );
1451 if( SUCCEEDED( hr ) )
1453 pin_info_downstream.pFilter->Release();
1454 pin_info_upstream.pFilter->Release();
1458 /* If we fall out here it means this downstream pin was not
1459 * suitable so try the next downstream pin */
1460 l.p_pin_downstream = NULL;
1461 pin_info_downstream.pFilter->Release();
1465 /* If we fall out here it means we did not find any suitable downstream
1466 * pin so try the next upstream pin */
1467 l.p_pin_upstream = NULL;
1468 pin_info_upstream.pFilter->Release();
1471 /* If we fall out here it means we did not find any pair of suitable pins */
1475 /*****************************************************************************
1476 * Start uses MediaControl to start the graph
1477 *****************************************************************************/
1478 HRESULT BDAGraph::Start()
1481 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1483 if( !p_media_control )
1485 msg_Dbg( p_access, "Start: Media Control has not been created" );
1488 hr = p_media_control->Run();
1492 /* Query the state of the graph - timeout after 100 milliseconds */
1493 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1498 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1502 if( i_state == State_Running )
1505 /* The Graph is not running so stop it and return an error */
1506 msg_Warn( p_access, "Start: Graph not started: %d", i_state );
1507 hr = p_media_control->Stop();
1511 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1517 /*****************************************************************************
1518 * Read the stream of data - query the buffer size required
1519 *****************************************************************************/
1520 long BDAGraph::GetBufferSize()
1522 long l_buffer_size = 0;
1527 for( int i_timer = 0; queue_sample.empty() && i_timer < 200; i_timer++ )
1530 l_queue_size = queue_sample.size();
1531 if( l_queue_size <= 0 )
1533 msg_Warn( p_access, "BDA GetBufferSize: Timed Out waiting for sample" );
1537 /* Establish the length of the queue as it grows quickly. If the queue
1538 * size is checked dynamically there is a risk of not exiting the loop */
1539 for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1541 l_buffer_size += queue_sample.front()->GetActualDataLength();
1542 queue_buffer.push( queue_sample.front() );
1545 return l_buffer_size;
1548 /*****************************************************************************
1549 * Read the stream of data - Retrieve from the buffer queue
1550 ******************************************************************************/
1551 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1558 while( !queue_buffer.empty() )
1560 queue_buffer.front()->GetPointer( &p_buff_temp );
1561 hr = queue_buffer.front()->IsDiscontinuity();
1564 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1565 memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1566 queue_buffer.front()->GetActualDataLength() );
1567 *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1568 queue_buffer.front()->Release();
1572 return *pl_buffer_len;
1575 /******************************************************************************
1576 * SampleCB - Callback when the Sample Grabber has a sample
1577 ******************************************************************************/
1578 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1583 queue_sample.push( p_sample );
1587 msg_Warn( p_access, "BDA SampleCB: Not ready - dropped sample" );
1592 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1598 /******************************************************************************
1599 * removes each filter from the graph
1600 ******************************************************************************/
1601 HRESULT BDAGraph::Destroy()
1605 if( p_media_control )
1606 hr = p_media_control->Stop();
1608 if( p_transport_info )
1610 p_filter_graph->RemoveFilter( p_transport_info );
1611 p_transport_info->Release();
1612 p_transport_info = NULL;
1616 p_filter_graph->RemoveFilter( p_mpeg_demux );
1617 p_mpeg_demux->Release();
1618 p_mpeg_demux = NULL;
1620 if( p_sample_grabber )
1622 p_filter_graph->RemoveFilter( p_sample_grabber );
1623 p_sample_grabber->Release();
1624 p_sample_grabber = NULL;
1626 if( p_capture_device )
1628 p_filter_graph->RemoveFilter( p_capture_device );
1629 p_capture_device->Release();
1630 p_capture_device = NULL;
1632 if( p_tuner_device )
1634 p_filter_graph->RemoveFilter( p_tuner_device );
1635 p_tuner_device->Release();
1636 p_tuner_device = NULL;
1638 if( p_network_provider )
1640 p_filter_graph->RemoveFilter( p_network_provider );
1641 p_network_provider->Release();
1642 p_network_provider = NULL;
1645 if( p_scanning_tuner )
1647 p_scanning_tuner->Release();
1648 p_scanning_tuner = NULL;
1650 if( p_media_control )
1652 p_media_control->Release();
1653 p_media_control = NULL;
1655 if( p_filter_graph )
1657 p_filter_graph->Release();
1658 p_filter_graph = NULL;
1661 if( d_graph_register )
1669 /*****************************************************************************
1670 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1671 * Allows GraphEdit to "spy" on a remote filter graph.
1672 ******************************************************************************/
1673 HRESULT BDAGraph::Register()
1678 IMoniker* p_moniker;
1679 IRunningObjectTable* p_ro_table;
1680 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1684 p_moniker->Release();
1686 p_ro_table->Release();
1689 WCHAR psz_w_graph_name[128];
1692 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1695 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1699 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1700 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1701 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1704 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1707 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1708 p_filter_graph, l.p_moniker, &d_graph_register );
1711 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1714 msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1718 void BDAGraph::Deregister()
1721 IRunningObjectTable* p_ro_table;
1722 hr = ::GetRunningObjectTable( 0, &p_ro_table );
1723 if( SUCCEEDED( hr ) )
1724 p_ro_table->Revoke( d_graph_register );
1725 d_graph_register = 0;
1726 p_ro_table->Release();