1 /*****************************************************************************
2 * bdagraph.cpp : DirectShow BDA graph for vlc
3 *****************************************************************************
4 * Copyright (C) 2007 the VideoLAN team
5 * Copyright (C) 2011 RĂ©mi Denis-Courmont
7 * Author: Ken Self <kenself(at)optusnet(dot)com(dot)au>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 *( at your option ) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_block.h>
33 #include "dtv/bdagraph.hpp"
37 static ModulationType dvb_parse_modulation (const char *mod)
39 if (!strcmp (mod, "16QAM")) return BDA_MOD_16QAM;
40 if (!strcmp (mod, "32QAM")) return BDA_MOD_32QAM;
41 if (!strcmp (mod, "64QAM")) return BDA_MOD_64QAM;
42 if (!strcmp (mod, "128QAM")) return BDA_MOD_128QAM;
43 if (!strcmp (mod, "256QAM")) return BDA_MOD_256QAM;
44 return BDA_MOD_NOT_SET;
47 static BinaryConvolutionCodeRate dvb_parse_fec (uint32_t fec)
51 case VLC_FEC(1,2): return BDA_BCC_RATE_1_2;
52 case VLC_FEC(2,3): return BDA_BCC_RATE_2_3;
53 case VLC_FEC(3,4): return BDA_BCC_RATE_3_4;
54 case VLC_FEC(5,6): return BDA_BCC_RATE_5_6;
55 case VLC_FEC(7,8): return BDA_BCC_RATE_7_8;
57 return BDA_BCC_RATE_NOT_SET;
60 static GuardInterval dvb_parse_guard (uint32_t guard)
64 case VLC_GUARD(1, 4): return BDA_GUARD_1_4;
65 case VLC_GUARD(1, 8): return BDA_GUARD_1_8;
66 case VLC_GUARD(1,16): return BDA_GUARD_1_16;
67 case VLC_GUARD(1,32): return BDA_GUARD_1_32;
69 return BDA_GUARD_NOT_SET;
72 static TransmissionMode dvb_parse_transmission (int transmit)
76 case 2: return BDA_XMIT_MODE_2K;
77 case 8: return BDA_XMIT_MODE_8K;
79 return BDA_XMIT_MODE_NOT_SET;
82 static HierarchyAlpha dvb_parse_hierarchy (int hierarchy)
86 case 1: return BDA_HALPHA_1;
87 case 2: return BDA_HALPHA_2;
88 case 4: return BDA_HALPHA_4;
90 return BDA_HALPHA_NOT_SET;
93 static Polarisation dvb_parse_polarization (char pol)
97 case 'H': return BDA_POLARISATION_LINEAR_H;
98 case 'V': return BDA_POLARISATION_LINEAR_V;
99 case 'L': return BDA_POLARISATION_CIRCULAR_L;
100 case 'R': return BDA_POLARISATION_CIRCULAR_R;
102 return BDA_POLARISATION_NOT_SET;
105 static SpectralInversion dvb_parse_inversion (int inversion)
109 case 0: return BDA_SPECTRAL_INVERSION_NORMAL;
110 case 1: return BDA_SPECTRAL_INVERSION_INVERTED;
111 case -1: return BDA_SPECTRAL_INVERSION_AUTOMATIC;
113 /* should never happen */
114 return BDA_SPECTRAL_INVERSION_NOT_SET;
117 /****************************************************************************
118 * Interfaces for calls from C
119 ****************************************************************************/
124 /* DVB-S property cache */
130 uint32_t lowf, highf, switchf;
133 dvb_device_t *dvb_open (vlc_object_t *obj)
135 dvb_device_t *d = new dvb_device_t;
137 d->module = new BDAGraph (obj);
140 d->fec = VLC_FEC_AUTO;
143 d->lowf = d->highf = d->switchf = 0;
147 void dvb_close (dvb_device_t *d)
153 ssize_t dvb_read (dvb_device_t *d, void *buf, size_t len)
155 return d->module->Pop(buf, len);
158 int dvb_add_pid (dvb_device_t *, uint16_t)
163 void dvb_remove_pid (dvb_device_t *, uint16_t)
167 unsigned dvb_enum_systems (dvb_device_t *)
173 float dvb_get_signal_strength (dvb_device_t *)
178 float dvb_get_snr (dvb_device_t *)
183 int dvb_set_inversion (dvb_device_t *d, int inversion)
185 d->inversion = inversion;
186 if (d->frequency == 0)
187 return 0; /* not DVB-S */
188 return d->module->SetDVBS(d->frequency, d->srate, d->fec, d->inversion,
189 d->pol, d->lowf, d->highf, d->switchf);
192 int dvb_tune (dvb_device_t *d)
194 return d->module->SubmitTuneRequest ();
198 int dvb_set_dvbc (dvb_device_t *d, uint32_t freq, const char *mod,
199 uint32_t srate, uint32_t /*fec*/)
201 return d->module->SetDVBC (freq / 1000, mod, srate);
205 int dvb_set_dvbs (dvb_device_t *d, uint64_t freq, uint32_t srate, uint32_t fec)
207 d->frequency = freq / 1000;
210 return d->module->SetDVBS(d->frequency, d->srate, d->fec, d->inversion,
211 d->pol, d->lowf, d->highf, d->switchf);
214 int dvb_set_dvbs2 (dvb_device_t *, uint64_t /*freq*/, const char * /*mod*/,
215 uint32_t /*srate*/, uint32_t /*fec*/, int /*pilot*/, int /*rolloff*/)
220 int dvb_set_sec (dvb_device_t *d, uint64_t freq, char pol,
221 uint32_t lowf, uint32_t highf, uint32_t switchf)
223 d->frequency = freq / 1000;
227 d->switchf = switchf;
228 return d->module->SetDVBS(d->frequency, d->srate, d->fec, d->inversion,
229 d->pol, d->lowf, d->highf, d->switchf);
233 int dvb_set_dvbt (dvb_device_t *d, uint32_t freq, const char * /*mod*/,
234 uint32_t fec_hp, uint32_t fec_lp, uint32_t bandwidth,
235 int transmission, uint32_t guard, int hierarchy)
237 return d->module->SetDVBT(freq / 1000, fec_hp, fec_lp,
238 bandwidth, transmission, guard, hierarchy);
241 int dvb_set_dvbt2 (dvb_device_t *, uint32_t /*freq*/, const char * /*mod*/,
242 uint32_t /*fec*/, uint32_t /*bandwidth*/, int /*tx_mode*/,
249 int dvb_set_isdbc (dvb_device_t *, uint32_t freq, const char *mod,
250 uint32_t srate, uint32_t fec)
256 int dvb_set_isdbs (dvb_device_t *, uint64_t /*freq*/, uint16_t /*ts_id*/)
262 int dvb_set_isdbt (dvb_device_t *, uint32_t /*freq*/, uint32_t /*bandwidth*/,
263 int /*transmit_mode*/, uint32_t /*guard*/,
264 const isdbt_layer_t /*layers*/[3])
270 int dvb_set_atsc (dvb_device_t *d, uint32_t freq, const char * /*mod*/)
272 return d->module->SetATSC(freq / 1000);
275 int dvb_set_cqam (dvb_device_t *d, uint32_t freq, const char * /*mod*/)
277 return d->module->SetCQAM(freq / 1000);
281 /*****************************************************************************
283 *****************************************************************************/
284 BDAOutput::BDAOutput( vlc_object_t *p_access ) :
285 p_access(p_access), p_first(NULL), pp_next(&p_first)
287 vlc_mutex_init( &lock );
288 vlc_cond_init( &wait );
291 BDAOutput::~BDAOutput()
294 vlc_mutex_destroy( &lock );
295 vlc_cond_destroy( &wait );
298 void BDAOutput::Push( block_t *p_block )
300 vlc_mutex_locker l( &lock );
302 block_ChainLastAppend( &pp_next, p_block );
303 vlc_cond_signal( &wait );
306 ssize_t BDAOutput::Pop(void *buf, size_t len)
310 vlc_mutex_locker l( &lock );
313 vlc_cond_timedwait( &wait, &lock, mdate() + 250*1000 );
323 if(len < block->i_buffer)
324 msg_Err(p_access, "buffer overflow!");
326 len = block->i_buffer;
327 vlc_memcpy(buf, block->p_buffer, len);
328 block_Release(block);
332 void BDAOutput::Empty()
334 vlc_mutex_locker l( &lock );
337 block_ChainRelease( p_first );
342 /*****************************************************************************
344 *****************************************************************************/
345 BDAGraph::BDAGraph( vlc_object_t *p_this ):
347 guid_network_type(GUID_NULL),
349 d_graph_register( 0 ),
352 p_tuning_space = NULL;
353 p_tune_request = NULL;
354 p_media_control = NULL;
355 p_filter_graph = NULL;
356 p_system_dev_enum = NULL;
357 p_network_provider = p_tuner_device = p_capture_device = NULL;
358 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
359 p_scanning_tuner = NULL;
362 /* Initialize COM - MS says to use CoInitializeEx in preference to
364 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
367 /*****************************************************************************
369 *****************************************************************************/
370 BDAGraph::~BDAGraph()
377 int BDAGraph::SubmitTuneRequest(void)
381 /* Build and Run the Graph. If a Tuner device is in use the graph will
382 * fail to run. Repeated calls to build will check successive tuner
389 msg_Warn( p_access, "SubmitTuneRequest: "
390 "Cannot Build the Graph: hr=0x%8lx", hr );
400 /*****************************************************************************
401 * Set clear QAM (US cable)
402 *****************************************************************************/
403 int BDAGraph::SetCQAM(long l_frequency)
409 IDigitalCableTuneRequest* p_cqam_tune_request;
410 IDigitalCableLocator* p_cqam_locator;
411 localComPtr(): p_cqam_tune_request(NULL), p_cqam_locator(NULL) {};
414 if( p_cqam_tune_request )
415 p_cqam_tune_request->Release();
417 p_cqam_locator->Release();
420 long l_minor_channel, l_physical_channel;
422 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
423 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
425 guid_network_type = CLSID_DigitalCableNetworkType;
426 hr = CreateTuneRequest();
429 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
430 "Cannot create Tuning Space: hr=0x%8lx", hr );
434 hr = p_tune_request->QueryInterface( IID_IDigitalCableTuneRequest,
435 (void**)&l.p_cqam_tune_request );
438 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
439 "Cannot QI for IDigitalCableTuneRequest: hr=0x%8lx", hr );
442 hr = ::CoCreateInstance( CLSID_DigitalCableLocator, 0, CLSCTX_INPROC,
443 IID_IDigitalCableLocator, (void**)&l.p_cqam_locator );
446 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
447 "Cannot create the CQAM locator: hr=0x%8lx", hr );
452 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
453 hr = l.p_cqam_locator->put_PhysicalChannel( l_physical_channel );
454 if( SUCCEEDED( hr ) && l_frequency > 0 )
455 hr = l.p_cqam_locator->put_CarrierFrequency( l_frequency );
456 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
457 hr = l.p_cqam_tune_request->put_MinorChannel( l_minor_channel );
460 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
461 "Cannot set tuning parameters: hr=0x%8lx", hr );
465 hr = p_tune_request->put_Locator( l.p_cqam_locator );
468 msg_Warn( p_access, "SubmitCQAMTuneRequest: "\
469 "Cannot put the locator: hr=0x%8lx", hr );
476 /*****************************************************************************
478 *****************************************************************************/
479 int BDAGraph::SetATSC(long l_frequency)
485 IATSCChannelTuneRequest* p_atsc_tune_request;
486 IATSCLocator* p_atsc_locator;
487 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
490 if( p_atsc_tune_request )
491 p_atsc_tune_request->Release();
493 p_atsc_locator->Release();
496 long l_major_channel, l_minor_channel, l_physical_channel;
498 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
499 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
500 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
502 guid_network_type = CLSID_ATSCNetworkProvider;
503 hr = CreateTuneRequest();
506 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
507 "Cannot create Tuning Space: hr=0x%8lx", hr );
511 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
512 (void**)&l.p_atsc_tune_request );
515 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
516 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
519 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
520 IID_IATSCLocator, (void**)&l.p_atsc_locator );
523 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
524 "Cannot create the ATSC locator: hr=0x%8lx", hr );
529 if( l_frequency > 0 )
530 hr = l.p_atsc_locator->put_CarrierFrequency( l_frequency );
531 if( l_major_channel > 0 )
532 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
533 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
534 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
535 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
536 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
539 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
540 "Cannot set tuning parameters: hr=0x%8lx", hr );
544 hr = p_tune_request->put_Locator( l.p_atsc_locator );
547 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
548 "Cannot put the locator: hr=0x%8lx", hr );
554 /*****************************************************************************
556 ******************************************************************************/
557 int BDAGraph::SetDVBT(long l_frequency, uint32_t fec_hp, uint32_t fec_lp,
558 long l_bandwidth, int transmission, uint32_t guard, int hierarchy)
564 IDVBTuneRequest* p_dvbt_tune_request;
565 IDVBTLocator* p_dvbt_locator;
566 IDVBTuningSpace2* p_dvb_tuning_space;
567 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL),
568 p_dvb_tuning_space(NULL) {};
571 if( p_dvbt_tune_request )
572 p_dvbt_tune_request->Release();
574 p_dvbt_locator->Release();
575 if( p_dvb_tuning_space )
576 p_dvb_tuning_space->Release();
580 BinaryConvolutionCodeRate i_hp_fec = dvb_parse_fec(fec_hp);
581 BinaryConvolutionCodeRate i_lp_fec = dvb_parse_fec(fec_lp);
582 GuardInterval i_guard = dvb_parse_guard(guard);
583 TransmissionMode i_transmission = dvb_parse_transmission(transmission);
584 HierarchyAlpha i_hierarchy = dvb_parse_hierarchy(hierarchy);
586 guid_network_type = CLSID_DVBTNetworkProvider;
587 hr = CreateTuneRequest();
590 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
591 "Cannot create Tune Request: hr=0x%8lx", hr );
595 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
596 (void**)&l.p_dvbt_tune_request );
599 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
600 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
603 l.p_dvbt_tune_request->put_ONID( -1 );
604 l.p_dvbt_tune_request->put_SID( -1 );
605 l.p_dvbt_tune_request->put_TSID( -1 );
607 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
608 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
611 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
612 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
615 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
616 (void**)&l.p_dvb_tuning_space );
619 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
620 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
625 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
627 if( SUCCEEDED( hr ) && l_frequency > 0 )
628 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
629 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
630 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
631 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
632 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
633 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
634 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
635 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
636 hr = l.p_dvbt_locator->put_Guard( i_guard );
637 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
638 hr = l.p_dvbt_locator->put_Mode( i_transmission );
639 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
640 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
643 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
644 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
648 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
651 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
652 "Cannot put the locator: hr=0x%8lx", hr );
659 /*****************************************************************************
661 ******************************************************************************/
662 int BDAGraph::SetDVBC(long l_frequency, const char *mod, long l_symbolrate)
669 IDVBTuneRequest* p_dvbc_tune_request;
670 IDVBCLocator* p_dvbc_locator;
671 IDVBTuningSpace2* p_dvb_tuning_space;
673 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL),
674 p_dvb_tuning_space(NULL) {};
677 if( p_dvbc_tune_request )
678 p_dvbc_tune_request->Release();
680 p_dvbc_locator->Release();
681 if( p_dvb_tuning_space )
682 p_dvb_tuning_space->Release();
686 ModulationType i_qam_mod = dvb_parse_modulation(mod);
688 guid_network_type = CLSID_DVBCNetworkProvider;
689 hr = CreateTuneRequest();
692 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
693 "Cannot create Tune Request: hr=0x%8lx", hr );
697 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
698 (void**)&l.p_dvbc_tune_request );
701 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
702 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
705 l.p_dvbc_tune_request->put_ONID( -1 );
706 l.p_dvbc_tune_request->put_SID( -1 );
707 l.p_dvbc_tune_request->put_TSID( -1 );
709 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
710 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
713 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
714 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
717 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
718 (void**)&l.p_dvb_tuning_space );
721 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
722 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
727 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
729 if( SUCCEEDED( hr ) && l_frequency > 0 )
730 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
731 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
732 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
733 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
734 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
738 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
739 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
743 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
746 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
747 "Cannot put the locator: hr=0x%8lx", hr );
754 /*****************************************************************************
756 ******************************************************************************/
757 int BDAGraph::SetDVBS(long l_frequency, long l_symbolrate, uint32_t fec,
758 int inversion, char pol,
759 long l_lnb_lof1, long l_lnb_lof2, long l_lnb_slof)
766 IDVBTuneRequest* p_dvbs_tune_request;
767 IDVBSLocator* p_dvbs_locator;
768 IDVBSTuningSpace* p_dvbs_tuning_space;
769 char* psz_polarisation;
770 char* psz_input_range;
771 BSTR bstr_input_range;
772 WCHAR* pwsz_input_range;
774 localComPtr() : p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
775 p_dvbs_tuning_space(NULL),
776 psz_polarisation(NULL), psz_input_range(NULL),
777 bstr_input_range(NULL), pwsz_input_range(NULL), i_range_len(0)
781 if( p_dvbs_tuning_space )
782 p_dvbs_tuning_space->Release();
783 if( p_dvbs_tune_request )
784 p_dvbs_tune_request->Release();
786 p_dvbs_locator->Release();
787 SysFreeString( bstr_input_range );
788 delete pwsz_input_range;
789 free( psz_input_range );
790 free( psz_polarisation );
793 long l_azimuth, l_elevation, l_longitude;
797 BinaryConvolutionCodeRate i_hp_fec = dvb_parse_fec( fec );
798 Polarisation i_polar = dvb_parse_polarization( pol );
799 SpectralInversion i_inversion = dvb_parse_inversion( inversion );
801 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
802 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
803 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
804 l_network_id = var_GetInteger( p_access, "dvb-network-id" );
806 l.psz_input_range = var_GetNonEmptyString( p_access, "dvb-range" );
807 if( asprintf( &l.psz_polarisation, "%c", pol ) == -1 )
810 b_west = ( l_longitude < 0 );
812 l.i_range_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
813 l.psz_input_range, -1, l.pwsz_input_range, 0 );
814 if( l.i_range_len > 0 )
816 l.pwsz_input_range = new WCHAR[l.i_range_len];
817 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
818 l.psz_input_range, -1, l.pwsz_input_range, l.i_range_len );
819 l.bstr_input_range=SysAllocString( l.pwsz_input_range );
822 guid_network_type = CLSID_DVBSNetworkProvider;
823 hr = CreateTuneRequest();
826 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
827 "Cannot create Tune Request: hr=0x%8lx", hr );
831 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
832 (void**)&l.p_dvbs_tune_request );
835 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
836 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
839 l.p_dvbs_tune_request->put_ONID( -1 );
840 l.p_dvbs_tune_request->put_SID( -1 );
841 l.p_dvbs_tune_request->put_TSID( -1 );
843 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
844 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
847 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
848 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
852 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
853 (void**)&l.p_dvbs_tuning_space );
856 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
857 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
862 hr = l.p_dvbs_tuning_space->put_SystemType( DVB_Satellite );
863 if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
864 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
865 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
866 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
867 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
868 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
869 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
870 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
871 if( SUCCEEDED( hr ) && l_network_id > 0 )
872 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
873 if( SUCCEEDED( hr ) && l.i_range_len > 0 )
874 hr = l.p_dvbs_tuning_space->put_InputRange( l.bstr_input_range );
876 if( SUCCEEDED( hr ) && l_frequency > 0 )
877 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
878 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
879 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
880 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
881 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
882 if( SUCCEEDED( hr ) )
883 hr = l.p_dvbs_locator->put_Modulation( BDA_MOD_QPSK );
884 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
885 hr = l.p_dvbs_locator->put_InnerFECRate( i_hp_fec );
887 if( SUCCEEDED( hr ) && l_azimuth > 0 )
888 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
889 if( SUCCEEDED( hr ) && l_elevation > 0 )
890 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
891 if( SUCCEEDED( hr ) )
892 hr = l.p_dvbs_locator->put_WestPosition( b_west );
893 if( SUCCEEDED( hr ) )
894 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
897 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
898 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
902 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
905 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
906 "Cannot put the locator: hr=0x%8lx", hr );
913 /*****************************************************************************
914 * Load the Tuning Space from System Tuning Spaces according to the
915 * Network Type requested
916 ******************************************************************************/
917 HRESULT BDAGraph::CreateTuneRequest()
920 GUID guid_this_network_type;
925 ITuningSpaceContainer* p_tuning_space_container;
926 IEnumTuningSpaces* p_tuning_space_enum;
927 ITuningSpace* p_this_tuning_space;
928 IDVBTuningSpace2* p_dvb_tuning_space;
930 char * psz_network_name;
931 char * psz_create_name;
932 char * psz_bstr_name;
933 WCHAR * wpsz_create_name;
936 localComPtr(): p_tuning_space_container(NULL),
937 p_tuning_space_enum(NULL), p_this_tuning_space(NULL),
938 p_dvb_tuning_space(NULL), bstr_name(NULL),
939 psz_network_name(NULL), psz_create_name(NULL),
940 psz_bstr_name(NULL), wpsz_create_name(NULL), i_name_len(0)
944 if( p_tuning_space_enum )
945 p_tuning_space_enum->Release();
946 if( p_tuning_space_container )
947 p_tuning_space_container->Release();
948 if( p_this_tuning_space )
949 p_this_tuning_space->Release();
950 if( p_dvb_tuning_space )
951 p_dvb_tuning_space->Release();
952 SysFreeString( bstr_name );
953 delete[] psz_bstr_name;
954 delete[] wpsz_create_name;
955 free( psz_network_name );
956 free( psz_create_name );
960 /* We shall test for a specific Tuning space name supplied on the command
961 * line as dvb-networkname=xxx.
962 * For some users with multiple cards and/or multiple networks this could
963 * be useful. This allows us to reasonably safely apply updates to the
964 * System Tuning Space in the registry without disrupting other streams. */
965 l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-network-name" );
966 if( l.psz_network_name )
968 msg_Dbg( p_access, "CreateTuneRequest: Find Tuning Space: %s",
969 l.psz_network_name );
973 l.psz_network_name = new char[1];
974 *l.psz_network_name = '\0';
977 /* A Tuning Space may already have been set up. If it is for the same
978 * network type then all is well. Otherwise, reset the Tuning Space and get
982 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
983 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
984 if( guid_this_network_type == guid_network_type )
986 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
989 msg_Warn( p_access, "CreateTuneRequest: "\
990 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
993 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
994 l.psz_bstr_name, 0, NULL, NULL );
995 l.psz_bstr_name = new char[ l.i_name_len ];
996 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
997 l.psz_bstr_name, l.i_name_len, NULL, NULL );
999 /* Test for a specific Tuning space name supplied on the command
1000 * line as dvb-networkname=xxx */
1001 if( *l.psz_network_name == '\0' ||
1002 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
1004 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
1005 l.psz_network_name );
1009 /* else different guid_network_type */
1010 if( p_tuning_space )
1011 p_tuning_space->Release();
1012 if( p_tune_request )
1013 p_tune_request->Release();
1014 p_tuning_space = NULL;
1015 p_tune_request = NULL;
1018 /* Force use of the first available Tuner Device during Build */
1021 /* Get the SystemTuningSpaces container to enumerate through all the
1022 * defined tuning spaces.
1023 * l.p_tuning_space_container->Refcount = 1 */
1024 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
1025 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
1028 msg_Warn( p_access, "CreateTuneRequest: "\
1029 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
1033 /* Get the SystemTuningSpaces container to enumerate through all the
1034 * defined tuning spaces.
1035 * l.p_tuning_space_container->Refcount = 2
1036 * l.p_tuning_space_enum->Refcount = 1 */
1037 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
1038 &l.p_tuning_space_enum );
1041 msg_Warn( p_access, "CreateTuneRequest: "\
1042 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
1048 /* l.p_this_tuning_space->RefCount = 1 after the first pass
1049 * Release before overwriting with Next */
1050 if( l.p_this_tuning_space )
1051 l.p_this_tuning_space->Release();
1052 l.p_this_tuning_space = NULL;
1053 SysFreeString( l.bstr_name );
1055 hr = l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL );
1056 if( hr != S_OK ) break;
1058 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
1060 /* GUID_NULL means a non-BDA network was found e.g analog
1061 * Ignore failures and non-BDA networks and keep looking */
1062 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
1064 if( guid_this_network_type == guid_network_type )
1066 /* QueryInterface to clone l.p_this_tuning_space
1067 * l.p_this_tuning_space->RefCount = 2 */
1068 hr = l.p_this_tuning_space->Clone( &p_tuning_space );
1071 msg_Warn( p_access, "CreateTuneRequest: "\
1072 "Cannot QI Tuning Space: hr=0x%8lx", hr );
1075 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
1078 msg_Warn( p_access, "CreateTuneRequest: "\
1079 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
1083 /* Test for a specific Tuning space name supplied on the command
1084 * line as dvb-networkname=xxx */
1085 delete[] l.psz_bstr_name;
1086 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1087 l.psz_bstr_name, 0, NULL, NULL );
1088 l.psz_bstr_name = new char[ l.i_name_len ];
1089 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1090 l.psz_bstr_name, l.i_name_len, NULL, NULL );
1091 if( *l.psz_network_name == '\0' ||
1092 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
1094 msg_Dbg( p_access, "CreateTuneRequest: Using Tuning Space: %s",
1097 /* CreateTuneRequest adds TuneRequest to p_tuning_space
1098 * p_tune_request->RefCount = 1 */
1099 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
1101 msg_Warn( p_access, "CreateTuneRequest: "\
1102 "Cannot Create Tune Request: hr=0x%8lx", hr );
1105 if( p_tuning_space )
1106 p_tuning_space->Release();
1107 p_tuning_space = NULL;
1112 /* No tuning space was found. If the create-name parameter was set then
1113 * create a tuning space. By rights should use the same name used in
1115 * Also would be nice to copy a tuning space but we only come here if we do
1117 l.psz_create_name = var_GetNonEmptyString( p_access, "dvb-create-name" );
1118 if( !l.psz_create_name || strlen( l.psz_create_name ) <= 0 )
1121 msg_Warn( p_access, "CreateTuneRequest: "\
1122 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
1125 if( strcmp( l.psz_create_name, l.psz_network_name ) )
1128 msg_Warn( p_access, "CreateTuneRequest: "\
1129 "dvb-create-name %s must match dvb-network-name %s",
1130 l.psz_create_name, l.psz_network_name );
1134 /* Need to use DVBSTuningSpace for DVB-S and ATSCTuningSpace for ATSC */
1136 CLSID cls_tuning_space;
1138 if( IsEqualCLSID( guid_network_type, CLSID_ATSCNetworkProvider ) )
1139 cls_tuning_space = CLSID_ATSCTuningSpace;
1140 if( IsEqualCLSID( guid_network_type, CLSID_DVBTNetworkProvider ) )
1141 cls_tuning_space = CLSID_DVBTuningSpace;
1142 if( IsEqualCLSID( guid_network_type, CLSID_DVBCNetworkProvider ) )
1143 cls_tuning_space = CLSID_DVBTuningSpace;
1144 if( IsEqualCLSID( guid_network_type, CLSID_DVBSNetworkProvider ) )
1145 cls_tuning_space = CLSID_DVBSTuningSpace;
1147 l.i_name_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
1148 l.psz_create_name, -1, l.wpsz_create_name, 0 );
1149 if( l.i_name_len <= 0 )
1152 msg_Warn( p_access, "CreateTuneRequest: "\
1153 "Cannot convert zero length dvb-create-name %s",
1154 l.psz_create_name );
1157 l.wpsz_create_name = new WCHAR[l.i_name_len];
1158 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, l.psz_create_name, -1,
1159 l.wpsz_create_name, l.i_name_len );
1161 SysFreeString( l.bstr_name );
1162 l.bstr_name = SysAllocString( l.wpsz_create_name );
1164 msg_Dbg( p_access, "CreateTuneRequest: Create Tuning Space: %s",
1165 l.psz_create_name );
1167 hr = ::CoCreateInstance( cls_tuning_space, 0, CLSCTX_INPROC,
1168 IID_ITuningSpace, (void**)&p_tuning_space );
1171 msg_Warn( p_access, "CreateTuneRequest: "\
1172 "Cannot CoCreate new TuningSpace: hr=0x%8lx", hr );
1173 if( SUCCEEDED( hr ) )
1174 hr = p_tuning_space->put__NetworkType( guid_network_type );
1176 msg_Warn( p_access, "CreateTuneRequest: "\
1177 "Cannot Put Network Type: hr=0x%8lx", hr );
1178 if( SUCCEEDED( hr ) )
1179 hr = p_tuning_space->put_UniqueName( l.bstr_name );
1181 msg_Warn( p_access, "CreateTuneRequest: "\
1182 "Cannot Put Unique Name: hr=0x%8lx", hr );
1183 if( SUCCEEDED( hr ) )
1184 hr = p_tuning_space->put_FriendlyName( l.bstr_name );
1186 msg_Warn( p_access, "CreateTuneRequest: "\
1187 "Cannot Put Friendly Name: hr=0x%8lx", hr );
1188 if( guid_network_type == CLSID_DVBTNetworkProvider ||
1189 guid_network_type == CLSID_DVBCNetworkProvider ||
1190 guid_network_type == CLSID_DVBSNetworkProvider )
1192 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
1193 (void**)&l.p_dvb_tuning_space );
1196 msg_Warn( p_access, "CreateTuneRequest: "\
1197 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
1200 if( guid_network_type == CLSID_DVBTNetworkProvider )
1201 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
1202 if( guid_network_type == CLSID_DVBCNetworkProvider )
1203 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
1204 if( guid_network_type == CLSID_DVBSNetworkProvider )
1205 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Satellite );
1208 if( SUCCEEDED( hr ) )
1209 hr = l.p_tuning_space_container->Add( p_tuning_space, &var_id );
1213 msg_Warn( p_access, "CreateTuneRequest: "\
1214 "Cannot Create new TuningSpace: hr=0x%8lx", hr );
1218 msg_Dbg( p_access, "CreateTuneRequest: Tuning Space: %s created",
1219 l.psz_create_name );
1221 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
1223 msg_Warn( p_access, "CreateTuneRequest: "\
1224 "Cannot Create Tune Request: hr=0x%8lx", hr );
1229 /******************************************************************************
1231 * Step 4: Build the Filter Graph
1232 * Build sets up devices, adds and connects filters
1233 ******************************************************************************/
1234 HRESULT BDAGraph::Build()
1237 long l_capture_used, l_tif_used;
1238 VARIANT l_tuning_space_id;
1239 AM_MEDIA_TYPE grabber_media_type;
1243 ITuningSpaceContainer* p_tuning_space_container;
1244 localComPtr(): p_tuning_space_container(NULL) {};
1247 if( p_tuning_space_container )
1248 p_tuning_space_container->Release();
1252 /* Get the SystemTuningSpaces container to save the Tuning space */
1253 l_tuning_space_id.vt = VT_I4;
1254 l_tuning_space_id.lVal = 0L;
1255 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
1256 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
1259 msg_Warn( p_access, "Build: "\
1260 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
1263 hr = l.p_tuning_space_container->FindID( p_tuning_space,
1264 &l_tuning_space_id.lVal );
1267 msg_Warn( p_access, "Build: "\
1268 "Cannot Find Tuning Space ID: hr=0x%8lx", hr );
1271 msg_Dbg( p_access, "Build: Using Tuning Space ID %ld",
1272 l_tuning_space_id.lVal );
1273 hr = l.p_tuning_space_container->put_Item( l_tuning_space_id,
1277 msg_Warn( p_access, "Build: "\
1278 "Cannot save Tuning Space: hr=0x%8lx (ignored)", hr );
1281 /* If we have already have a filter graph, rebuild it*/
1284 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1285 IID_IGraphBuilder, (void**)&p_filter_graph );
1288 msg_Warn( p_access, "Build: "\
1289 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
1293 /* First filter in the graph is the Network Provider and
1294 * its Scanning Tuner which takes the Tune Request
1295 * Try to build the Win 7 Universal Network Provider first*/
1296 hr = ::CoCreateInstance( CLSID_NetworkProvider, NULL, CLSCTX_INPROC_SERVER,
1297 IID_IBaseFilter, (void**)&p_network_provider);
1300 msg_Warn( p_access, "Build: "\
1301 "Cannot CoCreate the Universal Network Provider, trying the old way...");
1302 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
1303 IID_IBaseFilter, (void**)&p_network_provider);
1306 msg_Warn( p_access, "Build: "\
1307 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
1311 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
1314 msg_Warn( p_access, "Build: "\
1315 "Cannot load network provider: hr=0x%8lx", hr );
1319 /* Add the Network Tuner to the Network Provider. On subsequent calls,
1320 * l_tuner_used will cause a different tuner to be selected
1321 * To select a specific device first get the parameter that nominates the
1322 * device (dvb-adapter) and use the value to initialise l_tuner_used.
1323 * When FindFilter returns check the contents of l_tuner_used.
1324 * If it is not what was selected then the requested device was not
1325 * available so return with an error. */
1327 long l_adapter = -1;
1328 l_adapter = var_GetInteger( p_access, "dvb-adapter" );
1329 if( l_tuner_used < 0 && l_adapter >= 0 )
1330 l_tuner_used = l_adapter - 1;
1332 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
1333 p_network_provider, &p_tuner_device );
1336 msg_Warn( p_access, "Build: "\
1337 "Cannot load tuner device and connect network provider: "\
1341 if( l_adapter > 0 && l_tuner_used != l_adapter )
1343 msg_Warn( p_access, "Build: "\
1344 "Tuner device %ld is not available", l_adapter );
1347 msg_Dbg( p_access, "BDAGraph: Using adapter %ld", l_tuner_used );
1349 /* VLC 1.0 works reliably up this point then crashes
1350 * Obvious candidate is FindFilter */
1351 /* Always look for all capture devices to match the Network Tuner */
1352 l_capture_used = -1;
1353 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
1354 p_tuner_device, &p_capture_device );
1357 /* Some BDA drivers do not provide a Capture Device Filter so force
1358 * the Sample Grabber to connect directly to the Tuner Device */
1359 p_capture_device = p_tuner_device;
1360 p_tuner_device = NULL;
1361 msg_Warn( p_access, "Build: "\
1362 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
1365 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
1366 (void**)&p_scanning_tuner );
1369 msg_Warn( p_access, "Build: "\
1370 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
1374 hr = p_scanning_tuner->Validate( p_tune_request );
1377 msg_Warn( p_access, "Build: "\
1378 "Tune Request is invalid: hr=0x%8lx", hr );
1379 //return hr; it is not mandatory to validate. Validate fails, but the request is successfully accepted
1381 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
1384 msg_Warn( p_access, "Build: "\
1385 "Cannot submit the tune request: hr=0x%8lx", hr );
1389 if( p_sample_grabber )
1390 p_sample_grabber->Release();
1391 p_sample_grabber = NULL;
1392 /* Insert the Sample Grabber to tap into the Transport Stream. */
1393 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
1394 IID_IBaseFilter, (void**)&p_sample_grabber );
1397 msg_Warn( p_access, "Build: "\
1398 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
1401 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
1404 msg_Warn( p_access, "Build: "\
1405 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
1410 p_grabber->Release();
1412 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
1413 (void**)&p_grabber );
1416 msg_Warn( p_access, "Build: "\
1417 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
1421 /* Try the possible stream type */
1423 for( int i = 0; i < 2; i++ )
1425 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
1426 grabber_media_type.majortype = MEDIATYPE_Stream;
1427 grabber_media_type.subtype = i == 0 ? MEDIASUBTYPE_MPEG2_TRANSPORT : KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT;
1428 msg_Dbg( p_access, "Build: "
1429 "Trying connecting with subtype %s",
1430 i == 0 ? "MEDIASUBTYPE_MPEG2_TRANSPORT" : "KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT" );
1431 hr = p_grabber->SetMediaType( &grabber_media_type );
1432 if( SUCCEEDED( hr ) )
1434 hr = Connect( p_capture_device, p_sample_grabber );
1435 if( SUCCEEDED( hr ) )
1437 msg_Warn( p_access, "Build: "\
1438 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr, 1+i );
1442 msg_Warn( p_access, "Build: "\
1443 "Cannot set media type on grabber filter: hr=0x%8lx (try %d/2", hr, 1+i );
1449 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
1450 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
1451 * the Network Provider filter to set up the stream */
1452 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
1453 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
1456 msg_Warn( p_access, "Build: "\
1457 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
1460 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
1463 msg_Warn( p_access, "Build: "\
1464 "Cannot add demux filter to graph: hr=0x%8lx", hr );
1467 hr = Connect( p_sample_grabber, p_mpeg_demux );
1470 msg_Warn( p_access, "Build: "\
1471 "Cannot connect demux to grabber: hr=0x%8lx", hr );
1475 /* Always look for the Transform Information Filter from the start
1476 * of the collection*/
1478 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
1479 p_mpeg_demux, &p_transport_info );
1482 msg_Warn( p_access, "Build: "\
1483 "Cannot load TIF onto demux: hr=0x%8lx", hr );
1486 /* Configure the Sample Grabber to buffer the samples continuously */
1487 hr = p_grabber->SetBufferSamples( true );
1490 msg_Warn( p_access, "Build: "\
1491 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
1494 hr = p_grabber->SetOneShot( false );
1497 msg_Warn( p_access, "Build: "\
1498 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
1501 hr = p_grabber->SetCallback( this, 0 );
1504 msg_Warn( p_access, "Build: "\
1505 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
1512 d_graph_register = 0;
1515 /* The Media Control is used to Run and Stop the Graph */
1516 if( p_media_control )
1517 p_media_control->Release();
1518 p_media_control = NULL;
1519 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
1520 (void**)&p_media_control );
1523 msg_Warn( p_access, "Build: "\
1524 "Cannot QI Media Control: hr=0x%8lx", hr );
1532 /******************************************************************************
1534 * Looks up all filters in a category and connects to the upstream filter until
1535 * a successful match is found. The index of the connected filter is returned.
1536 * On subsequent calls, this can be used to start from that point to find
1538 * This is used when the graph does not run because a tuner device is in use so
1539 * another one needs to be selected.
1540 ******************************************************************************/
1541 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
1542 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
1545 int i_moniker_index = -1;
1549 IMoniker* p_moniker;
1550 IEnumMoniker* p_moniker_enum;
1551 IBaseFilter* p_filter;
1552 IPropertyBag* p_property_bag;
1558 p_moniker_enum(NULL),
1560 p_property_bag(NULL),
1562 { ::VariantInit(&var_bstr); };
1565 if( p_property_bag )
1566 p_property_bag->Release();
1568 p_filter->Release();
1570 p_moniker->Release();
1571 if( p_moniker_enum )
1572 p_moniker_enum->Release();
1573 ::VariantClear(&var_bstr);
1578 if( !p_system_dev_enum )
1580 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1581 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1584 msg_Warn( p_access, "FindFilter: "\
1585 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1590 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1591 &l.p_moniker_enum, 0 );
1594 msg_Warn( p_access, "FindFilter: "\
1595 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1601 /* We are overwriting l.p_moniker so we should Release and nullify
1602 * It is important that p_moniker and p_property_bag are fully released
1603 * l.p_filter may not be dereferenced so we could force to NULL */
1604 if( l.p_property_bag )
1605 l.p_property_bag->Release();
1606 l.p_property_bag = NULL;
1608 l.p_filter->Release();
1611 l.p_moniker->Release();
1614 hr = l.p_moniker_enum->Next( 1, &l.p_moniker, 0 );
1615 if( hr != S_OK ) break;
1618 /* Skip over devices already found on previous calls */
1619 if( i_moniker_index <= *i_moniker_used ) continue;
1620 *i_moniker_used = i_moniker_index;
1622 /* l.p_filter is Released at the top of the loop */
1623 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1624 (void**)&l.p_filter );
1629 /* l.p_property_bag is released at the top of the loop */
1630 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1631 (void**)&l.p_property_bag );
1634 msg_Warn( p_access, "FindFilter: "\
1635 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1638 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1641 msg_Warn( p_access, "FindFilter: "\
1642 "Cannot read filter friendly name: hr=0x%8lx", hr );
1646 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1649 msg_Warn( p_access, "FindFilter: "\
1650 "Cannot add filter: hr=0x%8lx", hr );
1653 hr = Connect( p_upstream, l.p_filter );
1654 if( SUCCEEDED( hr ) )
1656 /* p_p_downstream has not been touched yet so no release needed */
1657 delete[] l.psz_bstr;
1658 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1659 l.var_bstr.bstrVal, -1, l.psz_bstr, 0, NULL, NULL );
1660 l.psz_bstr = new char[l.i_bstr_len];
1661 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0,
1662 l.var_bstr.bstrVal, -1, l.psz_bstr, l.i_bstr_len, NULL, NULL );
1663 msg_Dbg( p_access, "FindFilter: Connected %s", l.psz_bstr );
1664 l.p_filter->QueryInterface( IID_IBaseFilter,
1665 (void**)p_p_downstream );
1668 /* Not the filter we want so unload and try the next one */
1669 hr = p_filter_graph->RemoveFilter( l.p_filter );
1672 msg_Warn( p_access, "FindFilter: "\
1673 "Failed unloading Filter: hr=0x%8lx", hr );
1681 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1685 /*****************************************************************************
1686 * Connect is called from Build to enumerate and connect pins
1687 *****************************************************************************/
1688 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1690 HRESULT hr = E_FAIL;
1694 IPin* p_pin_upstream;
1695 IPin* p_pin_downstream;
1696 IEnumPins* p_pin_upstream_enum;
1697 IEnumPins* p_pin_downstream_enum;
1699 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1700 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1701 p_pin_temp(NULL) { };
1705 p_pin_temp->Release();
1706 if( p_pin_downstream )
1707 p_pin_downstream->Release();
1708 if( p_pin_upstream )
1709 p_pin_upstream->Release();
1710 if( p_pin_downstream_enum )
1711 p_pin_downstream_enum->Release();
1712 if( p_pin_upstream_enum )
1713 p_pin_upstream_enum->Release();
1717 PIN_DIRECTION pin_dir;
1719 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1722 msg_Warn( p_access, "Connect: "\
1723 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1729 /* Release l.p_pin_upstream before next iteration */
1730 if( l.p_pin_upstream )
1731 l.p_pin_upstream ->Release();
1732 l.p_pin_upstream = NULL;
1733 hr = l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 );
1734 if( hr != S_OK ) break;
1736 hr = l.p_pin_upstream->QueryDirection( &pin_dir );
1739 msg_Warn( p_access, "Connect: "\
1740 "Cannot get upstream filter pin direction: hr=0x%8lx", hr );
1743 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1744 if( SUCCEEDED( hr ) )
1746 l.p_pin_downstream->Release();
1747 l.p_pin_downstream = NULL;
1749 if( FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1751 msg_Warn( p_access, "Connect: "\
1752 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1755 if( ( pin_dir == PINDIR_OUTPUT ) && ( hr == VFW_E_NOT_CONNECTED ) )
1757 /* The upstream pin is not yet connected so check each pin on the
1758 * downstream filter */
1759 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1762 msg_Warn( p_access, "Connect: Cannot get "\
1763 "downstream filter enumerator: hr=0x%8lx", hr );
1768 /* Release l.p_pin_downstream before next iteration */
1769 if( l.p_pin_downstream )
1770 l.p_pin_downstream ->Release();
1771 l.p_pin_downstream = NULL;
1773 hr = l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 );
1774 if( hr != S_OK ) break;
1776 hr = l.p_pin_downstream->QueryDirection( &pin_dir );
1779 msg_Warn( p_access, "Connect: Cannot get "\
1780 "downstream filter pin direction: hr=0x%8lx", hr );
1784 /* Looking for a free Pin to connect to
1785 * A connected Pin may have an reference count > 1
1786 * so Release and nullify the pointer */
1787 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1788 if( SUCCEEDED( hr ) )
1790 l.p_pin_temp->Release();
1791 l.p_pin_temp = NULL;
1793 if( hr != VFW_E_NOT_CONNECTED )
1797 msg_Warn( p_access, "Connect: Cannot check "\
1798 "downstream filter connection: hr=0x%8lx", hr );
1802 if( ( pin_dir == PINDIR_INPUT ) &&
1803 ( hr == VFW_E_NOT_CONNECTED ) )
1805 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1806 l.p_pin_downstream, NULL );
1807 if( SUCCEEDED( hr ) )
1809 /* If we arrive here then we have a matching pair of
1814 /* If we arrive here it means this downstream pin is not
1815 * suitable so try the next downstream pin.
1816 * l.p_pin_downstream is released at the top of the loop */
1819 /* If we arrive here then we ran out of pins before we found a
1820 * suitable one. Release outstanding refcounts */
1821 if( l.p_pin_downstream_enum )
1822 l.p_pin_downstream_enum->Release();
1823 l.p_pin_downstream_enum = NULL;
1824 if( l.p_pin_downstream )
1825 l.p_pin_downstream->Release();
1826 l.p_pin_downstream = NULL;
1828 /* If we arrive here it means this upstream pin is not suitable
1829 * so try the next upstream pin
1830 * l.p_pin_upstream is released at the top of the loop */
1833 /* If we arrive here it means we did not find any pair of suitable pins
1834 * Outstanding refcounts are released in the destructor */
1838 /*****************************************************************************
1839 * Start uses MediaControl to start the graph
1840 *****************************************************************************/
1841 HRESULT BDAGraph::Start()
1844 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1846 if( !p_media_control )
1848 msg_Dbg( p_access, "Start: Media Control has not been created" );
1851 hr = p_media_control->Run();
1852 msg_Dbg( p_access, "Graph started hr=0x%lx", hr );
1856 /* Query the state of the graph - timeout after 100 milliseconds */
1857 while( (hr = p_media_control->GetState( 100, &i_state )) != S_OK )
1862 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1866 if( i_state == State_Running )
1869 /* The Graph is not running so stop it and return an error */
1870 msg_Warn( p_access, "Start: Graph not started: %d", (int)i_state );
1871 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
1875 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1881 /*****************************************************************************
1882 * Pop the stream of data
1883 *****************************************************************************/
1884 ssize_t BDAGraph::Pop(void *buf, size_t len)
1886 return output.Pop(buf, len);
1889 /******************************************************************************
1890 * SampleCB - Callback when the Sample Grabber has a sample
1891 ******************************************************************************/
1892 STDMETHODIMP BDAGraph::SampleCB( double /*date*/, IMediaSample *p_sample )
1894 if( p_sample->IsDiscontinuity() == S_OK )
1895 msg_Warn( p_access, "BDA SampleCB: Sample Discontinuity.");
1897 const size_t i_sample_size = p_sample->GetActualDataLength();
1898 BYTE *p_sample_data;
1899 p_sample->GetPointer( &p_sample_data );
1901 if( i_sample_size > 0 && p_sample_data )
1903 block_t *p_block = block_New( p_access, i_sample_size );
1907 memcpy( p_block->p_buffer, p_sample_data, i_sample_size );
1908 output.Push( p_block );
1914 STDMETHODIMP BDAGraph::BufferCB( double /*date*/, BYTE* /*buffer*/,
1915 long /*buffer_len*/ )
1920 /******************************************************************************
1921 * removes each filter from the graph
1922 ******************************************************************************/
1923 HRESULT BDAGraph::Destroy()
1925 if( p_media_control )
1926 p_media_control->StopWhenReady(); /* Instead of Stop() */
1928 if( d_graph_register )
1937 p_grabber->Release();
1941 if( p_transport_info )
1943 p_filter_graph->RemoveFilter( p_transport_info );
1944 p_transport_info->Release();
1945 p_transport_info = NULL;
1949 p_filter_graph->RemoveFilter( p_mpeg_demux );
1950 p_mpeg_demux->Release();
1951 p_mpeg_demux = NULL;
1953 if( p_sample_grabber )
1955 p_filter_graph->RemoveFilter( p_sample_grabber );
1956 p_sample_grabber->Release();
1957 p_sample_grabber = NULL;
1959 if( p_capture_device )
1961 p_filter_graph->RemoveFilter( p_capture_device );
1962 p_capture_device->Release();
1963 p_capture_device = NULL;
1965 if( p_tuner_device )
1967 p_filter_graph->RemoveFilter( p_tuner_device );
1968 p_tuner_device->Release();
1969 p_tuner_device = NULL;
1971 if( p_scanning_tuner )
1973 p_scanning_tuner->Release();
1974 p_scanning_tuner = NULL;
1976 if( p_network_provider )
1978 p_filter_graph->RemoveFilter( p_network_provider );
1979 p_network_provider->Release();
1980 p_network_provider = NULL;
1983 if( p_media_control )
1985 p_media_control->Release();
1986 p_media_control = NULL;
1988 if( p_filter_graph )
1990 p_filter_graph->Release();
1991 p_filter_graph = NULL;
1993 if( p_system_dev_enum )
1995 p_system_dev_enum->Release();
1996 p_system_dev_enum = NULL;
2002 /*****************************************************************************
2003 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
2004 * Allows GraphEdit to "spy" on a remote filter graph.
2005 ******************************************************************************/
2006 HRESULT BDAGraph::Register()
2011 IMoniker* p_moniker;
2012 IRunningObjectTable* p_ro_table;
2013 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
2017 p_moniker->Release();
2019 p_ro_table->Release();
2022 WCHAR psz_w_graph_name[128];
2025 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
2028 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
2032 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
2033 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
2034 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
2037 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
2040 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
2041 p_filter_graph, l.p_moniker, &d_graph_register );
2044 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
2047 // msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
2051 void BDAGraph::Deregister()
2054 IRunningObjectTable* p_ro_table;
2055 hr = ::GetRunningObjectTable( 0, &p_ro_table );
2056 if( SUCCEEDED( hr ) )
2057 p_ro_table->Revoke( d_graph_register );
2058 d_graph_register = 0;
2059 p_ro_table->Release();