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
6 * Copyright (C) 2012 John Freed
8 * Author: Ken Self <kenself(at)optusnet(dot)com(dot)au>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_block.h>
36 #include "dtv/bdagraph.hpp"
38 #undef DEBUG_MONIKER_NAME
40 static ModulationType
dvb_parse_modulation (const char *mod
)
42 if (!strcmp (mod
, "16QAM")) return BDA_MOD_16QAM
;
43 if (!strcmp (mod
, "32QAM")) return BDA_MOD_32QAM
;
44 if (!strcmp (mod
, "64QAM")) return BDA_MOD_64QAM
;
45 if (!strcmp (mod
, "128QAM")) return BDA_MOD_128QAM
;
46 if (!strcmp (mod
, "256QAM")) return BDA_MOD_256QAM
;
47 return BDA_MOD_NOT_SET
;
50 static BinaryConvolutionCodeRate
dvb_parse_fec (uint32_t fec
)
54 case VLC_FEC(1,2): return BDA_BCC_RATE_1_2
;
55 case VLC_FEC(2,3): return BDA_BCC_RATE_2_3
;
56 case VLC_FEC(3,4): return BDA_BCC_RATE_3_4
;
57 case VLC_FEC(5,6): return BDA_BCC_RATE_5_6
;
58 case VLC_FEC(7,8): return BDA_BCC_RATE_7_8
;
60 return BDA_BCC_RATE_NOT_SET
;
63 static GuardInterval
dvb_parse_guard (uint32_t guard
)
67 case VLC_GUARD(1, 4): return BDA_GUARD_1_4
;
68 case VLC_GUARD(1, 8): return BDA_GUARD_1_8
;
69 case VLC_GUARD(1,16): return BDA_GUARD_1_16
;
70 case VLC_GUARD(1,32): return BDA_GUARD_1_32
;
72 return BDA_GUARD_NOT_SET
;
75 static TransmissionMode
dvb_parse_transmission (int transmit
)
79 case 2: return BDA_XMIT_MODE_2K
;
80 case 8: return BDA_XMIT_MODE_8K
;
82 return BDA_XMIT_MODE_NOT_SET
;
85 static HierarchyAlpha
dvb_parse_hierarchy (int hierarchy
)
89 case 1: return BDA_HALPHA_1
;
90 case 2: return BDA_HALPHA_2
;
91 case 4: return BDA_HALPHA_4
;
93 return BDA_HALPHA_NOT_SET
;
96 static Polarisation
dvb_parse_polarization (char pol
)
100 case 'H': return BDA_POLARISATION_LINEAR_H
;
101 case 'V': return BDA_POLARISATION_LINEAR_V
;
102 case 'L': return BDA_POLARISATION_CIRCULAR_L
;
103 case 'R': return BDA_POLARISATION_CIRCULAR_R
;
105 return BDA_POLARISATION_NOT_SET
;
108 static SpectralInversion
dvb_parse_inversion (int inversion
)
112 case 0: return BDA_SPECTRAL_INVERSION_NORMAL
;
113 case 1: return BDA_SPECTRAL_INVERSION_INVERTED
;
114 case -1: return BDA_SPECTRAL_INVERSION_AUTOMATIC
;
116 /* should never happen */
117 return BDA_SPECTRAL_INVERSION_NOT_SET
;
120 /****************************************************************************
121 * Interfaces for calls from C
122 ****************************************************************************/
127 /* DVB-S property cache */
133 uint32_t lowf
, highf
, switchf
;
136 dvb_device_t
*dvb_open (vlc_object_t
*obj
)
138 dvb_device_t
*d
= new dvb_device_t
;
140 d
->module
= new BDAGraph (obj
);
143 d
->fec
= VLC_FEC_AUTO
;
146 d
->lowf
= d
->highf
= d
->switchf
= 0;
150 void dvb_close (dvb_device_t
*d
)
152 ComContext
ctx( COINIT_APARTMENTTHREADED
);
157 ssize_t
dvb_read (dvb_device_t
*d
, void *buf
, size_t len
, int ms
)
159 return d
->module
->Pop(buf
, len
, ms
);
162 int dvb_add_pid (dvb_device_t
*, uint16_t)
167 void dvb_remove_pid (dvb_device_t
*, uint16_t)
171 bool dvb_get_pid_state (const dvb_device_t
*, uint16_t)
176 unsigned dvb_enum_systems (dvb_device_t
*d
)
178 ComContext
ctx( COINIT_APARTMENTTHREADED
);
179 return d
->module
->EnumSystems( );
182 float dvb_get_signal_strength (dvb_device_t
*d
)
184 ComContext
ctx( COINIT_APARTMENTTHREADED
);
185 return d
->module
->GetSignalStrength( );
188 float dvb_get_snr (dvb_device_t
*d
)
190 ComContext
ctx( COINIT_APARTMENTTHREADED
);
191 return d
->module
->GetSignalNoiseRatio( );
194 int dvb_set_inversion (dvb_device_t
*d
, int inversion
)
196 ComContext
ctx( COINIT_APARTMENTTHREADED
);
197 d
->inversion
= inversion
;
198 return d
->module
->SetInversion( d
->inversion
);
201 int dvb_tune (dvb_device_t
*d
)
203 ComContext
ctx( COINIT_APARTMENTTHREADED
);
204 return d
->module
->SubmitTuneRequest ();
207 int dvb_fill_device_caps( dvb_device_t
*, dvb_device_caps_t
* )
213 bool dvb_set_ca_pmt (dvb_device_t
*, en50221_capmt_info_t
*)
219 int dvb_set_dvbc (dvb_device_t
*d
, uint32_t freq
, const char *mod
,
220 uint32_t srate
, uint32_t /*fec*/)
222 ComContext
ctx( COINIT_APARTMENTTHREADED
);
223 return d
->module
->SetDVBC (freq
/ 1000, mod
, srate
);
227 int dvb_set_dvbs (dvb_device_t
*d
, uint64_t freq
, uint32_t srate
, uint32_t fec
)
229 ComContext
ctx( COINIT_APARTMENTTHREADED
);
230 d
->frequency
= freq
/ 1000;
233 return d
->module
->SetDVBS(d
->frequency
, d
->srate
, d
->fec
, d
->inversion
,
234 d
->pol
, d
->lowf
, d
->highf
, d
->switchf
);
237 int dvb_set_dvbs2 (dvb_device_t
*, uint64_t /*freq*/, const char * /*mod*/,
238 uint32_t /*srate*/, uint32_t /*fec*/, int /*pilot*/, int /*rolloff*/,
244 int dvb_set_sec (dvb_device_t
*d
, uint64_t freq
, char pol
,
245 uint32_t lowf
, uint32_t highf
, uint32_t switchf
)
247 ComContext
ctx( COINIT_APARTMENTTHREADED
);
248 d
->frequency
= freq
/ 1000;
252 d
->switchf
= switchf
;
253 return d
->module
->SetDVBS(d
->frequency
, d
->srate
, d
->fec
, d
->inversion
,
254 d
->pol
, d
->lowf
, d
->highf
, d
->switchf
);
258 int dvb_set_dvbt (dvb_device_t
*d
, uint32_t freq
, const char * /*mod*/,
259 uint32_t fec_hp
, uint32_t fec_lp
, uint32_t bandwidth
,
260 int transmission
, uint32_t guard
, int hierarchy
)
262 ComContext
ctx( COINIT_APARTMENTTHREADED
);
263 return d
->module
->SetDVBT(freq
/ 1000, fec_hp
, fec_lp
,
264 bandwidth
, transmission
, guard
, hierarchy
);
268 int dvb_set_dvbt2 (dvb_device_t
*d
, uint32_t freq
, const char * /*mod*/,
269 uint32_t fec
, uint32_t bandwidth
, int transmission
,
270 uint32_t guard
, uint8_t plp
)
272 ComContext
ctx( COINIT_APARTMENTTHREADED
);
273 return d
->module
->SetDVBT2(freq
/ 1000, fec
,
274 bandwidth
, transmission
, guard
, plp
);
278 int dvb_set_isdbc (dvb_device_t
*, uint32_t /*freq*/, const char * /*mod*/,
279 uint32_t /*srate*/, uint32_t /*fec*/)
285 int dvb_set_isdbs (dvb_device_t
*, uint64_t /*freq*/, uint16_t /*ts_id*/)
291 int dvb_set_isdbt (dvb_device_t
*, uint32_t /*freq*/, uint32_t /*bandwidth*/,
292 int /*transmit_mode*/, uint32_t /*guard*/,
293 const isdbt_layer_t
/*layers*/[3])
299 int dvb_set_atsc (dvb_device_t
*d
, uint32_t freq
, const char * /*mod*/)
301 ComContext
ctx( COINIT_APARTMENTTHREADED
);
302 return d
->module
->SetATSC(freq
/ 1000);
305 int dvb_set_cqam (dvb_device_t
*d
, uint32_t freq
, const char * /*mod*/)
307 ComContext
ctx( COINIT_APARTMENTTHREADED
);
308 return d
->module
->SetCQAM(freq
/ 1000);
311 /*****************************************************************************
313 *****************************************************************************/
314 BDAOutput::BDAOutput( vlc_object_t
*p_access
) :
315 p_access(p_access
), p_first(NULL
), pp_next(&p_first
)
317 vlc_mutex_init( &lock
);
318 vlc_cond_init( &wait
);
321 BDAOutput::~BDAOutput()
324 vlc_mutex_destroy( &lock
);
325 vlc_cond_destroy( &wait
);
328 void BDAOutput::Push( block_t
*p_block
)
330 vlc_mutex_locker
l( &lock
);
332 block_ChainLastAppend( &pp_next
, p_block
);
333 vlc_cond_signal( &wait
);
336 ssize_t
BDAOutput::Pop(void *buf
, size_t len
, int ms
)
341 vlc_mutex_locker
l( &lock
);
343 mtime_t i_deadline
= mdate() + ms
* 1000;
346 if( vlc_cond_timedwait( &wait
, &lock
, i_deadline
) )
351 while( i_index
< len
)
353 size_t i_copy
= __MIN( len
- i_index
, p_first
->i_buffer
);
354 memcpy( (uint8_t *)buf
+ i_index
, p_first
->p_buffer
, i_copy
);
358 p_first
->p_buffer
+= i_copy
;
359 p_first
->i_buffer
-= i_copy
;
361 if( p_first
->i_buffer
<= 0 )
363 block_t
*p_next
= p_first
->p_next
;
364 block_Release( p_first
);
377 void BDAOutput::Empty()
379 vlc_mutex_locker
l( &lock
);
382 block_ChainRelease( p_first
);
387 /*****************************************************************************
389 *****************************************************************************/
390 BDAGraph::BDAGraph( vlc_object_t
*p_this
):
393 guid_network_type(GUID_NULL
),
396 d_graph_register( 0 ),
399 p_media_control
= NULL
;
401 p_tuning_space
= NULL
;
403 p_filter_graph
= NULL
;
404 p_system_dev_enum
= NULL
;
405 p_network_provider
= p_tuner_device
= p_capture_device
= NULL
;
406 p_sample_grabber
= p_mpeg_demux
= p_transport_info
= NULL
;
407 p_scanning_tuner
= NULL
;
411 /*****************************************************************************
413 *****************************************************************************/
414 BDAGraph::~BDAGraph()
419 p_tuning_space
->Release();
420 p_tuning_space
= NULL
;
425 /*****************************************************************************
428 *****************************************************************************/
429 unsigned BDAGraph::GetSystem( REFCLSID clsid
)
433 if( clsid
== CLSID_DVBTNetworkProvider
)
434 sys
= DTV_DELIVERY_DVB_T
;
435 if( clsid
== CLSID_DVBCNetworkProvider
)
436 sys
= DTV_DELIVERY_DVB_C
;
437 if( clsid
== CLSID_DVBSNetworkProvider
)
438 sys
= DTV_DELIVERY_DVB_S
;
439 if( clsid
== CLSID_ATSCNetworkProvider
)
440 sys
= DTV_DELIVERY_ATSC
;
441 if( clsid
== CLSID_DigitalCableNetworkType
)
442 sys
= DTV_DELIVERY_CQAM
;
448 /*****************************************************************************
450 *****************************************************************************
451 * here is logic for special case where user uses an MRL that points
452 * to DTV but is not fully specific. This is usually dvb:// and can come
453 * either from a playlist, a channels.conf MythTV file, or from manual entry.
455 * Since this is done before the real tune request is submitted, we can
456 * use the global device enumerator, etc., so long as we do a Destroy() at
458 *****************************************************************************/
459 unsigned BDAGraph::EnumSystems()
462 GUID guid_network_provider
= GUID_NULL
;
464 msg_Dbg( p_access
, "EnumSystems: Entering " );
468 hr
= GetNextNetworkType( &guid_network_provider
);
469 if( hr
!= S_OK
) break;
470 hr
= Check( guid_network_provider
);
472 msg_Dbg( p_access
, "EnumSystems: Check failed, trying next" );
478 msg_Dbg( p_access
, "EnumSystems: Returning systems 0x%08x", systems
);
482 float BDAGraph::GetSignalNoiseRatio(void)
484 /* not implemented until Windows 7
485 * IBDA_Encoder::GetState */
489 float BDAGraph::GetSignalStrength(void)
493 msg_Dbg( p_access
, "GetSignalStrength: entering" );
494 if( !p_scanning_tuner
)
496 hr
= p_scanning_tuner
->get_SignalStrength( &l_strength
);
499 msg_Warn( p_access
, "GetSignalStrength: "
500 "Cannot get value: hr=0x%8lx", hr
);
503 msg_Dbg( p_access
, "GetSignalStrength: got %ld", l_strength
);
504 if( l_strength
== -1 )
506 return l_strength
/ 100.;
509 int BDAGraph::SubmitTuneRequest(void)
514 /* Build and Start the Graph. If a Tuner device is in use the graph will
515 * fail to start. Repeated calls to Build will check successive tuner
519 msg_Dbg( p_access
, "SubmitTuneRequest: Building the Graph" );
524 msg_Warn( p_access
, "SubmitTuneRequest: "
525 "Cannot Build the Graph: hr=0x%8lx", hr
);
528 msg_Dbg( p_access
, "SubmitTuneRequest: Starting the Graph" );
533 msg_Dbg( p_access
, "SubmitTuneRequest: "
534 "Cannot Start the Graph, retrying: hr=0x%8lx", hr
);
538 while( hr
!= S_OK
&& i
< 10 ); /* give up after 10 tries */
542 msg_Warn( p_access
, "SubmitTuneRequest: "
543 "Failed to Start the Graph: hr=0x%8lx", hr
);
550 /*****************************************************************************
551 * Set Clear QAM (DigitalCable)
552 * Local ATSC Digital Antenna
553 *****************************************************************************/
554 int BDAGraph::SetCQAM(long l_frequency
)
560 ITuneRequest
* p_tune_request
;
561 IDigitalCableTuneRequest
* p_cqam_tune_request
;
562 IDigitalCableLocator
* p_cqam_locator
;
564 p_tune_request(NULL
),
565 p_cqam_tune_request(NULL
),
571 p_tune_request
->Release();
572 if( p_cqam_tune_request
)
573 p_cqam_tune_request
->Release();
575 p_cqam_locator
->Release();
578 long l_minor_channel
, l_physical_channel
;
580 l_physical_channel
= var_GetInteger( p_access
, "dvb-physical-channel" );
581 l_minor_channel
= var_GetInteger( p_access
, "dvb-minor-channel" );
583 /* try to set p_scanning_tuner */
584 hr
= Check( CLSID_DigitalCableNetworkType
);
587 msg_Warn( p_access
, "SetCQAM: "\
588 "Cannot create Tuning Space: hr=0x%8lx", hr
);
592 if( !p_scanning_tuner
)
594 msg_Warn( p_access
, "SetCQAM: Cannot get scanning tuner" );
598 hr
= p_scanning_tuner
->get_TuneRequest( &l
.p_tune_request
);
601 msg_Warn( p_access
, "SetCQAM: "\
602 "Cannot get Tune Request: hr=0x%8lx", hr
);
606 hr
= l
.p_tune_request
->QueryInterface( IID_IDigitalCableTuneRequest
,
607 reinterpret_cast<void**>( &l
.p_cqam_tune_request
) );
610 msg_Warn( p_access
, "SetCQAM: "\
611 "Cannot QI for IDigitalCableTuneRequest: hr=0x%8lx", hr
);
615 hr
= ::CoCreateInstance( CLSID_DigitalCableLocator
, 0, CLSCTX_INPROC
,
616 IID_IDigitalCableLocator
, reinterpret_cast<void**>( &l
.p_cqam_locator
) );
619 msg_Warn( p_access
, "SetCQAM: "\
620 "Cannot create the CQAM locator: hr=0x%8lx", hr
);
625 if( SUCCEEDED( hr
) && l_physical_channel
> 0 )
626 hr
= l
.p_cqam_locator
->put_PhysicalChannel( l_physical_channel
);
627 if( SUCCEEDED( hr
) && l_frequency
> 0 )
628 hr
= l
.p_cqam_locator
->put_CarrierFrequency( l_frequency
);
629 if( SUCCEEDED( hr
) && l_minor_channel
> 0 )
630 hr
= l
.p_cqam_tune_request
->put_MinorChannel( l_minor_channel
);
633 msg_Warn( p_access
, "SetCQAM: "\
634 "Cannot set tuning parameters: hr=0x%8lx", hr
);
638 hr
= l
.p_cqam_tune_request
->put_Locator( l
.p_cqam_locator
);
641 msg_Warn( p_access
, "SetCQAM: "\
642 "Cannot put the locator: hr=0x%8lx", hr
);
646 hr
= p_scanning_tuner
->Validate( l
.p_cqam_tune_request
);
649 msg_Dbg( p_access
, "SetCQAM: "\
650 "Tune Request cannot be validated: hr=0x%8lx", hr
);
652 /* increments ref count for scanning tuner */
653 hr
= p_scanning_tuner
->put_TuneRequest( l
.p_cqam_tune_request
);
656 msg_Warn( p_access
, "SetCQAM: "\
657 "Cannot put the tune request: hr=0x%8lx", hr
);
664 /*****************************************************************************
666 *****************************************************************************/
667 int BDAGraph::SetATSC(long l_frequency
)
673 ITuneRequest
* p_tune_request
;
674 IATSCChannelTuneRequest
* p_atsc_tune_request
;
675 IATSCLocator
* p_atsc_locator
;
677 p_tune_request(NULL
),
678 p_atsc_tune_request(NULL
),
684 p_tune_request
->Release();
685 if( p_atsc_tune_request
)
686 p_atsc_tune_request
->Release();
688 p_atsc_locator
->Release();
691 long l_major_channel
, l_minor_channel
, l_physical_channel
;
693 /* fixme: these parameters should have dtv prefix, not dvb */
694 l_major_channel
= var_GetInteger( p_access
, "dvb-major-channel" );
695 l_minor_channel
= var_GetInteger( p_access
, "dvb-minor-channel" );
696 l_physical_channel
= var_GetInteger( p_access
, "dvb-physical-channel" );
698 /* try to set p_scanning_tuner */
699 hr
= Check( CLSID_ATSCNetworkProvider
);
702 msg_Warn( p_access
, "SetATSC: "\
703 "Cannot create Tuning Space: hr=0x%8lx", hr
);
707 if( !p_scanning_tuner
)
709 msg_Warn( p_access
, "SetATSC: Cannot get scanning tuner" );
713 hr
= p_scanning_tuner
->get_TuneRequest( &l
.p_tune_request
);
716 msg_Warn( p_access
, "SetATSC: "\
717 "Cannot get Tune Request: hr=0x%8lx", hr
);
721 hr
= l
.p_tune_request
->QueryInterface( IID_IATSCChannelTuneRequest
,
722 reinterpret_cast<void**>( &l
.p_atsc_tune_request
) );
725 msg_Warn( p_access
, "SetATSC: "\
726 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr
);
730 hr
= ::CoCreateInstance( CLSID_ATSCLocator
, 0, CLSCTX_INPROC
,
731 IID_IATSCLocator
, reinterpret_cast<void**>( &l
.p_atsc_locator
) );
734 msg_Warn( p_access
, "SetATSC: "\
735 "Cannot create the ATSC locator: hr=0x%8lx", hr
);
740 if( l_frequency
> 0 )
741 hr
= l
.p_atsc_locator
->put_CarrierFrequency( l_frequency
);
742 if( l_major_channel
> 0 )
743 hr
= l
.p_atsc_tune_request
->put_Channel( l_major_channel
);
744 if( SUCCEEDED( hr
) && l_minor_channel
> 0 )
745 hr
= l
.p_atsc_tune_request
->put_MinorChannel( l_minor_channel
);
746 if( SUCCEEDED( hr
) && l_physical_channel
> 0 )
747 hr
= l
.p_atsc_locator
->put_PhysicalChannel( l_physical_channel
);
750 msg_Warn( p_access
, "SetATSC: "\
751 "Cannot set tuning parameters: hr=0x%8lx", hr
);
755 hr
= l
.p_atsc_tune_request
->put_Locator( l
.p_atsc_locator
);
758 msg_Warn( p_access
, "SetATSC: "\
759 "Cannot put the locator: hr=0x%8lx", hr
);
763 hr
= p_scanning_tuner
->Validate( l
.p_atsc_tune_request
);
766 msg_Dbg( p_access
, "SetATSC: "\
767 "Tune Request cannot be validated: hr=0x%8lx", hr
);
769 /* increments ref count for scanning tuner */
770 hr
= p_scanning_tuner
->put_TuneRequest( l
.p_atsc_tune_request
);
773 msg_Warn( p_access
, "SetATSC: "\
774 "Cannot put the tune request: hr=0x%8lx", hr
);
781 /*****************************************************************************
784 * This provides the tune request that everything else is built upon.
786 * Stores the tune request to the scanning tuner, where it is pulled out by
787 * dvb_tune a/k/a SubmitTuneRequest.
788 ******************************************************************************/
789 int BDAGraph::SetDVBT(long l_frequency
, uint32_t fec_hp
, uint32_t fec_lp
,
790 long l_bandwidth
, int transmission
, uint32_t guard
, int hierarchy
)
797 ITuneRequest
* p_tune_request
;
798 IDVBTuneRequest
* p_dvb_tune_request
;
799 IDVBTLocator
* p_dvbt_locator
;
800 IDVBTuningSpace2
* p_dvb_tuning_space
;
802 p_tune_request(NULL
),
803 p_dvb_tune_request(NULL
),
804 p_dvbt_locator(NULL
),
805 p_dvb_tuning_space(NULL
)
810 p_tune_request
->Release();
811 if( p_dvb_tune_request
)
812 p_dvb_tune_request
->Release();
814 p_dvbt_locator
->Release();
815 if( p_dvb_tuning_space
)
816 p_dvb_tuning_space
->Release();
820 /* create local dvbt-specific tune request and locator
821 * then put it to existing scanning tuner */
822 BinaryConvolutionCodeRate i_hp_fec
= dvb_parse_fec(fec_hp
);
823 BinaryConvolutionCodeRate i_lp_fec
= dvb_parse_fec(fec_lp
);
824 GuardInterval i_guard
= dvb_parse_guard(guard
);
825 TransmissionMode i_transmission
= dvb_parse_transmission(transmission
);
826 HierarchyAlpha i_hierarchy
= dvb_parse_hierarchy(hierarchy
);
828 /* try to set p_scanning_tuner */
829 msg_Dbg( p_access
, "SetDVBT: set up scanning tuner" );
830 hr
= Check( CLSID_DVBTNetworkProvider
);
833 msg_Warn( p_access
, "SetDVBT: "\
834 "Cannot create Tuning Space: hr=0x%8lx", hr
);
838 if( !p_scanning_tuner
)
840 msg_Warn( p_access
, "SetDVBT: Cannot get scanning tuner" );
844 hr
= p_scanning_tuner
->get_TuneRequest( &l
.p_tune_request
);
847 msg_Warn( p_access
, "SetDVBT: "\
848 "Cannot get Tune Request: hr=0x%8lx", hr
);
852 msg_Dbg( p_access
, "SetDVBT: Creating DVB tune request" );
853 hr
= l
.p_tune_request
->QueryInterface( IID_IDVBTuneRequest
,
854 reinterpret_cast<void**>( &l
.p_dvb_tune_request
) );
857 msg_Warn( p_access
, "SetDVBT: "\
858 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr
);
862 l
.p_dvb_tune_request
->put_ONID( -1 );
863 l
.p_dvb_tune_request
->put_SID( -1 );
864 l
.p_dvb_tune_request
->put_TSID( -1 );
866 msg_Dbg( p_access
, "SetDVBT: get TS" );
867 hr
= p_scanning_tuner
->get_TuningSpace( &p_tuning_space
);
870 msg_Dbg( p_access
, "SetDVBT: "\
871 "cannot get tuning space: hr=0x%8lx", hr
);
875 msg_Dbg( p_access
, "SetDVBT: QI to DVBT TS" );
876 hr
= p_tuning_space
->QueryInterface( IID_IDVBTuningSpace2
,
877 reinterpret_cast<void**>( &l
.p_dvb_tuning_space
) );
880 msg_Warn( p_access
, "SetDVBT: "\
881 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr
);
885 msg_Dbg( p_access
, "SetDVBT: Creating local locator" );
886 hr
= ::CoCreateInstance( CLSID_DVBTLocator
, 0, CLSCTX_INPROC
,
887 IID_IDVBTLocator
, reinterpret_cast<void**>( &l
.p_dvbt_locator
) );
890 msg_Warn( p_access
, "SetDVBT: "\
891 "Cannot create the DVBT Locator: hr=0x%8lx", hr
);
895 hr
= l
.p_dvb_tuning_space
->put_SystemType( DVB_Terrestrial
);
896 if( SUCCEEDED( hr
) && l_frequency
> 0 )
897 hr
= l
.p_dvbt_locator
->put_CarrierFrequency( l_frequency
);
898 if( SUCCEEDED( hr
) && l_bandwidth
> 0 )
899 hr
= l
.p_dvbt_locator
->put_Bandwidth( l_bandwidth
);
900 if( SUCCEEDED( hr
) && i_hp_fec
!= BDA_BCC_RATE_NOT_SET
)
901 hr
= l
.p_dvbt_locator
->put_InnerFECRate( i_hp_fec
);
902 if( SUCCEEDED( hr
) && i_lp_fec
!= BDA_BCC_RATE_NOT_SET
)
903 hr
= l
.p_dvbt_locator
->put_LPInnerFECRate( i_lp_fec
);
904 if( SUCCEEDED( hr
) && i_guard
!= BDA_GUARD_NOT_SET
)
905 hr
= l
.p_dvbt_locator
->put_Guard( i_guard
);
906 if( SUCCEEDED( hr
) && i_transmission
!= BDA_XMIT_MODE_NOT_SET
)
907 hr
= l
.p_dvbt_locator
->put_Mode( i_transmission
);
908 if( SUCCEEDED( hr
) && i_hierarchy
!= BDA_HALPHA_NOT_SET
)
909 hr
= l
.p_dvbt_locator
->put_HAlpha( i_hierarchy
);
913 msg_Warn( p_access
, "SetDVBT: "\
914 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr
);
918 msg_Dbg( p_access
, "SetDVBT: putting DVBT locator into local tune request" );
920 hr
= l
.p_dvb_tune_request
->put_Locator( l
.p_dvbt_locator
);
923 msg_Warn( p_access
, "SetDVBT: "\
924 "Cannot put the locator: hr=0x%8lx", hr
);
928 msg_Dbg( p_access
, "SetDVBT: putting local Tune Request to scanning tuner" );
929 hr
= p_scanning_tuner
->Validate( l
.p_dvb_tune_request
);
932 msg_Dbg( p_access
, "SetDVBT: "\
933 "Tune Request cannot be validated: hr=0x%8lx", hr
);
935 /* increments ref count for scanning tuner */
936 hr
= p_scanning_tuner
->put_TuneRequest( l
.p_dvb_tune_request
);
939 msg_Warn( p_access
, "SetDVBT: "\
940 "Cannot put the tune request: hr=0x%8lx", hr
);
944 msg_Dbg( p_access
, "SetDVBT: return success" );
948 /*****************************************************************************
951 * This provides the tune request that everything else is built upon.
953 * Stores the tune request to the scanning tuner, where it is pulled out by
954 * dvb_tune a/k/a SubmitTuneRequest.
955 ******************************************************************************/
956 int BDAGraph::SetDVBT2(long l_frequency
, uint32_t fec
,
957 long l_bandwidth
, int transmission
, uint32_t guard
, int plp
)
964 ITuneRequest
* p_tune_request
;
965 IDVBTuneRequest
* p_dvb_tune_request
;
966 IDVBTLocator2
* p_dvbt_locator
;
967 IDVBTuningSpace2
* p_dvb_tuning_space
;
969 p_tune_request(NULL
),
970 p_dvb_tune_request(NULL
),
971 p_dvbt_locator(NULL
),
972 p_dvb_tuning_space(NULL
)
977 p_tune_request
->Release();
978 if( p_dvb_tune_request
)
979 p_dvb_tune_request
->Release();
981 p_dvbt_locator
->Release();
982 if( p_dvb_tuning_space
)
983 p_dvb_tuning_space
->Release();
987 /* create local dvbt-specific tune request and locator
988 * then put it to existing scanning tuner */
989 BinaryConvolutionCodeRate i_fec
= dvb_parse_fec(fec
);
990 GuardInterval i_guard
= dvb_parse_guard(guard
);
991 TransmissionMode i_transmission
= dvb_parse_transmission(transmission
);
994 /* try to set p_scanning_tuner */
995 msg_Dbg( p_access
, "SetDVBT: set up scanning tuner" );
996 hr
= Check( CLSID_DVBTNetworkProvider
);
999 msg_Warn( p_access
, "SetDVBT: "\
1000 "Cannot create Tuning Space: hr=0x%8lx", hr
);
1001 return VLC_EGENERIC
;
1004 if( !p_scanning_tuner
)
1006 msg_Warn( p_access
, "SetDVBT: Cannot get scanning tuner" );
1007 return VLC_EGENERIC
;
1010 hr
= p_scanning_tuner
->get_TuneRequest( &l
.p_tune_request
);
1013 msg_Warn( p_access
, "SetDVBT: "\
1014 "Cannot get Tune Request: hr=0x%8lx", hr
);
1015 return VLC_EGENERIC
;
1018 msg_Dbg( p_access
, "SetDVBT: Creating DVB tune request" );
1019 hr
= l
.p_tune_request
->QueryInterface( IID_IDVBTuneRequest
,
1020 reinterpret_cast<void**>( &l
.p_dvb_tune_request
) );
1023 msg_Warn( p_access
, "SetDVBT: "\
1024 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr
);
1025 return VLC_EGENERIC
;
1028 l
.p_dvb_tune_request
->put_ONID( -1 );
1029 l
.p_dvb_tune_request
->put_SID( -1 );
1030 l
.p_dvb_tune_request
->put_TSID( -1 );
1032 msg_Dbg( p_access
, "SetDVBT: get TS" );
1033 hr
= p_scanning_tuner
->get_TuningSpace( &p_tuning_space
);
1036 msg_Dbg( p_access
, "SetDVBT: "\
1037 "cannot get tuning space: hr=0x%8lx", hr
);
1038 return VLC_EGENERIC
;
1041 msg_Dbg( p_access
, "SetDVBT: QI to DVBT TS" );
1042 hr
= p_tuning_space
->QueryInterface( IID_IDVBTuningSpace2
,
1043 reinterpret_cast<void**>( &l
.p_dvb_tuning_space
) );
1046 msg_Warn( p_access
, "SetDVBT: "\
1047 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr
);
1048 return VLC_EGENERIC
;
1051 msg_Dbg( p_access
, "SetDVBT: Creating local locator2" );
1053 hr
= ::CoCreateInstance( CLSID_DVBTLocator2
, 0, CLSCTX_INPROC
,
1054 IID_IDVBTLocator2
, reinterpret_cast<void**>( &l
.p_dvbt_locator
) );
1059 msg_Warn( p_access
, "SetDVBT: "\
1060 "Cannot create the DVBT Locator2: hr=0x%8lx", hr
);
1061 return VLC_EGENERIC
;
1064 hr
= l
.p_dvb_tuning_space
->put_SystemType( DVB_Terrestrial
);
1065 if( SUCCEEDED( hr
) && l_frequency
> 0 )
1066 hr
= l
.p_dvbt_locator
->put_CarrierFrequency( l_frequency
);
1067 if( SUCCEEDED( hr
) && l_bandwidth
> 0 )
1068 hr
= l
.p_dvbt_locator
->put_Bandwidth( l_bandwidth
);
1069 if( SUCCEEDED( hr
) && i_fec
!= BDA_BCC_RATE_NOT_SET
)
1070 hr
= l
.p_dvbt_locator
->put_InnerFECRate( i_fec
);
1071 if( SUCCEEDED( hr
) && i_fec
!= BDA_BCC_RATE_NOT_SET
)
1072 hr
= l
.p_dvbt_locator
->put_LPInnerFECRate( i_fec
);
1073 if( SUCCEEDED( hr
) && i_guard
!= BDA_GUARD_NOT_SET
)
1074 hr
= l
.p_dvbt_locator
->put_Guard( i_guard
);
1075 if( SUCCEEDED( hr
) && i_transmission
!= BDA_XMIT_MODE_NOT_SET
)
1076 hr
= l
.p_dvbt_locator
->put_Mode( i_transmission
);
1077 if( SUCCEEDED( hr
) && l_plp
> 0 ){
1078 hr
= l
.p_dvbt_locator
->put_PhysicalLayerPipeId( l_plp
);
1083 msg_Warn( p_access
, "SetDVBT: "\
1084 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr
);
1085 return VLC_EGENERIC
;
1088 msg_Dbg( p_access
, "SetDVBT: putting DVBT locator into local tune request" );
1090 hr
= l
.p_dvb_tune_request
->put_Locator( l
.p_dvbt_locator
);
1093 msg_Warn( p_access
, "SetDVBT: "\
1094 "Cannot put the locator: hr=0x%8lx", hr
);
1095 return VLC_EGENERIC
;
1098 msg_Dbg( p_access
, "SetDVBT: putting local Tune Request to scanning tuner" );
1099 hr
= p_scanning_tuner
->Validate( l
.p_dvb_tune_request
);
1102 msg_Dbg( p_access
, "SetDVBT: "\
1103 "Tune Request cannot be validated: hr=0x%8lx", hr
);
1105 /* increments ref count for scanning tuner */
1106 hr
= p_scanning_tuner
->put_TuneRequest( l
.p_dvb_tune_request
);
1109 msg_Warn( p_access
, "SetDVBT: "\
1110 "Cannot put the tune request: hr=0x%8lx", hr
);
1111 return VLC_EGENERIC
;
1114 /* TBS tuner PLP set workaround */
1115 /* TODO: Check TBS tuner is present */
1116 IPin
* pinInput0
= FindPinOnFilter( p_tuner_device
, "Input0");
1119 msg_Dbg( p_access
, "SetDVBT: pin Input0 found on tuner filter, trying to get IKsPropertySet interface for TBS tuner..." );
1120 IKsPropertySet
* p_ksPropertySet
;
1121 hr
= pinInput0
->QueryInterface(IID_IKsPropertySet
, reinterpret_cast<void**>(&p_ksPropertySet
));
1124 msg_Dbg( p_access
, "SetDVBT: Cannot query for IKsPropertySet (this can be normal if not TBS tuner) : hr=0x%8lx", hr
);
1128 msg_Dbg( p_access
, "SetDVBT: found IKsPropertySet interface (using TBS tuner PLP-set workaround)");
1129 TBS_PLP_INFO plp_info
;
1130 ZeroMemory( &plp_info
, sizeof( TBS_PLP_INFO
));
1131 plp_info
.plpId
= plp
;
1132 p_ksPropertySet
->Set( KSPROPSETID_BdaTunerExtensionProperties
,
1133 KSPROPERTY_BDA_PLPINFO
,
1137 sizeof( TBS_PLP_INFO
));
1138 msg_Dbg( p_access
, "SetDVBT: TBS tuner set PLP: %d", plp
);
1139 p_ksPropertySet
->Release();
1141 pinInput0
->Release();
1145 msg_Dbg( p_access
, "SetDVBT: no pin Input0 found on tuner filter (this can be normal if not TBS tuner)" );
1148 msg_Dbg( p_access
, "SetDVBT: return success" );
1153 /*****************************************************************************
1155 ******************************************************************************/
1156 int BDAGraph::SetDVBC(long l_frequency
, const char *mod
, long l_symbolrate
)
1163 ITuneRequest
* p_tune_request
;
1164 IDVBTuneRequest
* p_dvb_tune_request
;
1165 IDVBCLocator
* p_dvbc_locator
;
1166 IDVBTuningSpace2
* p_dvb_tuning_space
;
1169 p_tune_request(NULL
),
1170 p_dvb_tune_request(NULL
),
1171 p_dvbc_locator(NULL
),
1172 p_dvb_tuning_space(NULL
)
1176 if( p_tune_request
)
1177 p_tune_request
->Release();
1178 if( p_dvb_tune_request
)
1179 p_dvb_tune_request
->Release();
1180 if( p_dvbc_locator
)
1181 p_dvbc_locator
->Release();
1182 if( p_dvb_tuning_space
)
1183 p_dvb_tuning_space
->Release();
1187 ModulationType i_qam_mod
= dvb_parse_modulation(mod
);
1189 /* try to set p_scanning_tuner */
1190 hr
= Check( CLSID_DVBCNetworkProvider
);
1191 msg_Dbg( p_access
, "SetDVBC: returned from Check" );
1195 msg_Warn( p_access
, "SetDVBC: "\
1196 "Cannot create Tuning Space: hr=0x%8lx", hr
);
1197 return VLC_EGENERIC
;
1200 msg_Dbg( p_access
, "SetDVBC: check on scanning tuner" );
1201 if( !p_scanning_tuner
)
1203 msg_Warn( p_access
, "SetDVBC: Cannot get scanning tuner" );
1204 return VLC_EGENERIC
;
1207 msg_Dbg( p_access
, "SetDVBC: get tune request" );
1208 hr
= p_scanning_tuner
->get_TuneRequest( &l
.p_tune_request
);
1211 msg_Warn( p_access
, "SetDVBC: "\
1212 "Cannot get Tune Request: hr=0x%8lx", hr
);
1213 return VLC_EGENERIC
;
1216 msg_Dbg( p_access
, "SetDVBC: QI for dvb tune request" );
1217 hr
= l
.p_tune_request
->QueryInterface( IID_IDVBTuneRequest
,
1218 reinterpret_cast<void**>( &l
.p_dvb_tune_request
) );
1221 msg_Warn( p_access
, "SetDVBC: "\
1222 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr
);
1223 return VLC_EGENERIC
;
1226 l
.p_dvb_tune_request
->put_ONID( -1 );
1227 l
.p_dvb_tune_request
->put_SID( -1 );
1228 l
.p_dvb_tune_request
->put_TSID( -1 );
1230 msg_Dbg( p_access
, "SetDVBC: create dvbc locator" );
1231 hr
= ::CoCreateInstance( CLSID_DVBCLocator
, 0, CLSCTX_INPROC
,
1232 IID_IDVBCLocator
, reinterpret_cast<void**>( &l
.p_dvbc_locator
) );
1235 msg_Warn( p_access
, "SetDVBC: "\
1236 "Cannot create the DVB-C Locator: hr=0x%8lx", hr
);
1237 return VLC_EGENERIC
;
1241 msg_Dbg( p_access
, "SetDVBC: get TS" );
1242 hr
= p_scanning_tuner
->get_TuningSpace( &p_tuning_space
);
1245 msg_Dbg( p_access
, "SetDVBC: "\
1246 "cannot get tuning space: hr=0x%8lx", hr
);
1247 return VLC_EGENERIC
;
1250 msg_Dbg( p_access
, "SetDVBC: QI for dvb tuning space" );
1251 hr
= p_tuning_space
->QueryInterface( IID_IDVBTuningSpace2
,
1252 reinterpret_cast<void**>( &l
.p_dvb_tuning_space
) );
1255 msg_Warn( p_access
, "SetDVBC: "\
1256 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr
);
1257 return VLC_EGENERIC
;
1260 msg_Dbg( p_access
, "SetDVBC: set up locator" );
1262 hr
= l
.p_dvb_tuning_space
->put_SystemType( DVB_Cable
);
1264 if( SUCCEEDED( hr
) && l_frequency
> 0 )
1265 hr
= l
.p_dvbc_locator
->put_CarrierFrequency( l_frequency
);
1266 if( SUCCEEDED( hr
) && l_symbolrate
> 0 )
1267 hr
= l
.p_dvbc_locator
->put_SymbolRate( l_symbolrate
);
1268 if( SUCCEEDED( hr
) && i_qam_mod
!= BDA_MOD_NOT_SET
)
1269 hr
= l
.p_dvbc_locator
->put_Modulation( i_qam_mod
);
1273 msg_Warn( p_access
, "SetDVBC: "\
1274 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr
);
1275 return VLC_EGENERIC
;
1278 msg_Dbg( p_access
, "SetDVBC: put locator to dvb tune request" );
1279 hr
= l
.p_dvb_tune_request
->put_Locator( l
.p_dvbc_locator
);
1282 msg_Warn( p_access
, "SetDVBC: "\
1283 "Cannot put the locator: hr=0x%8lx", hr
);
1284 return VLC_EGENERIC
;
1287 msg_Dbg( p_access
, "SetDVBC: validate dvb tune request" );
1288 hr
= p_scanning_tuner
->Validate( l
.p_dvb_tune_request
);
1291 msg_Dbg( p_access
, "SetDVBC: "\
1292 "Tune Request cannot be validated: hr=0x%8lx", hr
);
1295 /* increments ref count for scanning tuner */
1296 msg_Dbg( p_access
, "SetDVBC: put dvb tune request to tuner" );
1297 hr
= p_scanning_tuner
->put_TuneRequest( l
.p_dvb_tune_request
);
1300 msg_Warn( p_access
, "SetDVBC: "\
1301 "Cannot put the tune request: hr=0x%8lx", hr
);
1302 return VLC_EGENERIC
;
1304 msg_Dbg( p_access
, "SetDVBC: return success" );
1309 /*****************************************************************************
1311 ******************************************************************************/
1312 int BDAGraph::SetInversion(int inversion
)
1318 IDVBSTuningSpace
* p_dvbs_tuning_space
;
1320 p_dvbs_tuning_space(NULL
)
1324 if( p_dvbs_tuning_space
)
1325 p_dvbs_tuning_space
->Release();
1329 SpectralInversion i_inversion
= dvb_parse_inversion( inversion
);
1331 if( !p_scanning_tuner
)
1333 msg_Warn( p_access
, "SetInversion: "\
1334 "No scanning tuner" );
1335 return VLC_EGENERIC
;
1338 /* SetInversion is called for all DVB tuners, before the dvb_tune(),
1339 * in access.c. Since DVBT and DVBC don't support spectral
1340 * inversion, we need to return VLC_SUCCESS in those cases
1341 * so that dvb_tune() will be called */
1342 if( ( GetSystem( guid_network_type
) & ( DTV_DELIVERY_DVB_S
| DTV_DELIVERY_DVB_S2
| DTV_DELIVERY_ISDB_S
) ) == 0 )
1344 msg_Dbg( p_access
, "SetInversion: Not Satellite type" );
1348 msg_Dbg( p_access
, "SetInversion: get TS" );
1349 hr
= p_scanning_tuner
->get_TuningSpace( &p_tuning_space
);
1352 msg_Warn( p_access
, "SetInversion: "\
1353 "cannot get tuning space: hr=0x%8lx", hr
);
1354 return VLC_EGENERIC
;
1357 hr
= p_tuning_space
->QueryInterface( IID_IDVBSTuningSpace
,
1358 reinterpret_cast<void**>( &l
.p_dvbs_tuning_space
) );
1361 msg_Warn( p_access
, "SetInversion: "\
1362 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr
);
1363 return VLC_EGENERIC
;
1366 if( i_inversion
!= BDA_SPECTRAL_INVERSION_NOT_SET
)
1367 hr
= l
.p_dvbs_tuning_space
->put_SpectralInversion( i_inversion
);
1370 msg_Warn( p_access
, "SetInversion: "\
1371 "Cannot put inversion: hr=0x%8lx", hr
);
1372 return VLC_EGENERIC
;
1378 /*****************************************************************************
1380 ******************************************************************************/
1381 int BDAGraph::SetDVBS(long l_frequency
, long l_symbolrate
, uint32_t fec
,
1382 int inversion
, char pol
,
1383 long l_lnb_lof1
, long l_lnb_lof2
, long l_lnb_slof
)
1390 ITuneRequest
* p_tune_request
;
1391 IDVBTuneRequest
* p_dvb_tune_request
;
1392 IDVBSLocator
* p_dvbs_locator
;
1393 IDVBSTuningSpace
* p_dvbs_tuning_space
;
1394 char* psz_polarisation
;
1395 char* psz_input_range
;
1396 BSTR bstr_input_range
;
1397 WCHAR
* pwsz_input_range
;
1400 p_tune_request(NULL
),
1401 p_dvb_tune_request(NULL
),
1402 p_dvbs_locator(NULL
),
1403 p_dvbs_tuning_space(NULL
),
1404 psz_polarisation(NULL
),
1405 psz_input_range(NULL
),
1406 bstr_input_range(NULL
),
1407 pwsz_input_range(NULL
),
1412 if( p_tune_request
)
1413 p_tune_request
->Release();
1414 if( p_dvb_tune_request
)
1415 p_dvb_tune_request
->Release();
1416 if( p_dvbs_locator
)
1417 p_dvbs_locator
->Release();
1418 if( p_dvbs_tuning_space
)
1419 p_dvbs_tuning_space
->Release();
1420 SysFreeString( bstr_input_range
);
1421 if( pwsz_input_range
)
1422 delete[] pwsz_input_range
;
1423 free( psz_input_range
);
1424 free( psz_polarisation
);
1427 long l_azimuth
, l_elevation
, l_longitude
;
1429 VARIANT_BOOL b_west
;
1431 BinaryConvolutionCodeRate i_hp_fec
= dvb_parse_fec( fec
);
1432 Polarisation i_polar
= dvb_parse_polarization( pol
);
1433 SpectralInversion i_inversion
= dvb_parse_inversion( inversion
);
1435 l_azimuth
= var_GetInteger( p_access
, "dvb-azimuth" );
1436 l_elevation
= var_GetInteger( p_access
, "dvb-elevation" );
1437 l_longitude
= var_GetInteger( p_access
, "dvb-longitude" );
1438 l_network_id
= var_GetInteger( p_access
, "dvb-network-id" );
1440 if( asprintf( &l
.psz_polarisation
, "%c", pol
) == -1 )
1443 b_west
= ( l_longitude
< 0 );
1445 l
.psz_input_range
= var_GetNonEmptyString( p_access
, "dvb-range" );
1446 l
.i_range_len
= MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
,
1447 l
.psz_input_range
, -1, l
.pwsz_input_range
, 0 );
1448 if( l
.i_range_len
> 0 )
1450 l
.pwsz_input_range
= new WCHAR
[l
.i_range_len
];
1451 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
,
1452 l
.psz_input_range
, -1, l
.pwsz_input_range
, l
.i_range_len
);
1453 l
.bstr_input_range
= SysAllocString( l
.pwsz_input_range
);
1456 /* try to set p_scanning_tuner */
1457 hr
= Check( CLSID_DVBSNetworkProvider
);
1460 msg_Warn( p_access
, "SetDVBS: "\
1461 "Cannot create Tuning Space: hr=0x%8lx", hr
);
1462 return VLC_EGENERIC
;
1465 if( !p_scanning_tuner
)
1467 msg_Warn( p_access
, "SetDVBS: Cannot get scanning tuner" );
1468 return VLC_EGENERIC
;
1471 hr
= p_scanning_tuner
->get_TuneRequest( &l
.p_tune_request
);
1474 msg_Warn( p_access
, "SetDVBS: "\
1475 "Cannot get Tune Request: hr=0x%8lx", hr
);
1476 return VLC_EGENERIC
;
1479 hr
= l
.p_tune_request
->QueryInterface( IID_IDVBTuneRequest
,
1480 reinterpret_cast<void**>( &l
.p_dvb_tune_request
) );
1483 msg_Warn( p_access
, "SetDVBS: "\
1484 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr
);
1485 return VLC_EGENERIC
;
1488 l
.p_dvb_tune_request
->put_ONID( -1 );
1489 l
.p_dvb_tune_request
->put_SID( -1 );
1490 l
.p_dvb_tune_request
->put_TSID( -1 );
1492 hr
= ::CoCreateInstance( CLSID_DVBSLocator
, 0, CLSCTX_INPROC
,
1493 IID_IDVBSLocator
, reinterpret_cast<void**>( &l
.p_dvbs_locator
) );
1496 msg_Warn( p_access
, "SetDVBS: "\
1497 "Cannot create the DVBS Locator: hr=0x%8lx", hr
);
1498 return VLC_EGENERIC
;
1501 msg_Dbg( p_access
, "SetDVBS: get TS" );
1502 hr
= p_scanning_tuner
->get_TuningSpace( &p_tuning_space
);
1505 msg_Dbg( p_access
, "SetDVBS: "\
1506 "cannot get tuning space: hr=0x%8lx", hr
);
1507 return VLC_EGENERIC
;
1510 hr
= p_tuning_space
->QueryInterface( IID_IDVBSTuningSpace
,
1511 reinterpret_cast<void**>( &l
.p_dvbs_tuning_space
) );
1514 msg_Warn( p_access
, "SetDVBS: "\
1515 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr
);
1516 return VLC_EGENERIC
;
1519 hr
= l
.p_dvbs_tuning_space
->put_SystemType( DVB_Satellite
);
1520 if( SUCCEEDED( hr
) && l_lnb_lof1
> 0 )
1521 hr
= l
.p_dvbs_tuning_space
->put_LowOscillator( l_lnb_lof1
);
1522 if( SUCCEEDED( hr
) && l_lnb_slof
> 0 )
1523 hr
= l
.p_dvbs_tuning_space
->put_LNBSwitch( l_lnb_slof
);
1524 if( SUCCEEDED( hr
) && l_lnb_lof2
> 0 )
1525 hr
= l
.p_dvbs_tuning_space
->put_HighOscillator( l_lnb_lof2
);
1526 if( SUCCEEDED( hr
) && i_inversion
!= BDA_SPECTRAL_INVERSION_NOT_SET
)
1527 hr
= l
.p_dvbs_tuning_space
->put_SpectralInversion( i_inversion
);
1528 if( SUCCEEDED( hr
) && l_network_id
> 0 )
1529 hr
= l
.p_dvbs_tuning_space
->put_NetworkID( l_network_id
);
1530 if( SUCCEEDED( hr
) && l
.i_range_len
> 0 )
1531 hr
= l
.p_dvbs_tuning_space
->put_InputRange( l
.bstr_input_range
);
1533 if( SUCCEEDED( hr
) && l_frequency
> 0 )
1534 hr
= l
.p_dvbs_locator
->put_CarrierFrequency( l_frequency
);
1535 if( SUCCEEDED( hr
) && l_symbolrate
> 0 )
1536 hr
= l
.p_dvbs_locator
->put_SymbolRate( l_symbolrate
);
1537 if( SUCCEEDED( hr
) && i_polar
!= BDA_POLARISATION_NOT_SET
)
1538 hr
= l
.p_dvbs_locator
->put_SignalPolarisation( i_polar
);
1539 if( SUCCEEDED( hr
) )
1540 hr
= l
.p_dvbs_locator
->put_Modulation( BDA_MOD_QPSK
);
1541 if( SUCCEEDED( hr
) && i_hp_fec
!= BDA_BCC_RATE_NOT_SET
)
1542 hr
= l
.p_dvbs_locator
->put_InnerFECRate( i_hp_fec
);
1544 if( SUCCEEDED( hr
) && l_azimuth
> 0 )
1545 hr
= l
.p_dvbs_locator
->put_Azimuth( l_azimuth
);
1546 if( SUCCEEDED( hr
) && l_elevation
> 0 )
1547 hr
= l
.p_dvbs_locator
->put_Elevation( l_elevation
);
1548 if( SUCCEEDED( hr
) )
1549 hr
= l
.p_dvbs_locator
->put_WestPosition( b_west
);
1550 if( SUCCEEDED( hr
) )
1551 hr
= l
.p_dvbs_locator
->put_OrbitalPosition( labs( l_longitude
) );
1555 msg_Warn( p_access
, "SetDVBS: "\
1556 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr
);
1557 return VLC_EGENERIC
;
1560 hr
= l
.p_dvb_tune_request
->put_Locator( l
.p_dvbs_locator
);
1563 msg_Warn( p_access
, "SetDVBS: "\
1564 "Cannot put the locator: hr=0x%8lx", hr
);
1565 return VLC_EGENERIC
;
1568 hr
= p_scanning_tuner
->Validate( l
.p_dvb_tune_request
);
1571 msg_Dbg( p_access
, "SetDVBS: "\
1572 "Tune Request cannot be validated: hr=0x%8lx", hr
);
1575 /* increments ref count for scanning tuner */
1576 hr
= p_scanning_tuner
->put_TuneRequest( l
.p_dvb_tune_request
);
1579 msg_Warn( p_access
, "SetDVBS: "\
1580 "Cannot put the tune request: hr=0x%8lx", hr
);
1581 return VLC_EGENERIC
;
1587 /*****************************************************************************
1589 ******************************************************************************
1590 * Sets up global p_scanning_tuner and sets guid_network_type according
1591 * to the Network Type requested.
1593 * Logic: if tuner is set up and is the right network type, use it.
1594 * Otherwise, poll the tuner for the right tuning space.
1596 * Then set up a tune request and try to validate it. Finally, put
1597 * tune request and tuning space to tuner
1599 * on success, sets globals: p_scanning_tuner and guid_network_type
1601 ******************************************************************************/
1602 HRESULT
BDAGraph::SetUpTuner( REFCLSID guid_this_network_type
)
1608 ITuningSpaceContainer
* p_tuning_space_container
;
1609 IEnumTuningSpaces
* p_tuning_space_enum
;
1610 ITuningSpace
* p_test_tuning_space
;
1611 ITuneRequest
* p_tune_request
;
1612 IDVBTuneRequest
* p_dvb_tune_request
;
1614 IDigitalCableTuneRequest
* p_cqam_tune_request
;
1615 IATSCChannelTuneRequest
* p_atsc_tune_request
;
1616 ILocator
* p_locator
;
1617 IDVBTLocator
* p_dvbt_locator
;
1618 IDVBCLocator
* p_dvbc_locator
;
1619 IDVBSLocator
* p_dvbs_locator
;
1623 CLSID guid_test_network_type
;
1624 char* psz_network_name
;
1625 char* psz_bstr_name
;
1629 p_tuning_space_container(NULL
),
1630 p_tuning_space_enum(NULL
),
1631 p_test_tuning_space(NULL
),
1632 p_tune_request(NULL
),
1633 p_dvb_tune_request(NULL
),
1634 p_cqam_tune_request(NULL
),
1635 p_atsc_tune_request(NULL
),
1637 p_dvbt_locator(NULL
),
1638 p_dvbc_locator(NULL
),
1639 p_dvbs_locator(NULL
),
1641 guid_test_network_type(GUID_NULL
),
1642 psz_network_name(NULL
),
1643 psz_bstr_name(NULL
),
1648 if( p_tuning_space_enum
)
1649 p_tuning_space_enum
->Release();
1650 if( p_tuning_space_container
)
1651 p_tuning_space_container
->Release();
1652 if( p_test_tuning_space
)
1653 p_test_tuning_space
->Release();
1654 if( p_tune_request
)
1655 p_tune_request
->Release();
1656 if( p_dvb_tune_request
)
1657 p_dvb_tune_request
->Release();
1658 if( p_cqam_tune_request
)
1659 p_cqam_tune_request
->Release();
1660 if( p_atsc_tune_request
)
1661 p_atsc_tune_request
->Release();
1663 p_locator
->Release();
1664 if( p_dvbt_locator
)
1665 p_dvbt_locator
->Release();
1666 if( p_dvbc_locator
)
1667 p_dvbc_locator
->Release();
1668 if( p_dvbs_locator
)
1669 p_dvbs_locator
->Release();
1670 SysFreeString( bstr_name
);
1671 delete[] psz_bstr_name
;
1672 free( psz_network_name
);
1676 msg_Dbg( p_access
, "SetUpTuner: entering" );
1679 /* We shall test for a specific Tuning space name supplied on the command
1680 * line as dvb-network-name=xxx.
1681 * For some users with multiple cards and/or multiple networks this could
1682 * be useful. This allows us to reasonably safely apply updates to the
1683 * System Tuning Space in the registry without disrupting other streams. */
1685 l
.psz_network_name
= var_GetNonEmptyString( p_access
, "dvb-network-name" );
1687 if( l
.psz_network_name
)
1689 msg_Dbg( p_access
, "SetUpTuner: Find Tuning Space: %s",
1690 l
.psz_network_name
);
1694 l
.psz_network_name
= new char[1];
1695 *l
.psz_network_name
= '\0';
1698 /* Tuner may already have been set up. If it is for the same
1699 * network type then all is well. Otherwise, reset the Tuning Space and get
1701 msg_Dbg( p_access
, "SetUpTuner: Checking for tuning space" );
1702 if( !p_scanning_tuner
)
1704 msg_Warn( p_access
, "SetUpTuner: "\
1705 "Cannot find scanning tuner" );
1709 if( p_tuning_space
)
1711 msg_Dbg( p_access
, "SetUpTuner: get network type" );
1712 hr
= p_tuning_space
->get__NetworkType( &l
.guid_test_network_type
);
1715 msg_Warn( p_access
, "Check: "\
1716 "Cannot get network type: hr=0x%8lx", hr
);
1717 l
.guid_test_network_type
= GUID_NULL
;
1720 msg_Dbg( p_access
, "SetUpTuner: see if it's the right one" );
1721 if( l
.guid_test_network_type
== guid_this_network_type
)
1723 msg_Dbg( p_access
, "SetUpTuner: it's the right one" );
1724 SysFreeString( l
.bstr_name
);
1726 hr
= p_tuning_space
->get_UniqueName( &l
.bstr_name
);
1729 /* should never fail on a good tuning space */
1730 msg_Dbg( p_access
, "SetUpTuner: "\
1731 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr
);
1735 /* Test for a specific Tuning space name supplied on the command
1736 * line as dvb-network-name=xxx */
1737 if( l
.psz_bstr_name
)
1738 delete[] l
.psz_bstr_name
;
1739 l
.i_name_len
= WideCharToMultiByte( CP_ACP
, 0, l
.bstr_name
, -1,
1740 l
.psz_bstr_name
, 0, NULL
, NULL
);
1741 l
.psz_bstr_name
= new char[ l
.i_name_len
];
1742 l
.i_name_len
= WideCharToMultiByte( CP_ACP
, 0, l
.bstr_name
, -1,
1743 l
.psz_bstr_name
, l
.i_name_len
, NULL
, NULL
);
1745 /* if no name was requested on command line, or if the name
1746 * requested equals the name of this space, we are OK */
1747 if( *l
.psz_network_name
== '\0' ||
1748 strcmp( l
.psz_network_name
, l
.psz_bstr_name
) == 0 )
1750 msg_Dbg( p_access
, "SetUpTuner: Using Tuning Space: %s",
1752 /* p_tuning_space and guid_network_type are already set */
1753 /* you probably already have a tune request, also */
1754 hr
= p_scanning_tuner
->get_TuneRequest( &l
.p_tune_request
);
1755 if( SUCCEEDED( hr
) )
1759 /* CreateTuneRequest adds l.p_tune_request to p_tuning_space
1760 * l.p_tune_request->RefCount = 1 */
1761 hr
= p_tuning_space
->CreateTuneRequest( &l
.p_tune_request
);
1762 if( SUCCEEDED( hr
) )
1766 msg_Warn( p_access
, "SetUpTuner: "\
1767 "Cannot Create Tune Request: hr=0x%8lx", hr
);
1768 /* fall through to NoTuningSpace */
1772 /* else different guid_network_type */
1774 if( p_tuning_space
)
1775 p_tuning_space
->Release();
1776 p_tuning_space
= NULL
;
1777 /* pro forma; should have returned S_OK if we created this */
1778 if( l
.p_tune_request
)
1779 l
.p_tune_request
->Release();
1780 l
.p_tune_request
= NULL
;
1784 /* p_tuning_space is null at this point; we have already
1785 returned S_OK if it was good. So find a tuning
1786 space on the scanning tuner. */
1788 msg_Dbg( p_access
, "SetUpTuner: release TuningSpaces Enumerator" );
1789 if( l
.p_tuning_space_enum
)
1790 l
.p_tuning_space_enum
->Release();
1791 msg_Dbg( p_access
, "SetUpTuner: nullify TuningSpaces Enumerator" );
1792 l
.p_tuning_space_enum
= NULL
;
1793 msg_Dbg( p_access
, "SetUpTuner: create TuningSpaces Enumerator" );
1795 hr
= p_scanning_tuner
->EnumTuningSpaces( &l
.p_tuning_space_enum
);
1798 msg_Warn( p_access
, "SetUpTuner: "\
1799 "Cannot create TuningSpaces Enumerator: hr=0x%8lx", hr
);
1805 msg_Dbg( p_access
, "SetUpTuner: top of loop" );
1806 l
.guid_test_network_type
= GUID_NULL
;
1807 if( l
.p_test_tuning_space
)
1808 l
.p_test_tuning_space
->Release();
1809 l
.p_test_tuning_space
= NULL
;
1810 if( p_tuning_space
)
1811 p_tuning_space
->Release();
1812 p_tuning_space
= NULL
;
1813 SysFreeString( l
.bstr_name
);
1815 msg_Dbg( p_access
, "SetUpTuner: need good TS enum" );
1816 if( !l
.p_tuning_space_enum
) break;
1817 msg_Dbg( p_access
, "SetUpTuner: next tuning space" );
1818 hr
= l
.p_tuning_space_enum
->Next( 1, &l
.p_test_tuning_space
, NULL
);
1819 if( hr
!= S_OK
) break;
1820 msg_Dbg( p_access
, "SetUpTuner: get network type" );
1821 hr
= l
.p_test_tuning_space
->get__NetworkType( &l
.guid_test_network_type
);
1824 msg_Warn( p_access
, "Check: "\
1825 "Cannot get network type: hr=0x%8lx", hr
);
1826 l
.guid_test_network_type
= GUID_NULL
;
1828 if( l
.guid_test_network_type
== guid_this_network_type
)
1830 msg_Dbg( p_access
, "SetUpTuner: Found matching space on tuner" );
1832 SysFreeString( l
.bstr_name
);
1833 msg_Dbg( p_access
, "SetUpTuner: get unique name" );
1835 hr
= l
.p_test_tuning_space
->get_UniqueName( &l
.bstr_name
);
1838 /* should never fail on a good tuning space */
1839 msg_Dbg( p_access
, "SetUpTuner: "\
1840 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr
);
1843 msg_Dbg( p_access
, "SetUpTuner: convert w to multi" );
1844 if ( l
.psz_bstr_name
)
1845 delete[] l
.psz_bstr_name
;
1846 l
.i_name_len
= WideCharToMultiByte( CP_ACP
, 0, l
.bstr_name
, -1,
1847 l
.psz_bstr_name
, 0, NULL
, NULL
);
1848 l
.psz_bstr_name
= new char[ l
.i_name_len
];
1849 l
.i_name_len
= WideCharToMultiByte( CP_ACP
, 0, l
.bstr_name
, -1,
1850 l
.psz_bstr_name
, l
.i_name_len
, NULL
, NULL
);
1851 msg_Dbg( p_access
, "SetUpTuner: Using Tuning Space: %s",
1858 msg_Dbg( p_access
, "SetUpTuner: checking what we got" );
1860 if( l
.guid_test_network_type
== GUID_NULL
)
1862 msg_Dbg( p_access
, "SetUpTuner: got null, try to clone" );
1866 msg_Dbg( p_access
, "SetUpTuner: put TS" );
1867 hr
= p_scanning_tuner
->put_TuningSpace( l
.p_test_tuning_space
);
1870 msg_Dbg( p_access
, "SetUpTuner: "\
1871 "cannot put tuning space: hr=0x%8lx", hr
);
1875 msg_Dbg( p_access
, "SetUpTuner: get default locator" );
1876 hr
= l
.p_test_tuning_space
->get_DefaultLocator( &l
.p_locator
);
1879 msg_Dbg( p_access
, "SetUpTuner: "\
1880 "cannot get default locator: hr=0x%8lx", hr
);
1884 msg_Dbg( p_access
, "SetUpTuner: create tune request" );
1885 hr
= l
.p_test_tuning_space
->CreateTuneRequest( &l
.p_tune_request
);
1888 msg_Dbg( p_access
, "SetUpTuner: "\
1889 "cannot create tune request: hr=0x%8lx", hr
);
1893 msg_Dbg( p_access
, "SetUpTuner: put locator" );
1894 hr
= l
.p_tune_request
->put_Locator( l
.p_locator
);
1897 msg_Dbg( p_access
, "SetUpTuner: "\
1898 "cannot put locator: hr=0x%8lx", hr
);
1902 msg_Dbg( p_access
, "SetUpTuner: try to validate tune request" );
1903 hr
= p_scanning_tuner
->Validate( l
.p_tune_request
);
1906 msg_Dbg( p_access
, "SetUpTuner: "\
1907 "Tune Request cannot be validated: hr=0x%8lx", hr
);
1910 msg_Dbg( p_access
, "SetUpTuner: Attach tune request to Scanning Tuner");
1911 /* increments ref count for scanning tuner */
1912 hr
= p_scanning_tuner
->put_TuneRequest( l
.p_tune_request
);
1915 msg_Warn( p_access
, "SetUpTuner: "\
1916 "Cannot submit the tune request: hr=0x%8lx", hr
);
1920 msg_Dbg( p_access
, "SetUpTuner: Tuning Space and Tune Request created" );
1923 /* Get the SystemTuningSpaces container
1924 * p_tuning_space_container->Refcount = 1 */
1926 msg_Warn( p_access
, "SetUpTuner: won't try to clone " );
1930 /*****************************************************************************
1931 * GetNextNetworkType
1932 * helper function; this is probably best done as an Enumeration of
1934 *****************************************************************************/
1935 HRESULT
BDAGraph::GetNextNetworkType( CLSID
* guid_this_network_type
)
1938 if( *guid_this_network_type
== GUID_NULL
)
1940 msg_Dbg( p_access
, "GetNextNetworkType: DVB-C" );
1941 *guid_this_network_type
= CLSID_DVBCNetworkProvider
;
1944 if( *guid_this_network_type
== CLSID_DVBCNetworkProvider
)
1946 msg_Dbg( p_access
, "GetNextNetworkType: DVB-T" );
1947 *guid_this_network_type
= CLSID_DVBTNetworkProvider
;
1950 if( *guid_this_network_type
== CLSID_DVBTNetworkProvider
)
1952 msg_Dbg( p_access
, "GetNextNetworkType: DVB-S" );
1953 *guid_this_network_type
= CLSID_DVBSNetworkProvider
;
1956 if( *guid_this_network_type
== CLSID_DVBSNetworkProvider
)
1958 msg_Dbg( p_access
, "GetNextNetworkType: ATSC" );
1959 *guid_this_network_type
= CLSID_ATSCNetworkProvider
;
1962 msg_Dbg( p_access
, "GetNextNetworkType: failed" );
1963 *guid_this_network_type
= GUID_NULL
;
1969 /******************************************************************************
1971 *******************************************************************************
1972 * Check if tuner supports this network type
1974 * on success, sets globals:
1975 * systems, l_tuner_used, p_network_provider, p_scanning_tuner, p_tuner_device,
1976 * p_tuning_space, p_filter_graph
1977 ******************************************************************************/
1978 HRESULT
BDAGraph::Check( REFCLSID guid_this_network_type
)
1985 ITuningSpaceContainer
* p_tuning_space_container
;
1988 p_tuning_space_container(NULL
)
1992 if( p_tuning_space_container
)
1993 p_tuning_space_container
->Release();
1997 msg_Dbg( p_access
, "Check: entering ");
1999 /* Note that the systems global is persistent across Destroy().
2000 * So we need to see if a tuner has been physically removed from
2001 * the system since the last Check. Before we do anything,
2002 * assume that this Check will fail and remove this network type
2003 * from systems. It will be restored if the Check passes.
2006 systems
&= ~( GetSystem( guid_this_network_type
) );
2009 /* If we have already have a filter graph, rebuild it*/
2010 msg_Dbg( p_access
, "Check: Destroying filter graph" );
2011 if( p_filter_graph
)
2013 p_filter_graph
= NULL
;
2014 hr
= ::CoCreateInstance( CLSID_FilterGraph
, NULL
, CLSCTX_INPROC
,
2015 IID_IGraphBuilder
, reinterpret_cast<void**>( &p_filter_graph
) );
2018 msg_Warn( p_access
, "Check: "\
2019 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr
);
2023 /* First filter in the graph is the Network Provider and
2024 * its Scanning Tuner which takes the Tune Request */
2025 if( p_network_provider
)
2026 p_network_provider
->Release();
2027 p_network_provider
= NULL
;
2028 hr
= ::CoCreateInstance( guid_this_network_type
, NULL
, CLSCTX_INPROC_SERVER
,
2029 IID_IBaseFilter
, reinterpret_cast<void**>( &p_network_provider
) );
2032 msg_Warn( p_access
, "Check: "\
2033 "Cannot CoCreate Network Provider: hr=0x%8lx", hr
);
2037 msg_Dbg( p_access
, "Check: adding Network Provider to graph");
2038 hr
= p_filter_graph
->AddFilter( p_network_provider
, L
"Network Provider" );
2041 msg_Warn( p_access
, "Check: "\
2042 "Cannot load network provider: hr=0x%8lx", hr
);
2046 /* Add the Network Tuner to the Network Provider. On subsequent calls,
2047 * l_tuner_used will cause a different tuner to be selected.
2049 * To select a specific device first get the parameter that nominates the
2050 * device (dvb-adapter) and use the value to initialise l_tuner_used.
2051 * Note that dvb-adapter is 1-based, while l_tuner_used is 0-based.
2052 * When FindFilter returns, check the contents of l_tuner_used.
2053 * If it is not what was selected, then the requested device was not
2054 * available, so return with an error. */
2056 long l_adapter
= -1;
2057 l_adapter
= var_GetInteger( p_access
, "dvb-adapter" );
2058 if( l_tuner_used
< 0 && l_adapter
>= 0 )
2059 l_tuner_used
= l_adapter
- 1;
2061 /* If tuner is in cold state, we have to do a successful put_TuneRequest
2062 * before it will Connect. */
2063 msg_Dbg( p_access
, "Check: Creating Scanning Tuner");
2064 if( p_scanning_tuner
)
2065 p_scanning_tuner
->Release();
2066 p_scanning_tuner
= NULL
;
2067 hr
= p_network_provider
->QueryInterface( IID_IScanningTuner
,
2068 reinterpret_cast<void**>( &p_scanning_tuner
) );
2071 msg_Warn( p_access
, "Check: "\
2072 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr
);
2076 /* try to set up p_scanning_tuner */
2077 msg_Dbg( p_access
, "Check: Calling SetUpTuner" );
2078 hr
= SetUpTuner( guid_this_network_type
);
2081 msg_Dbg( p_access
, "Check: "\
2082 "Cannot set up scanner in Check mode: hr=0x%8lx", hr
);
2086 msg_Dbg( p_access
, "Check: "\
2087 "Calling FindFilter for KSCATEGORY_BDA_NETWORK_TUNER with "\
2088 "p_network_provider; l_tuner_used=%ld", l_tuner_used
);
2089 hr
= FindFilter( KSCATEGORY_BDA_NETWORK_TUNER
, &l_tuner_used
,
2090 p_network_provider
, &p_tuner_device
);
2093 msg_Warn( p_access
, "Check: "\
2094 "Cannot load tuner device and connect network provider: "\
2099 if( l_adapter
> 0 && l_tuner_used
!= l_adapter
)
2101 msg_Warn( p_access
, "Check: "\
2102 "Tuner device %ld is not available", l_adapter
);
2106 msg_Dbg( p_access
, "Check: Using adapter %ld", l_tuner_used
);
2108 * already set l_tuner_used,
2111 msg_Dbg( p_access
, "Check: check succeeded: hr=0x%8lx", hr
);
2112 systems
|= GetSystem( guid_this_network_type
);
2113 msg_Dbg( p_access
, "Check: returning from Check mode" );
2118 /******************************************************************************
2120 *******************************************************************************
2121 * Build the Filter Graph
2123 * connects filters and
2124 * creates the media control and registers the graph
2125 * on success, sets globals:
2126 * d_graph_register, p_media_control, p_grabber, p_sample_grabber,
2127 * p_mpeg_demux, p_transport_info
2128 ******************************************************************************/
2129 HRESULT
BDAGraph::Build()
2132 long l_capture_used
;
2134 AM_MEDIA_TYPE grabber_media_type
;
2139 ITuningSpaceContainer
* p_tuning_space_container
;
2141 p_tuning_space_container(NULL
)
2145 if( p_tuning_space_container
)
2146 p_tuning_space_container
->Release();
2150 msg_Dbg( p_access
, "Build: entering");
2152 /* at this point, you've connected to a scanning tuner of the right
2155 if( !p_scanning_tuner
|| !p_tuner_device
)
2157 msg_Warn( p_access
, "Build: "\
2158 "Scanning Tuner does not exist" );
2162 hr
= p_scanning_tuner
->get_TuneRequest( &p_tune_request
);
2165 msg_Warn( p_access
, "Build: no tune request" );
2168 hr
= p_scanning_tuner
->get_TuningSpace( &p_tuning_space
);
2171 msg_Warn( p_access
, "Build: no tuning space" );
2174 hr
= p_tuning_space
->get__NetworkType( &guid_network_type
);
2177 /* Always look for all capture devices to match the Network Tuner */
2178 l_capture_used
= -1;
2179 msg_Dbg( p_access
, "Build: "\
2180 "Calling FindFilter for KSCATEGORY_BDA_RECEIVER_COMPONENT with "\
2181 "p_tuner_device; l_capture_used=%ld", l_capture_used
);
2182 hr
= FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT
, &l_capture_used
,
2183 p_tuner_device
, &p_capture_device
);
2186 /* Some BDA drivers do not provide a Capture Device Filter so force
2187 * the Sample Grabber to connect directly to the Tuner Device */
2188 msg_Dbg( p_access
, "Build: "\
2189 "Cannot find Capture device. Connect to tuner "\
2190 "and AddRef() : hr=0x%8lx", hr
);
2191 p_capture_device
= p_tuner_device
;
2192 p_capture_device
->AddRef();
2195 if( p_sample_grabber
)
2196 p_sample_grabber
->Release();
2197 p_sample_grabber
= NULL
;
2198 /* Insert the Sample Grabber to tap into the Transport Stream. */
2199 hr
= ::CoCreateInstance( CLSID_SampleGrabber
, NULL
, CLSCTX_INPROC_SERVER
,
2200 IID_IBaseFilter
, reinterpret_cast<void**>( &p_sample_grabber
) );
2203 msg_Warn( p_access
, "Build: "\
2204 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr
);
2208 hr
= p_filter_graph
->AddFilter( p_sample_grabber
, L
"Sample Grabber" );
2211 msg_Warn( p_access
, "Build: "\
2212 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr
);
2216 /* create the sample grabber */
2218 p_grabber
->Release();
2220 hr
= p_sample_grabber
->QueryInterface( IID_ISampleGrabber
,
2221 reinterpret_cast<void**>( &p_grabber
) );
2224 msg_Warn( p_access
, "Build: "\
2225 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr
);
2229 /* Try the possible stream type */
2231 for( int i
= 0; i
< 2; i
++ )
2233 ZeroMemory( &grabber_media_type
, sizeof( AM_MEDIA_TYPE
) );
2234 grabber_media_type
.majortype
= MEDIATYPE_Stream
;
2235 grabber_media_type
.subtype
= i
== 0 ? MEDIASUBTYPE_MPEG2_TRANSPORT
: KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT
;
2236 msg_Dbg( p_access
, "Build: "
2237 "Trying connecting with subtype %s",
2238 i
== 0 ? "MEDIASUBTYPE_MPEG2_TRANSPORT" : "KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT" );
2239 hr
= p_grabber
->SetMediaType( &grabber_media_type
);
2240 if( SUCCEEDED( hr
) )
2242 hr
= Connect( p_capture_device
, p_sample_grabber
);
2243 if( SUCCEEDED( hr
) )
2245 msg_Dbg( p_access
, "Build: "\
2246 "Connected capture device to sample grabber" );
2249 msg_Warn( p_access
, "Build: "\
2250 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr
, 1+i
);
2254 msg_Warn( p_access
, "Build: "\
2255 "Cannot set media type on grabber filter: hr=0x%8lx (try %d/2", hr
, 1+i
);
2258 msg_Dbg( p_access
, "Build: This is where it used to return upon success" );
2261 msg_Warn( p_access
, "Build: "\
2262 "Cannot use capture device: hr=0x%8lx", hr
);
2266 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
2267 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
2268 * the Network Provider filter to set up the stream */
2269 //msg_Dbg( p_access, "Build: using MPEG2 demux" );
2271 p_mpeg_demux
->Release();
2272 p_mpeg_demux
= NULL
;
2273 hr
= ::CoCreateInstance( CLSID_MPEG2Demultiplexer
, NULL
,
2274 CLSCTX_INPROC_SERVER
, IID_IBaseFilter
,
2275 reinterpret_cast<void**>( &p_mpeg_demux
) );
2278 msg_Warn( p_access
, "Build: "\
2279 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr
);
2283 //msg_Dbg( p_access, "Build: adding demux" );
2284 hr
= p_filter_graph
->AddFilter( p_mpeg_demux
, L
"Demux" );
2287 msg_Warn( p_access
, "Build: "\
2288 "Cannot add demux filter to graph: hr=0x%8lx", hr
);
2292 hr
= Connect( p_sample_grabber
, p_mpeg_demux
);
2295 msg_Warn( p_access
, "Build: "\
2296 "Cannot connect demux to grabber: hr=0x%8lx", hr
);
2300 //msg_Dbg( p_access, "Build: Connected sample grabber to demux" );
2301 /* Always look for the Transport Information Filter from the start
2302 * of the collection*/
2304 msg_Dbg( p_access
, "Check: "\
2305 "Calling FindFilter for KSCATEGORY_BDA_TRANSPORT_INFORMATION with "\
2306 "p_mpeg_demux; l_tif_used=%ld", l_tif_used
);
2309 hr
= FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION
, &l_tif_used
,
2310 p_mpeg_demux
, &p_transport_info
);
2313 msg_Warn( p_access
, "Build: "\
2314 "Cannot load TIF onto demux: hr=0x%8lx", hr
);
2318 /* Configure the Sample Grabber to buffer the samples continuously */
2319 hr
= p_grabber
->SetBufferSamples( true );
2322 msg_Warn( p_access
, "Build: "\
2323 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr
);
2327 hr
= p_grabber
->SetOneShot( false );
2330 msg_Warn( p_access
, "Build: "\
2331 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr
);
2335 /* Second parameter to SetCallback specifies the callback method; 0 uses
2336 * the ISampleGrabberCB::SampleCB method, which receives an IMediaSample
2338 //msg_Dbg( p_access, "Build: Adding grabber callback" );
2339 hr
= p_grabber
->SetCallback( this, 0 );
2342 msg_Warn( p_access
, "Build: "\
2343 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr
);
2347 hr
= Register(); /* creates d_graph_register */
2350 d_graph_register
= 0;
2351 msg_Dbg( p_access
, "Build: "\
2352 "Cannot register graph: hr=0x%8lx", hr
);
2355 /* The Media Control is used to Run and Stop the Graph */
2356 if( p_media_control
)
2357 p_media_control
->Release();
2358 p_media_control
= NULL
;
2359 hr
= p_filter_graph
->QueryInterface( IID_IMediaControl
,
2360 reinterpret_cast<void**>( &p_media_control
) );
2363 msg_Warn( p_access
, "Build: "\
2364 "Cannot QI Media Control: hr=0x%8lx", hr
);
2369 //msg_Dbg( p_access, "Build: succeeded: hr=0x%8lx", hr );
2374 HRESULT
BDAGraph::ListFilters( REFCLSID this_clsid
)
2381 ICreateDevEnum
* p_local_system_dev_enum
;
2382 IEnumMoniker
* p_moniker_enum
;
2383 IMoniker
* p_moniker
;
2384 IBaseFilter
* p_filter
;
2385 IBaseFilter
* p_this_filter
;
2386 IBindCtx
* p_bind_context
;
2387 IPropertyBag
* p_property_bag
;
2389 char* psz_downstream
;
2394 p_local_system_dev_enum(NULL
),
2395 p_moniker_enum(NULL
),
2398 p_this_filter(NULL
),
2399 p_bind_context( NULL
),
2400 p_property_bag(NULL
),
2401 psz_downstream( NULL
),
2406 if( p_property_bag
)
2407 p_property_bag
->Release();
2408 if( p_bind_context
)
2409 p_bind_context
->Release();
2411 p_filter
->Release();
2413 p_this_filter
->Release();
2415 p_moniker
->Release();
2416 if( p_moniker_enum
)
2417 p_moniker_enum
->Release();
2418 if( p_local_system_dev_enum
)
2419 p_local_system_dev_enum
->Release();
2422 if( psz_downstream
)
2423 delete[] psz_downstream
;
2428 // msg_Dbg( p_access, "ListFilters: Create local system_dev_enum");
2429 if( l
.p_local_system_dev_enum
)
2430 l
.p_local_system_dev_enum
->Release();
2431 l
.p_local_system_dev_enum
= NULL
;
2432 hr
= ::CoCreateInstance( CLSID_SystemDeviceEnum
, 0, CLSCTX_INPROC
,
2433 IID_ICreateDevEnum
, reinterpret_cast<void**>( &l
.p_local_system_dev_enum
) );
2436 msg_Warn( p_access
, "ListFilters: "\
2437 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr
);
2441 //msg_Dbg( p_access, "ListFilters: Create p_moniker_enum");
2442 if( l
.p_moniker_enum
)
2443 l
.p_moniker_enum
->Release();
2444 l
.p_moniker_enum
= NULL
;
2445 hr
= l
.p_local_system_dev_enum
->CreateClassEnumerator( this_clsid
,
2446 &l
.p_moniker_enum
, 0 );
2449 msg_Warn( p_access
, "ListFilters: "\
2450 "Cannot CreateClassEnumerator: hr=0x%8lx", hr
);
2454 //msg_Dbg( p_access, "ListFilters: Entering main loop" );
2457 /* We are overwriting l.p_moniker so we should Release and nullify
2458 * It is important that p_moniker and p_property_bag are fully released
2459 * l.p_filter may not be dereferenced so we could force to NULL */
2460 /* msg_Dbg( p_access, "ListFilters: top of main loop");*/
2461 //msg_Dbg( p_access, "ListFilters: releasing property bag");
2462 if( l
.p_property_bag
)
2463 l
.p_property_bag
->Release();
2464 l
.p_property_bag
= NULL
;
2465 //msg_Dbg( p_access, "ListFilters: releasing filter");
2467 l
.p_filter
->Release();
2469 //msg_Dbg( p_access, "ListFilters: releasing bind context");
2470 if( l
.p_bind_context
)
2471 l
.p_bind_context
->Release();
2472 l
.p_bind_context
= NULL
;
2473 //msg_Dbg( p_access, "ListFilters: releasing moniker");
2475 l
.p_moniker
->Release();
2477 //msg_Dbg( p_access, "ListFilters: trying a moniker");
2479 if( !l
.p_moniker_enum
) break;
2480 hr
= l
.p_moniker_enum
->Next( 1, &l
.p_moniker
, 0 );
2481 if( hr
!= S_OK
) break;
2483 /* l.p_bind_context is Released at the top of the loop */
2484 hr
= CreateBindCtx( 0, &l
.p_bind_context
);
2487 msg_Dbg( p_access
, "ListFilters: "\
2488 "Cannot create bind_context, trying another: hr=0x%8lx", hr
);
2492 /* l.p_filter is Released at the top of the loop */
2493 hr
= l
.p_moniker
->BindToObject( l
.p_bind_context
, NULL
, IID_IBaseFilter
,
2494 reinterpret_cast<void**>( &l
.p_filter
) );
2497 msg_Dbg( p_access
, "ListFilters: "\
2498 "Cannot create p_filter, trying another: hr=0x%8lx", hr
);
2502 #ifdef DEBUG_MONIKER_NAME
2503 WCHAR
* pwsz_downstream
= NULL
;
2505 hr
= l
.p_moniker
->GetDisplayName(l
.p_bind_context
, NULL
,
2509 msg_Dbg( p_access
, "ListFilters: "\
2510 "Cannot get display name, trying another: hr=0x%8lx", hr
);
2514 if( l
.psz_downstream
)
2515 delete[] l
.psz_downstream
;
2516 l
.i_bstr_len
= WideCharToMultiByte( CP_ACP
, 0, pwsz_downstream
, -1,
2517 l
.psz_downstream
, 0, NULL
, NULL
);
2518 l
.psz_downstream
= new char[ l
.i_bstr_len
];
2519 l
.i_bstr_len
= WideCharToMultiByte( CP_ACP
, 0, pwsz_downstream
, -1,
2520 l
.psz_downstream
, l
.i_bstr_len
, NULL
, NULL
);
2523 ::CoGetMalloc( 1, &p_alloc
);
2524 p_alloc
->Free( pwsz_downstream
);
2526 msg_Dbg( p_access
, "ListFilters: "\
2527 "Moniker name is %s", l
.psz_downstream
);
2529 l
.psz_downstream
= strdup( "Downstream" );
2531 /* l.p_property_bag is released at the top of the loop */
2532 hr
= l
.p_moniker
->BindToStorage( NULL
, NULL
, IID_IPropertyBag
,
2533 reinterpret_cast<void**>( &l
.p_property_bag
) );
2536 msg_Dbg( p_access
, "ListFilters: "\
2537 "Cannot Bind to Property Bag: hr=0x%8lx", hr
);
2541 //msg_Dbg( p_access, "ListFilters: displaying another" );
2548 /******************************************************************************
2550 * Looks up all filters in a category and connects to the upstream filter until
2551 * a successful match is found. The index of the connected filter is returned.
2552 * On subsequent calls, this can be used to start from that point to find
2554 * This is used when the graph does not run because a tuner device is in use so
2555 * another one needs to be selected.
2556 ******************************************************************************/
2557 HRESULT
BDAGraph::FindFilter( REFCLSID this_clsid
, long* i_moniker_used
,
2558 IBaseFilter
* p_upstream
, IBaseFilter
** p_p_downstream
)
2561 int i_moniker_index
= -1;
2565 IEnumMoniker
* p_moniker_enum
;
2566 IMoniker
* p_moniker
;
2567 IBindCtx
* p_bind_context
;
2568 IPropertyBag
* p_property_bag
;
2571 char* psz_downstream
;
2575 p_moniker_enum(NULL
),
2577 p_bind_context( NULL
),
2578 p_property_bag(NULL
),
2579 psz_upstream( NULL
),
2580 psz_downstream( NULL
)
2582 ::VariantInit(&var_bstr
);
2586 if( p_moniker_enum
)
2587 p_moniker_enum
->Release();
2589 p_moniker
->Release();
2590 if( p_bind_context
)
2591 p_bind_context
->Release();
2592 if( p_property_bag
)
2593 p_property_bag
->Release();
2595 delete[] psz_upstream
;
2596 if( psz_downstream
)
2597 delete[] psz_downstream
;
2599 ::VariantClear(&var_bstr
);
2603 /* create system_dev_enum the first time through, or preserve the
2604 * existing one to loop through classes */
2605 if( !p_system_dev_enum
)
2607 msg_Dbg( p_access
, "FindFilter: Create p_system_dev_enum");
2608 hr
= ::CoCreateInstance( CLSID_SystemDeviceEnum
, 0, CLSCTX_INPROC
,
2609 IID_ICreateDevEnum
, reinterpret_cast<void**>( &p_system_dev_enum
) );
2612 msg_Warn( p_access
, "FindFilter: "\
2613 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr
);
2618 msg_Dbg( p_access
, "FindFilter: Create p_moniker_enum");
2619 hr
= p_system_dev_enum
->CreateClassEnumerator( this_clsid
,
2620 &l
.p_moniker_enum
, 0 );
2623 msg_Warn( p_access
, "FindFilter: "\
2624 "Cannot CreateClassEnumerator: hr=0x%8lx", hr
);
2628 msg_Dbg( p_access
, "FindFilter: get filter name");
2629 hr
= GetFilterName( p_upstream
, &l
.psz_upstream
);
2632 msg_Warn( p_access
, "FindFilter: "\
2633 "Cannot GetFilterName: hr=0x%8lx", hr
);
2637 msg_Dbg( p_access
, "FindFilter: "\
2638 "called with i_moniker_used=%ld, " \
2639 "p_upstream = %s", *i_moniker_used
, l
.psz_upstream
);
2643 /* We are overwriting l.p_moniker so we should Release and nullify
2644 * It is important that p_moniker and p_property_bag are fully released */
2645 msg_Dbg( p_access
, "FindFilter: top of main loop");
2646 if( l
.p_property_bag
)
2647 l
.p_property_bag
->Release();
2648 l
.p_property_bag
= NULL
;
2649 msg_Dbg( p_access
, "FindFilter: releasing bind context");
2650 if( l
.p_bind_context
)
2651 l
.p_bind_context
->Release();
2652 l
.p_bind_context
= NULL
;
2653 msg_Dbg( p_access
, "FindFilter: releasing moniker");
2655 l
.p_moniker
->Release();
2656 msg_Dbg( p_access
, "FindFilter: null moniker");
2659 msg_Dbg( p_access
, "FindFilter: quit if no enum");
2660 if( !l
.p_moniker_enum
) break;
2661 msg_Dbg( p_access
, "FindFilter: trying a moniker");
2662 hr
= l
.p_moniker_enum
->Next( 1, &l
.p_moniker
, 0 );
2663 if( hr
!= S_OK
) break;
2667 /* Skip over devices already found on previous calls */
2668 msg_Dbg( p_access
, "FindFilter: skip previously found devices");
2670 if( i_moniker_index
<= *i_moniker_used
) continue;
2671 *i_moniker_used
= i_moniker_index
;
2673 /* l.p_bind_context is Released at the top of the loop */
2674 msg_Dbg( p_access
, "FindFilter: create bind context");
2675 hr
= CreateBindCtx( 0, &l
.p_bind_context
);
2678 msg_Dbg( p_access
, "FindFilter: "\
2679 "Cannot create bind_context, trying another: hr=0x%8lx", hr
);
2683 msg_Dbg( p_access
, "FindFilter: try to create downstream filter");
2684 *p_p_downstream
= NULL
;
2685 hr
= l
.p_moniker
->BindToObject( l
.p_bind_context
, NULL
, IID_IBaseFilter
,
2686 reinterpret_cast<void**>( p_p_downstream
) );
2689 msg_Dbg( p_access
, "FindFilter: "\
2690 "Cannot bind to downstream, trying another: hr=0x%8lx", hr
);
2694 #ifdef DEBUG_MONIKER_NAME
2695 msg_Dbg( p_access
, "FindFilter: get downstream filter name");
2697 WCHAR
* pwsz_downstream
= NULL
;
2699 hr
= l
.p_moniker
->GetDisplayName(l
.p_bind_context
, NULL
,
2703 msg_Dbg( p_access
, "FindFilter: "\
2704 "Cannot get display name, trying another: hr=0x%8lx", hr
);
2708 if( l
.psz_downstream
)
2709 delete[] l
.psz_downstream
;
2710 l
.i_bstr_len
= WideCharToMultiByte( CP_ACP
, 0, pwsz_downstream
, -1,
2711 l
.psz_downstream
, 0, NULL
, NULL
);
2712 l
.psz_downstream
= new char[ l
.i_bstr_len
];
2713 l
.i_bstr_len
= WideCharToMultiByte( CP_ACP
, 0, pwsz_downstream
, -1,
2714 l
.psz_downstream
, l
.i_bstr_len
, NULL
, NULL
);
2717 ::CoGetMalloc( 1, &p_alloc
);
2718 p_alloc
->Free( pwsz_downstream
);
2721 l
.psz_downstream
= strdup( "Downstream" );
2724 /* l.p_property_bag is released at the top of the loop */
2725 msg_Dbg( p_access
, "FindFilter: "\
2726 "Moniker name is %s, binding to storage", l
.psz_downstream
);
2727 hr
= l
.p_moniker
->BindToStorage( l
.p_bind_context
, NULL
,
2728 IID_IPropertyBag
, reinterpret_cast<void**>( &l
.p_property_bag
) );
2731 msg_Dbg( p_access
, "FindFilter: "\
2732 "Cannot Bind to Property Bag: hr=0x%8lx", hr
);
2736 msg_Dbg( p_access
, "FindFilter: read friendly name");
2737 hr
= l
.p_property_bag
->Read( L
"FriendlyName", &l
.var_bstr
, NULL
);
2740 msg_Dbg( p_access
, "FindFilter: "\
2741 "Cannot read friendly name, next?: hr=0x%8lx", hr
);
2745 msg_Dbg( p_access
, "FindFilter: add filter to graph" );
2746 hr
= p_filter_graph
->AddFilter( *p_p_downstream
, l
.var_bstr
.bstrVal
);
2749 msg_Dbg( p_access
, "FindFilter: "\
2750 "Cannot add filter, trying another: hr=0x%8lx", hr
);
2754 msg_Dbg( p_access
, "FindFilter: "\
2755 "Trying to Connect %s to %s", l
.psz_upstream
, l
.psz_downstream
);
2756 hr
= Connect( p_upstream
, *p_p_downstream
);
2757 if( SUCCEEDED( hr
) )
2759 msg_Dbg( p_access
, "FindFilter: Connected %s", l
.psz_downstream
);
2763 /* Not the filter we want so unload and try the next one */
2764 /* Warning: RemoveFilter does an undocumented Release()
2765 * on pointer but does not set it to NULL */
2766 msg_Dbg( p_access
, "FindFilter: Removing filter" );
2767 hr
= p_filter_graph
->RemoveFilter( *p_p_downstream
);
2770 msg_Warn( p_access
, "FindFilter: "\
2771 "Failed unloading Filter: hr=0x%8lx", hr
);
2774 msg_Dbg( p_access
, "FindFilter: trying another" );
2779 msg_Warn( p_access
, "FindFilter: No filter connected" );
2784 /*****************************************************************************
2785 * Connect is called from Build to enumerate and connect pins
2786 *****************************************************************************/
2787 HRESULT
BDAGraph::Connect( IBaseFilter
* p_upstream
, IBaseFilter
* p_downstream
)
2789 HRESULT hr
= E_FAIL
;
2793 IPin
* p_pin_upstream
;
2794 IPin
* p_pin_downstream
;
2795 IEnumPins
* p_pin_upstream_enum
;
2796 IEnumPins
* p_pin_downstream_enum
;
2799 char* psz_downstream
;
2802 p_pin_upstream(NULL
), p_pin_downstream(NULL
),
2803 p_pin_upstream_enum(NULL
), p_pin_downstream_enum(NULL
),
2805 psz_upstream( NULL
),
2806 psz_downstream( NULL
)
2811 p_pin_temp
->Release();
2812 if( p_pin_downstream
)
2813 p_pin_downstream
->Release();
2814 if( p_pin_upstream
)
2815 p_pin_upstream
->Release();
2816 if( p_pin_downstream_enum
)
2817 p_pin_downstream_enum
->Release();
2818 if( p_pin_upstream_enum
)
2819 p_pin_upstream_enum
->Release();
2821 delete[] psz_upstream
;
2822 if( psz_downstream
)
2823 delete[] psz_downstream
;
2827 PIN_DIRECTION pin_dir
;
2829 //msg_Dbg( p_access, "Connect: entering" );
2830 hr
= p_upstream
->EnumPins( &l
.p_pin_upstream_enum
);
2833 msg_Warn( p_access
, "Connect: "\
2834 "Cannot get upstream filter enumerator: hr=0x%8lx", hr
);
2840 /* Release l.p_pin_upstream before next iteration */
2841 if( l
.p_pin_upstream
)
2842 l
.p_pin_upstream
->Release();
2843 l
.p_pin_upstream
= NULL
;
2844 if( !l
.p_pin_upstream_enum
) break;
2845 hr
= l
.p_pin_upstream_enum
->Next( 1, &l
.p_pin_upstream
, 0 );
2846 if( hr
!= S_OK
) break;
2848 //msg_Dbg( p_access, "Connect: get pin name");
2849 hr
= GetPinName( l
.p_pin_upstream
, &l
.psz_upstream
);
2852 msg_Warn( p_access
, "Connect: "\
2853 "Cannot GetPinName: hr=0x%8lx", hr
);
2856 //msg_Dbg( p_access, "Connect: p_pin_upstream = %s", l.psz_upstream );
2858 hr
= l
.p_pin_upstream
->QueryDirection( &pin_dir
);
2861 msg_Warn( p_access
, "Connect: "\
2862 "Cannot get upstream filter pin direction: hr=0x%8lx", hr
);
2866 hr
= l
.p_pin_upstream
->ConnectedTo( &l
.p_pin_downstream
);
2867 if( SUCCEEDED( hr
) )
2869 l
.p_pin_downstream
->Release();
2870 l
.p_pin_downstream
= NULL
;
2873 if( FAILED( hr
) && hr
!= VFW_E_NOT_CONNECTED
)
2875 msg_Warn( p_access
, "Connect: "\
2876 "Cannot check upstream filter connection: hr=0x%8lx", hr
);
2880 if( ( pin_dir
== PINDIR_OUTPUT
) && ( hr
== VFW_E_NOT_CONNECTED
) )
2882 /* The upstream pin is not yet connected so check each pin on the
2883 * downstream filter */
2884 //msg_Dbg( p_access, "Connect: enumerating downstream pins" );
2885 hr
= p_downstream
->EnumPins( &l
.p_pin_downstream_enum
);
2888 msg_Warn( p_access
, "Connect: Cannot get "\
2889 "downstream filter enumerator: hr=0x%8lx", hr
);
2895 /* Release l.p_pin_downstream before next iteration */
2896 if( l
.p_pin_downstream
)
2897 l
.p_pin_downstream
->Release();
2898 l
.p_pin_downstream
= NULL
;
2899 if( !l
.p_pin_downstream_enum
) break;
2900 hr
= l
.p_pin_downstream_enum
->Next( 1, &l
.p_pin_downstream
, 0 );
2901 if( hr
!= S_OK
) break;
2903 //msg_Dbg( p_access, "Connect: get pin name");
2904 hr
= GetPinName( l
.p_pin_downstream
, &l
.psz_downstream
);
2907 msg_Warn( p_access
, "Connect: "\
2908 "Cannot GetPinName: hr=0x%8lx", hr
);
2912 msg_Dbg( p_access, "Connect: Trying p_downstream = %s",
2916 hr
= l
.p_pin_downstream
->QueryDirection( &pin_dir
);
2919 msg_Warn( p_access
, "Connect: Cannot get "\
2920 "downstream filter pin direction: hr=0x%8lx", hr
);
2924 /* Looking for a free Pin to connect to
2925 * A connected Pin may have an reference count > 1
2926 * so Release and nullify the pointer */
2927 hr
= l
.p_pin_downstream
->ConnectedTo( &l
.p_pin_temp
);
2928 if( SUCCEEDED( hr
) )
2930 l
.p_pin_temp
->Release();
2931 l
.p_pin_temp
= NULL
;
2934 if( hr
!= VFW_E_NOT_CONNECTED
)
2938 msg_Warn( p_access
, "Connect: Cannot check "\
2939 "downstream filter connection: hr=0x%8lx", hr
);
2944 if( ( pin_dir
== PINDIR_INPUT
) &&
2945 ( hr
== VFW_E_NOT_CONNECTED
) )
2947 //msg_Dbg( p_access, "Connect: trying to connect pins" );
2949 hr
= p_filter_graph
->ConnectDirect( l
.p_pin_upstream
,
2950 l
.p_pin_downstream
, NULL
);
2951 if( SUCCEEDED( hr
) )
2953 /* If we arrive here then we have a matching pair of
2958 /* If we arrive here it means this downstream pin is not
2959 * suitable so try the next downstream pin.
2960 * l.p_pin_downstream is released at the top of the loop */
2963 /* If we arrive here then we ran out of pins before we found a
2964 * suitable one. Release outstanding refcounts */
2965 if( l
.p_pin_downstream_enum
)
2966 l
.p_pin_downstream_enum
->Release();
2967 l
.p_pin_downstream_enum
= NULL
;
2968 if( l
.p_pin_downstream
)
2969 l
.p_pin_downstream
->Release();
2970 l
.p_pin_downstream
= NULL
;
2972 /* If we arrive here it means this upstream pin is not suitable
2973 * so try the next upstream pin
2974 * l.p_pin_upstream is released at the top of the loop */
2977 /* If we arrive here it means we did not find any pair of suitable pins
2978 * Outstanding refcounts are released in the destructor */
2979 //msg_Dbg( p_access, "Connect: No pins connected" );
2983 /*****************************************************************************
2984 * Start uses MediaControl to start the graph
2985 *****************************************************************************/
2986 HRESULT
BDAGraph::Start()
2989 OAFilterState i_state
; /* State_Stopped, State_Paused, State_Running */
2991 msg_Dbg( p_access
, "Start: entering" );
2993 if( !p_media_control
)
2995 msg_Warn( p_access
, "Start: Media Control has not been created" );
2999 msg_Dbg( p_access
, "Start: Run()" );
3000 hr
= p_media_control
->Run();
3001 if( SUCCEEDED( hr
) )
3003 msg_Dbg( p_access
, "Start: Graph started, hr=0x%lx", hr
);
3007 msg_Dbg( p_access
, "Start: would not start, will retry" );
3008 /* Query the state of the graph - timeout after 100 milliseconds */
3009 while( (hr
= p_media_control
->GetState( 100, &i_state
) ) != S_OK
)
3014 "Start: Cannot get Graph state: hr=0x%8lx", hr
);
3019 msg_Dbg( p_access
, "Start: got state" );
3020 if( i_state
== State_Running
)
3022 msg_Dbg( p_access
, "Graph started after a delay, hr=0x%lx", hr
);
3026 /* The Graph is not running so stop it and return an error */
3027 msg_Warn( p_access
, "Start: Graph not started: %d", (int)i_state
);
3028 hr
= p_media_control
->StopWhenReady(); /* Instead of Stop() */
3032 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr
);
3039 /*****************************************************************************
3040 * Pop the stream of data
3041 *****************************************************************************/
3042 ssize_t
BDAGraph::Pop(void *buf
, size_t len
, int ms
)
3044 return output
.Pop(buf
, len
, ms
);
3047 /******************************************************************************
3048 * SampleCB - Callback when the Sample Grabber has a sample
3049 ******************************************************************************/
3050 STDMETHODIMP
BDAGraph::SampleCB( double /*date*/, IMediaSample
*p_sample
)
3052 if( p_sample
->IsDiscontinuity() == S_OK
)
3053 msg_Warn( p_access
, "BDA SampleCB: Sample Discontinuity.");
3055 const size_t i_sample_size
= p_sample
->GetActualDataLength();
3057 /* The buffer memory is owned by the media sample object, and is automatically
3058 * released when the media sample is destroyed. The caller should not free or
3059 * reallocate the buffer. */
3060 BYTE
*p_sample_data
;
3061 p_sample
->GetPointer( &p_sample_data
);
3063 if( i_sample_size
> 0 && p_sample_data
)
3065 block_t
*p_block
= block_Alloc( i_sample_size
);
3069 memcpy( p_block
->p_buffer
, p_sample_data
, i_sample_size
);
3070 output
.Push( p_block
);
3076 STDMETHODIMP
BDAGraph::BufferCB( double /*date*/, BYTE
* /*buffer*/,
3077 long /*buffer_len*/ )
3082 /******************************************************************************
3083 * removes each filter from the graph
3084 ******************************************************************************/
3085 HRESULT
BDAGraph::Destroy()
3089 // msg_Dbg( p_access, "Destroy: media control 1" );
3090 if( p_media_control
)
3091 p_media_control
->StopWhenReady(); /* Instead of Stop() */
3093 // msg_Dbg( p_access, "Destroy: deregistering graph" );
3094 if( d_graph_register
)
3097 // msg_Dbg( p_access, "Destroy: calling Empty" );
3100 // msg_Dbg( p_access, "Destroy: TIF" );
3101 if( p_transport_info
)
3103 /* Warning: RemoveFilter does an undocumented Release()
3104 * on pointer but does not set it to NULL */
3105 hr
= p_filter_graph
->RemoveFilter( p_transport_info
);
3108 msg_Dbg( p_access
, "Destroy: "\
3109 "Failed unloading TIF: hr=0x%8lx", hr
);
3111 p_transport_info
= NULL
;
3114 // msg_Dbg( p_access, "Destroy: demux" );
3117 p_filter_graph
->RemoveFilter( p_mpeg_demux
);
3120 msg_Dbg( p_access
, "Destroy: "\
3121 "Failed unloading demux: hr=0x%8lx", hr
);
3123 p_mpeg_demux
= NULL
;
3126 // msg_Dbg( p_access, "Destroy: sample grabber" );
3129 mem_ref
= p_grabber
->Release();
3132 msg_Dbg( p_access
, "Destroy: "\
3133 "Sample grabber mem_ref (varies): mem_ref=%ld", mem_ref
);
3138 // msg_Dbg( p_access, "Destroy: sample grabber filter" );
3139 if( p_sample_grabber
)
3141 hr
= p_filter_graph
->RemoveFilter( p_sample_grabber
);
3142 p_sample_grabber
= NULL
;
3145 msg_Dbg( p_access
, "Destroy: "\
3146 "Failed unloading sampler: hr=0x%8lx", hr
);
3150 // msg_Dbg( p_access, "Destroy: capture device" );
3151 if( p_capture_device
)
3153 p_filter_graph
->RemoveFilter( p_capture_device
);
3156 msg_Dbg( p_access
, "Destroy: "\
3157 "Failed unloading capture device: hr=0x%8lx", hr
);
3159 p_capture_device
= NULL
;
3162 // msg_Dbg( p_access, "Destroy: tuner device" );
3163 if( p_tuner_device
)
3165 //msg_Dbg( p_access, "Destroy: remove filter on tuner device" );
3166 hr
= p_filter_graph
->RemoveFilter( p_tuner_device
);
3167 //msg_Dbg( p_access, "Destroy: force tuner device to NULL" );
3168 p_tuner_device
= NULL
;
3171 msg_Dbg( p_access
, "Destroy: "\
3172 "Failed unloading tuner device: hr=0x%8lx", hr
);
3176 // msg_Dbg( p_access, "Destroy: scanning tuner" );
3177 if( p_scanning_tuner
)
3179 mem_ref
= p_scanning_tuner
->Release();
3182 msg_Dbg( p_access
, "Destroy: "\
3183 "Scanning tuner mem_ref (normally 2 if warm, "\
3184 "3 if active): mem_ref=%ld", mem_ref
);
3186 p_scanning_tuner
= NULL
;
3189 // msg_Dbg( p_access, "Destroy: net provider" );
3190 if( p_network_provider
)
3192 hr
= p_filter_graph
->RemoveFilter( p_network_provider
);
3193 p_network_provider
= NULL
;
3196 msg_Dbg( p_access
, "Destroy: "\
3197 "Failed unloading net provider: hr=0x%8lx", hr
);
3201 // msg_Dbg( p_access, "Destroy: filter graph" );
3202 if( p_filter_graph
)
3204 mem_ref
= p_filter_graph
->Release();
3207 msg_Dbg( p_access
, "Destroy: "\
3208 "Filter graph mem_ref (normally 1 if active): mem_ref=%ld",
3211 p_filter_graph
= NULL
;
3214 /* first call to FindFilter creates p_system_dev_enum */
3216 // msg_Dbg( p_access, "Destroy: system dev enum" );
3217 if( p_system_dev_enum
)
3219 mem_ref
= p_system_dev_enum
->Release();
3222 msg_Dbg( p_access
, "Destroy: "\
3223 "System_dev_enum mem_ref: mem_ref=%ld", mem_ref
);
3225 p_system_dev_enum
= NULL
;
3228 // msg_Dbg( p_access, "Destroy: media control 2" );
3229 if( p_media_control
)
3231 msg_Dbg( p_access
, "Destroy: release media control" );
3232 mem_ref
= p_media_control
->Release();
3235 msg_Dbg( p_access
, "Destroy: "\
3236 "Media control mem_ref: mem_ref=%ld", mem_ref
);
3238 msg_Dbg( p_access
, "Destroy: force media control to NULL" );
3239 p_media_control
= NULL
;
3242 d_graph_register
= 0;
3244 guid_network_type
= GUID_NULL
;
3246 // msg_Dbg( p_access, "Destroy: returning" );
3250 /*****************************************************************************
3251 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
3252 * Allows GraphEdit to "spy" on a remote filter graph.
3253 ******************************************************************************/
3254 HRESULT
BDAGraph::Register()
3259 IMoniker
* p_moniker
;
3260 IRunningObjectTable
* p_ro_table
;
3268 p_moniker
->Release();
3270 p_ro_table
->Release();
3273 WCHAR pwsz_graph_name
[128];
3276 hr
= ::GetRunningObjectTable( 0, &l
.p_ro_table
);
3279 msg_Warn( p_access
, "Register: Cannot get ROT: hr=0x%8lx", hr
);
3283 size_t len
= sizeof(pwsz_graph_name
) / sizeof(pwsz_graph_name
[0]);
3284 _snwprintf( pwsz_graph_name
, len
- 1, L
"VLC BDA Graph %08x Pid %08x",
3285 (DWORD_PTR
) p_filter_graph
, ::GetCurrentProcessId() );
3286 pwsz_graph_name
[len
-1] = 0;
3287 hr
= CreateItemMoniker( L
"!", pwsz_graph_name
, &l
.p_moniker
);
3290 msg_Warn( p_access
, "Register: Cannot Create Moniker: hr=0x%8lx", hr
);
3293 hr
= l
.p_ro_table
->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE
,
3294 p_filter_graph
, l
.p_moniker
, &d_graph_register
);
3297 msg_Warn( p_access
, "Register: Cannot Register Graph: hr=0x%8lx", hr
);
3301 msg_Dbg( p_access
, "Register: registered Graph: %S", pwsz_graph_name
);
3305 void BDAGraph::Deregister()
3308 IRunningObjectTable
* p_ro_table
;
3309 hr
= ::GetRunningObjectTable( 0, &p_ro_table
);
3310 /* docs say this does a Release() on d_graph_register stuff */
3311 if( SUCCEEDED( hr
) )
3312 p_ro_table
->Revoke( d_graph_register
);
3313 d_graph_register
= 0;
3314 p_ro_table
->Release();
3317 HRESULT
BDAGraph::GetFilterName( IBaseFilter
* p_filter
, char** psz_bstr_name
)
3319 FILTER_INFO filter_info
;
3322 hr
= p_filter
->QueryFilterInfo(&filter_info
);
3325 int i_name_len
= WideCharToMultiByte( CP_ACP
, 0, filter_info
.achName
,
3326 -1, *psz_bstr_name
, 0, NULL
, NULL
);
3327 *psz_bstr_name
= new char[ i_name_len
];
3328 i_name_len
= WideCharToMultiByte( CP_ACP
, 0, filter_info
.achName
,
3329 -1, *psz_bstr_name
, i_name_len
, NULL
, NULL
);
3331 // The FILTER_INFO structure holds a pointer to the Filter Graph
3332 // Manager, with a reference count that must be released.
3333 if( filter_info
.pGraph
)
3334 filter_info
.pGraph
->Release();
3338 HRESULT
BDAGraph::GetPinName( IPin
* p_pin
, char** psz_bstr_name
)
3343 hr
= p_pin
->QueryPinInfo(&pin_info
);
3346 int i_name_len
= WideCharToMultiByte( CP_ACP
, 0, pin_info
.achName
,
3347 -1, *psz_bstr_name
, 0, NULL
, NULL
);
3348 *psz_bstr_name
= new char[ i_name_len
];
3349 i_name_len
= WideCharToMultiByte( CP_ACP
, 0, pin_info
.achName
,
3350 -1, *psz_bstr_name
, i_name_len
, NULL
, NULL
);
3352 // The PIN_INFO structure holds a pointer to the Filter,
3353 // with a referenppce count that must be released.
3354 if( pin_info
.pFilter
)
3355 pin_info
.pFilter
->Release();
3359 IPin
* BDAGraph::FindPinOnFilter( IBaseFilter
* pBaseFilter
, const char* pPinName
)
3362 IEnumPins
*pEnumPin
= NULL
;
3363 ULONG CountReceived
= 0;
3364 IPin
*pPin
= NULL
, *pThePin
= NULL
;
3370 if (!pBaseFilter
|| !pPinName
)
3373 // enumerate of pins on the filter
3374 hr
= pBaseFilter
->EnumPins(&pEnumPin
);
3375 if (hr
== S_OK
&& pEnumPin
)
3378 while (pEnumPin
->Next( 1, &pPin
, &CountReceived
) == S_OK
&& pPin
)
3380 memset(String
, 0, sizeof(String
));
3382 hr
= pPin
->QueryPinInfo(&PinInfo
);
3385 length
= wcslen (PinInfo
.achName
) + 1;
3386 pString
= new char [length
];
3389 WideCharToMultiByte(CP_ACP
, 0, PinInfo
.achName
, -1, pString
, length
,
3392 //strcat (String, pString);
3393 //StringCbCat(String,strlen(String) + strlen(pString)+1,pString);
3394 snprintf( String
, strlen(String
) + strlen(pString
) + 1, "%s%s", String
, pString
);
3397 if (strstr(String
, pPinName
))
3398 pThePin
= pPin
; // yes
3407 // need to release this pin
3412 } // end if have pin
3414 // need to release the enumerator
3415 pEnumPin
->Release();
3418 // return address of pin if found on the filter