contrib: soxr: enable by default
[vlc.git] / modules / access / dtv / bdagraph.cpp
blobea36bc9ff9a6eb6ff08bdf14a0d8358f430119cd
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 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
32 #include <assert.h>
34 #include <vlc_common.h>
35 #include <vlc_block.h>
36 #include "dtv/bdagraph.hpp"
37 #include "dtv/dtv.h"
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)
52 switch (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)
65 switch (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)
77 switch (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)
87 switch (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)
98 switch (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)
110 switch (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 ****************************************************************************/
123 struct dvb_device
125 BDAGraph *module;
127 /* DVB-S property cache */
128 uint32_t frequency;
129 uint32_t srate;
130 uint32_t fec;
131 char inversion;
132 char pol;
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);
141 d->frequency = 0;
142 d->srate = 0;
143 d->fec = VLC_FEC_AUTO;
144 d->inversion = -1;
145 d->pol = 0;
146 d->lowf = d->highf = d->switchf = 0;
147 return d;
150 void dvb_close (dvb_device_t *d)
152 ComContext ctx( COINIT_APARTMENTTHREADED );
153 delete d->module;
154 delete d;
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)
164 return 0;
167 void dvb_remove_pid (dvb_device_t *, uint16_t)
171 bool dvb_get_pid_state (const dvb_device_t *, uint16_t)
173 return true;
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 * )
210 return -1;
213 bool dvb_set_ca_pmt (dvb_device_t *, en50221_capmt_info_t *)
215 return false;
218 /* DVB-C */
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);
226 /* DVB-S */
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;
231 d->srate = srate;
232 d->fec = fec;
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*/,
239 uint8_t /*sid*/)
241 return VLC_EGENERIC;
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;
249 d->pol = pol;
250 d->lowf = lowf;
251 d->highf = highf;
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);
257 /* DVB-T */
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);
267 /* DVB-T2 */
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);
277 /* ISDB-C */
278 int dvb_set_isdbc (dvb_device_t *, uint32_t /*freq*/, const char * /*mod*/,
279 uint32_t /*srate*/, uint32_t /*fec*/)
281 return VLC_EGENERIC;
284 /* ISDB-S */
285 int dvb_set_isdbs (dvb_device_t *, uint64_t /*freq*/, uint16_t /*ts_id*/)
287 return VLC_EGENERIC;
290 /* ISDB-T */
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])
295 return VLC_EGENERIC;
298 /* ATSC */
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 /*****************************************************************************
312 * BDAOutput
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()
323 Empty();
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)
338 if( ms < 0 )
339 ms = 250;
341 vlc_mutex_locker l( &lock );
343 mtime_t i_deadline = mdate() + ms * 1000;
344 while( !p_first )
346 if( vlc_cond_timedwait( &wait, &lock, i_deadline ) )
347 return -1;
350 size_t i_index = 0;
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 );
356 i_index += 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 );
366 p_first = p_next;
367 if( !p_first )
369 pp_next = &p_first;
370 break;
374 return i_index;
377 void BDAOutput::Empty()
379 vlc_mutex_locker l( &lock );
381 if( p_first )
382 block_ChainRelease( p_first );
383 p_first = NULL;
384 pp_next = &p_first;
387 /*****************************************************************************
388 * Constructor
389 *****************************************************************************/
390 BDAGraph::BDAGraph( vlc_object_t *p_this ):
391 ul_cbrc( 0 ),
392 p_access( p_this ),
393 guid_network_type(GUID_NULL),
394 l_tuner_used(-1),
395 systems(0),
396 d_graph_register( 0 ),
397 output( p_this )
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;
408 p_grabber = NULL;
411 /*****************************************************************************
412 * Destructor
413 *****************************************************************************/
414 BDAGraph::~BDAGraph()
416 Destroy();
418 if( p_tuning_space )
419 p_tuning_space->Release();
420 p_tuning_space = NULL;
422 systems = 0;
425 /*****************************************************************************
426 * GetSystem
427 * helper function
428 *****************************************************************************/
429 unsigned BDAGraph::GetSystem( REFCLSID clsid )
431 unsigned sys = 0;
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;
444 return sys;
448 /*****************************************************************************
449 * Enumerate Systems
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
457 * the end
458 *****************************************************************************/
459 unsigned BDAGraph::EnumSystems()
461 HRESULT hr = S_OK;
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 );
471 if( FAILED( hr ) )
472 msg_Dbg( p_access, "EnumSystems: Check failed, trying next" );
474 while( true );
476 if( p_filter_graph )
477 Destroy();
478 msg_Dbg( p_access, "EnumSystems: Returning systems 0x%08x", systems );
479 return systems;
482 float BDAGraph::GetSignalNoiseRatio(void)
484 /* not implemented until Windows 7
485 * IBDA_Encoder::GetState */
486 return 0.;
489 float BDAGraph::GetSignalStrength(void)
491 HRESULT hr = S_OK;
492 long l_strength = 0;
493 msg_Dbg( p_access, "GetSignalStrength: entering" );
494 if( !p_scanning_tuner)
495 return 0.;
496 hr = p_scanning_tuner->get_SignalStrength( &l_strength );
497 if( FAILED( hr ) )
499 msg_Warn( p_access, "GetSignalStrength: "
500 "Cannot get value: hr=0x%8lx", hr );
501 return 0.;
503 msg_Dbg( p_access, "GetSignalStrength: got %ld", l_strength );
504 if( l_strength == -1 )
505 return -1.;
506 return l_strength / 100.;
509 int BDAGraph::SubmitTuneRequest(void)
511 HRESULT hr;
512 int i = 0;
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
516 * devices */
519 msg_Dbg( p_access, "SubmitTuneRequest: Building the Graph" );
521 hr = Build();
522 if( FAILED( hr ) )
524 msg_Warn( p_access, "SubmitTuneRequest: "
525 "Cannot Build the Graph: hr=0x%8lx", hr );
526 return VLC_EGENERIC;
528 msg_Dbg( p_access, "SubmitTuneRequest: Starting the Graph" );
530 hr = Start();
531 if( FAILED( hr ) )
533 msg_Dbg( p_access, "SubmitTuneRequest: "
534 "Cannot Start the Graph, retrying: hr=0x%8lx", hr );
535 ++i;
538 while( hr != S_OK && i < 10 ); /* give up after 10 tries */
540 if( FAILED( hr ) )
542 msg_Warn( p_access, "SubmitTuneRequest: "
543 "Failed to Start the Graph: hr=0x%8lx", hr );
544 return VLC_EGENERIC;
547 return VLC_SUCCESS;
550 /*****************************************************************************
551 * Set Clear QAM (DigitalCable)
552 * Local ATSC Digital Antenna
553 *****************************************************************************/
554 int BDAGraph::SetCQAM(long l_frequency)
556 HRESULT hr = S_OK;
557 class localComPtr
559 public:
560 ITuneRequest* p_tune_request;
561 IDigitalCableTuneRequest* p_cqam_tune_request;
562 IDigitalCableLocator* p_cqam_locator;
563 localComPtr():
564 p_tune_request(NULL),
565 p_cqam_tune_request(NULL),
566 p_cqam_locator(NULL)
568 ~localComPtr()
570 if( p_tune_request )
571 p_tune_request->Release();
572 if( p_cqam_tune_request )
573 p_cqam_tune_request->Release();
574 if( p_cqam_locator )
575 p_cqam_locator->Release();
577 } l;
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 );
585 if( FAILED( hr ) )
587 msg_Warn( p_access, "SetCQAM: "\
588 "Cannot create Tuning Space: hr=0x%8lx", hr );
589 return VLC_EGENERIC;
592 if( !p_scanning_tuner )
594 msg_Warn( p_access, "SetCQAM: Cannot get scanning tuner" );
595 return VLC_EGENERIC;
598 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
599 if( FAILED( hr ) )
601 msg_Warn( p_access, "SetCQAM: "\
602 "Cannot get Tune Request: hr=0x%8lx", hr );
603 return VLC_EGENERIC;
606 hr = l.p_tune_request->QueryInterface( IID_IDigitalCableTuneRequest,
607 reinterpret_cast<void**>( &l.p_cqam_tune_request ) );
608 if( FAILED( hr ) )
610 msg_Warn( p_access, "SetCQAM: "\
611 "Cannot QI for IDigitalCableTuneRequest: hr=0x%8lx", hr );
612 return VLC_EGENERIC;
615 hr = ::CoCreateInstance( CLSID_DigitalCableLocator, 0, CLSCTX_INPROC,
616 IID_IDigitalCableLocator, reinterpret_cast<void**>( &l.p_cqam_locator ) );
617 if( FAILED( hr ) )
619 msg_Warn( p_access, "SetCQAM: "\
620 "Cannot create the CQAM locator: hr=0x%8lx", hr );
621 return VLC_EGENERIC;
624 hr = S_OK;
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 );
631 if( FAILED( hr ) )
633 msg_Warn( p_access, "SetCQAM: "\
634 "Cannot set tuning parameters: hr=0x%8lx", hr );
635 return VLC_EGENERIC;
638 hr = l.p_cqam_tune_request->put_Locator( l.p_cqam_locator );
639 if( FAILED( hr ) )
641 msg_Warn( p_access, "SetCQAM: "\
642 "Cannot put the locator: hr=0x%8lx", hr );
643 return VLC_EGENERIC;
646 hr = p_scanning_tuner->Validate( l.p_cqam_tune_request );
647 if( FAILED( hr ) )
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 );
654 if( FAILED( hr ) )
656 msg_Warn( p_access, "SetCQAM: "\
657 "Cannot put the tune request: hr=0x%8lx", hr );
658 return VLC_EGENERIC;
661 return VLC_SUCCESS;
664 /*****************************************************************************
665 * Set ATSC
666 *****************************************************************************/
667 int BDAGraph::SetATSC(long l_frequency)
669 HRESULT hr = S_OK;
670 class localComPtr
672 public:
673 ITuneRequest* p_tune_request;
674 IATSCChannelTuneRequest* p_atsc_tune_request;
675 IATSCLocator* p_atsc_locator;
676 localComPtr():
677 p_tune_request(NULL),
678 p_atsc_tune_request(NULL),
679 p_atsc_locator(NULL)
681 ~localComPtr()
683 if( p_tune_request )
684 p_tune_request->Release();
685 if( p_atsc_tune_request )
686 p_atsc_tune_request->Release();
687 if( p_atsc_locator )
688 p_atsc_locator->Release();
690 } l;
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 );
700 if( FAILED( hr ) )
702 msg_Warn( p_access, "SetATSC: "\
703 "Cannot create Tuning Space: hr=0x%8lx", hr );
704 return VLC_EGENERIC;
707 if( !p_scanning_tuner )
709 msg_Warn( p_access, "SetATSC: Cannot get scanning tuner" );
710 return VLC_EGENERIC;
713 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
714 if( FAILED( hr ) )
716 msg_Warn( p_access, "SetATSC: "\
717 "Cannot get Tune Request: hr=0x%8lx", hr );
718 return VLC_EGENERIC;
721 hr = l.p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
722 reinterpret_cast<void**>( &l.p_atsc_tune_request ) );
723 if( FAILED( hr ) )
725 msg_Warn( p_access, "SetATSC: "\
726 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
727 return VLC_EGENERIC;
730 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
731 IID_IATSCLocator, reinterpret_cast<void**>( &l.p_atsc_locator ) );
732 if( FAILED( hr ) )
734 msg_Warn( p_access, "SetATSC: "\
735 "Cannot create the ATSC locator: hr=0x%8lx", hr );
736 return VLC_EGENERIC;
739 hr = S_OK;
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 );
748 if( FAILED( hr ) )
750 msg_Warn( p_access, "SetATSC: "\
751 "Cannot set tuning parameters: hr=0x%8lx", hr );
752 return VLC_EGENERIC;
755 hr = l.p_atsc_tune_request->put_Locator( l.p_atsc_locator );
756 if( FAILED( hr ) )
758 msg_Warn( p_access, "SetATSC: "\
759 "Cannot put the locator: hr=0x%8lx", hr );
760 return VLC_EGENERIC;
763 hr = p_scanning_tuner->Validate( l.p_atsc_tune_request );
764 if( FAILED( hr ) )
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 );
771 if( FAILED( hr ) )
773 msg_Warn( p_access, "SetATSC: "\
774 "Cannot put the tune request: hr=0x%8lx", hr );
775 return VLC_EGENERIC;
778 return VLC_SUCCESS;
781 /*****************************************************************************
782 * Set DVB-T
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)
792 HRESULT hr = S_OK;
794 class localComPtr
796 public:
797 ITuneRequest* p_tune_request;
798 IDVBTuneRequest* p_dvb_tune_request;
799 IDVBTLocator* p_dvbt_locator;
800 IDVBTuningSpace2* p_dvb_tuning_space;
801 localComPtr():
802 p_tune_request(NULL),
803 p_dvb_tune_request(NULL),
804 p_dvbt_locator(NULL),
805 p_dvb_tuning_space(NULL)
807 ~localComPtr()
809 if( p_tune_request )
810 p_tune_request->Release();
811 if( p_dvb_tune_request )
812 p_dvb_tune_request->Release();
813 if( p_dvbt_locator )
814 p_dvbt_locator->Release();
815 if( p_dvb_tuning_space )
816 p_dvb_tuning_space->Release();
818 } l;
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 );
831 if( FAILED( hr ) )
833 msg_Warn( p_access, "SetDVBT: "\
834 "Cannot create Tuning Space: hr=0x%8lx", hr );
835 return VLC_EGENERIC;
838 if( !p_scanning_tuner )
840 msg_Warn( p_access, "SetDVBT: Cannot get scanning tuner" );
841 return VLC_EGENERIC;
844 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
845 if( FAILED( hr ) )
847 msg_Warn( p_access, "SetDVBT: "\
848 "Cannot get Tune Request: hr=0x%8lx", hr );
849 return VLC_EGENERIC;
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 ) );
855 if( FAILED( hr ) )
857 msg_Warn( p_access, "SetDVBT: "\
858 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
859 return VLC_EGENERIC;
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 );
868 if( FAILED( hr ) )
870 msg_Dbg( p_access, "SetDVBT: "\
871 "cannot get tuning space: hr=0x%8lx", hr );
872 return VLC_EGENERIC;
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 ) );
878 if( FAILED( hr ) )
880 msg_Warn( p_access, "SetDVBT: "\
881 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
882 return VLC_EGENERIC;
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 ) );
888 if( FAILED( hr ) )
890 msg_Warn( p_access, "SetDVBT: "\
891 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
892 return VLC_EGENERIC;
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 );
911 if( FAILED( hr ) )
913 msg_Warn( p_access, "SetDVBT: "\
914 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
915 return VLC_EGENERIC;
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 );
921 if( FAILED( hr ) )
923 msg_Warn( p_access, "SetDVBT: "\
924 "Cannot put the locator: hr=0x%8lx", hr );
925 return VLC_EGENERIC;
928 msg_Dbg( p_access, "SetDVBT: putting local Tune Request to scanning tuner" );
929 hr = p_scanning_tuner->Validate( l.p_dvb_tune_request );
930 if( FAILED( hr ) )
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 );
937 if( FAILED( hr ) )
939 msg_Warn( p_access, "SetDVBT: "\
940 "Cannot put the tune request: hr=0x%8lx", hr );
941 return VLC_EGENERIC;
944 msg_Dbg( p_access, "SetDVBT: return success" );
945 return VLC_SUCCESS;
948 /*****************************************************************************
949 * Set DVB-T2
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)
959 HRESULT hr = S_OK;
961 class localComPtr
963 public:
964 ITuneRequest* p_tune_request;
965 IDVBTuneRequest* p_dvb_tune_request;
966 IDVBTLocator2* p_dvbt_locator;
967 IDVBTuningSpace2* p_dvb_tuning_space;
968 localComPtr():
969 p_tune_request(NULL),
970 p_dvb_tune_request(NULL),
971 p_dvbt_locator(NULL),
972 p_dvb_tuning_space(NULL)
974 ~localComPtr()
976 if( p_tune_request )
977 p_tune_request->Release();
978 if( p_dvb_tune_request )
979 p_dvb_tune_request->Release();
980 if( p_dvbt_locator )
981 p_dvbt_locator->Release();
982 if( p_dvb_tuning_space )
983 p_dvb_tuning_space->Release();
985 } l;
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);
992 long l_plp = plp;
994 /* try to set p_scanning_tuner */
995 msg_Dbg( p_access, "SetDVBT: set up scanning tuner" );
996 hr = Check( CLSID_DVBTNetworkProvider );
997 if( FAILED( hr ) )
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 );
1011 if( FAILED( hr ) )
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 ) );
1021 if( FAILED( hr ) )
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 );
1034 if( FAILED( hr ) )
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 ) );
1044 if( FAILED( hr ) )
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 ) );
1057 if( FAILED( hr ) )
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);
1081 if( FAILED( hr ) )
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 );
1091 if( FAILED( hr ) )
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 );
1100 if( FAILED( hr ) )
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 );
1107 if( FAILED( hr ) )
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");
1117 if( pinInput0)
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));
1122 if( FAILED( hr ))
1124 msg_Dbg( p_access, "SetDVBT: Cannot query for IKsPropertySet (this can be normal if not TBS tuner) : hr=0x%8lx", hr );
1126 else
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,
1134 NULL,
1136 &plp_info,
1137 sizeof( TBS_PLP_INFO ));
1138 msg_Dbg( p_access, "SetDVBT: TBS tuner set PLP: %d", plp);
1139 p_ksPropertySet->Release();
1141 pinInput0->Release();
1143 else
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" );
1149 return VLC_SUCCESS;
1153 /*****************************************************************************
1154 * Set DVB-C
1155 ******************************************************************************/
1156 int BDAGraph::SetDVBC(long l_frequency, const char *mod, long l_symbolrate)
1158 HRESULT hr = S_OK;
1160 class localComPtr
1162 public:
1163 ITuneRequest* p_tune_request;
1164 IDVBTuneRequest* p_dvb_tune_request;
1165 IDVBCLocator* p_dvbc_locator;
1166 IDVBTuningSpace2* p_dvb_tuning_space;
1168 localComPtr():
1169 p_tune_request(NULL),
1170 p_dvb_tune_request(NULL),
1171 p_dvbc_locator(NULL),
1172 p_dvb_tuning_space(NULL)
1174 ~localComPtr()
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();
1185 } l;
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" );
1193 if( FAILED( hr ) )
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 );
1209 if( FAILED( hr ) )
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 ) );
1219 if( FAILED( hr ) )
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 ) );
1233 if( FAILED( hr ) )
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 );
1243 if( FAILED( hr ) )
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 ) );
1253 if( FAILED( hr ) )
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" );
1261 hr = S_OK;
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 );
1271 if( FAILED( hr ) )
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 );
1280 if( FAILED( hr ) )
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 );
1289 if( FAILED( hr ) )
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 );
1298 if( FAILED( hr ) )
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" );
1306 return VLC_SUCCESS;
1309 /*****************************************************************************
1310 * Set Inversion
1311 ******************************************************************************/
1312 int BDAGraph::SetInversion(int inversion)
1314 HRESULT hr = S_OK;
1315 class localComPtr
1317 public:
1318 IDVBSTuningSpace* p_dvbs_tuning_space;
1319 localComPtr() :
1320 p_dvbs_tuning_space(NULL)
1322 ~localComPtr()
1324 if( p_dvbs_tuning_space )
1325 p_dvbs_tuning_space->Release();
1327 } l;
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" );
1345 return VLC_SUCCESS;
1348 msg_Dbg( p_access, "SetInversion: get TS" );
1349 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
1350 if( FAILED( hr ) )
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 ) );
1359 if( FAILED( hr ) )
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 );
1368 if( FAILED( hr ) )
1370 msg_Warn( p_access, "SetInversion: "\
1371 "Cannot put inversion: hr=0x%8lx", hr );
1372 return VLC_EGENERIC;
1375 return VLC_SUCCESS;
1378 /*****************************************************************************
1379 * Set DVB-S
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)
1385 HRESULT hr = S_OK;
1387 class localComPtr
1389 public:
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;
1398 int i_range_len;
1399 localComPtr() :
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),
1408 i_range_len(0)
1410 ~localComPtr()
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 );
1426 } l;
1427 long l_azimuth, l_elevation, l_longitude;
1428 long l_network_id;
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 )
1441 abort();
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 );
1458 if( FAILED( hr ) )
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 );
1472 if( FAILED( hr ) )
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 ) );
1481 if( FAILED( hr ) )
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 ) );
1494 if( FAILED( hr ) )
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 );
1503 if( FAILED( hr ) )
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 ) );
1512 if( FAILED( hr ) )
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 ) );
1553 if( FAILED( hr ) )
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 );
1561 if( FAILED( hr ) )
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 );
1569 if( FAILED( hr ) )
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 );
1577 if( FAILED( hr ) )
1579 msg_Warn( p_access, "SetDVBS: "\
1580 "Cannot put the tune request: hr=0x%8lx", hr );
1581 return VLC_EGENERIC;
1584 return VLC_SUCCESS;
1587 /*****************************************************************************
1588 * SetUpTuner
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 )
1604 HRESULT hr = S_OK;
1605 class localComPtr
1607 public:
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;
1621 BSTR bstr_name;
1623 CLSID guid_test_network_type;
1624 char* psz_network_name;
1625 char* psz_bstr_name;
1626 int i_name_len;
1628 localComPtr():
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),
1636 p_locator(NULL),
1637 p_dvbt_locator(NULL),
1638 p_dvbc_locator(NULL),
1639 p_dvbs_locator(NULL),
1640 bstr_name(NULL),
1641 guid_test_network_type(GUID_NULL),
1642 psz_network_name(NULL),
1643 psz_bstr_name(NULL),
1644 i_name_len(0)
1646 ~localComPtr()
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();
1662 if( p_locator )
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 );
1674 } l;
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 );
1692 else
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
1700 * a new one */
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" );
1706 return E_FAIL;
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 );
1713 if( FAILED( hr ) )
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 );
1727 if( FAILED( hr ) )
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 );
1732 goto NoTuningSpace;
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",
1751 l.psz_bstr_name );
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 ) )
1757 return S_OK;
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 ) )
1764 return S_OK;
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 */
1773 NoTuningSpace:
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 );
1796 if( FAILED( hr ) )
1798 msg_Warn( p_access, "SetUpTuner: "\
1799 "Cannot create TuningSpaces Enumerator: hr=0x%8lx", hr );
1800 goto TryToClone;
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 );
1814 l.bstr_name = NULL;
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 );
1822 if( FAILED( hr ) )
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 );
1836 if( FAILED( hr ) )
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 );
1841 continue;
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",
1852 l.psz_bstr_name );
1853 break;
1857 while( true );
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" );
1863 goto TryToClone;
1866 msg_Dbg( p_access, "SetUpTuner: put TS" );
1867 hr = p_scanning_tuner->put_TuningSpace( l.p_test_tuning_space );
1868 if( FAILED( hr ) )
1870 msg_Dbg( p_access, "SetUpTuner: "\
1871 "cannot put tuning space: hr=0x%8lx", hr );
1872 goto TryToClone;
1875 msg_Dbg( p_access, "SetUpTuner: get default locator" );
1876 hr = l.p_test_tuning_space->get_DefaultLocator( &l.p_locator );
1877 if( FAILED( hr ) )
1879 msg_Dbg( p_access, "SetUpTuner: "\
1880 "cannot get default locator: hr=0x%8lx", hr );
1881 goto TryToClone;
1884 msg_Dbg( p_access, "SetUpTuner: create tune request" );
1885 hr = l.p_test_tuning_space->CreateTuneRequest( &l.p_tune_request );
1886 if( FAILED( hr ) )
1888 msg_Dbg( p_access, "SetUpTuner: "\
1889 "cannot create tune request: hr=0x%8lx", hr );
1890 goto TryToClone;
1893 msg_Dbg( p_access, "SetUpTuner: put locator" );
1894 hr = l.p_tune_request->put_Locator( l.p_locator );
1895 if( FAILED( hr ) )
1897 msg_Dbg( p_access, "SetUpTuner: "\
1898 "cannot put locator: hr=0x%8lx", hr );
1899 goto TryToClone;
1902 msg_Dbg( p_access, "SetUpTuner: try to validate tune request" );
1903 hr = p_scanning_tuner->Validate( l.p_tune_request );
1904 if( FAILED( hr ) )
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 );
1913 if( FAILED( hr ) )
1915 msg_Warn( p_access, "SetUpTuner: "\
1916 "Cannot submit the tune request: hr=0x%8lx", hr );
1917 return hr;
1920 msg_Dbg( p_access, "SetUpTuner: Tuning Space and Tune Request created" );
1921 return S_OK;
1923 /* Get the SystemTuningSpaces container
1924 * p_tuning_space_container->Refcount = 1 */
1925 TryToClone:
1926 msg_Warn( p_access, "SetUpTuner: won't try to clone " );
1927 return E_FAIL;
1930 /*****************************************************************************
1931 * GetNextNetworkType
1932 * helper function; this is probably best done as an Enumeration of
1933 * network providers
1934 *****************************************************************************/
1935 HRESULT BDAGraph::GetNextNetworkType( CLSID* guid_this_network_type )
1937 HRESULT hr = S_OK;
1938 if( *guid_this_network_type == GUID_NULL )
1940 msg_Dbg( p_access, "GetNextNetworkType: DVB-C" );
1941 *guid_this_network_type = CLSID_DVBCNetworkProvider;
1942 return S_OK;
1944 if( *guid_this_network_type == CLSID_DVBCNetworkProvider )
1946 msg_Dbg( p_access, "GetNextNetworkType: DVB-T" );
1947 *guid_this_network_type = CLSID_DVBTNetworkProvider;
1948 return S_OK;
1950 if( *guid_this_network_type == CLSID_DVBTNetworkProvider )
1952 msg_Dbg( p_access, "GetNextNetworkType: DVB-S" );
1953 *guid_this_network_type = CLSID_DVBSNetworkProvider;
1954 return S_OK;
1956 if( *guid_this_network_type == CLSID_DVBSNetworkProvider )
1958 msg_Dbg( p_access, "GetNextNetworkType: ATSC" );
1959 *guid_this_network_type = CLSID_ATSCNetworkProvider;
1960 return S_OK;
1962 msg_Dbg( p_access, "GetNextNetworkType: failed" );
1963 *guid_this_network_type = GUID_NULL;
1964 hr = E_FAIL;
1965 return hr;
1969 /******************************************************************************
1970 * Check
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 )
1980 HRESULT hr = S_OK;
1982 class localComPtr
1984 public:
1985 ITuningSpaceContainer* p_tuning_space_container;
1987 localComPtr():
1988 p_tuning_space_container(NULL)
1990 ~localComPtr()
1992 if( p_tuning_space_container )
1993 p_tuning_space_container->Release();
1995 } l;
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 )
2012 Destroy();
2013 p_filter_graph = NULL;
2014 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
2015 IID_IGraphBuilder, reinterpret_cast<void**>( &p_filter_graph ) );
2016 if( FAILED( hr ) )
2018 msg_Warn( p_access, "Check: "\
2019 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
2020 return 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 ) );
2030 if( FAILED( hr ) )
2032 msg_Warn( p_access, "Check: "\
2033 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
2034 return hr;
2037 msg_Dbg( p_access, "Check: adding Network Provider to graph");
2038 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
2039 if( FAILED( hr ) )
2041 msg_Warn( p_access, "Check: "\
2042 "Cannot load network provider: hr=0x%8lx", hr );
2043 return 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 ) );
2069 if( FAILED( hr ) )
2071 msg_Warn( p_access, "Check: "\
2072 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
2073 return hr;
2076 /* try to set up p_scanning_tuner */
2077 msg_Dbg( p_access, "Check: Calling SetUpTuner" );
2078 hr = SetUpTuner( guid_this_network_type );
2079 if( FAILED( hr ) )
2081 msg_Dbg( p_access, "Check: "\
2082 "Cannot set up scanner in Check mode: hr=0x%8lx", hr );
2083 return 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 );
2091 if( FAILED( hr ) )
2093 msg_Warn( p_access, "Check: "\
2094 "Cannot load tuner device and connect network provider: "\
2095 "hr=0x%8lx", hr );
2096 return hr;
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 );
2103 return E_FAIL;
2106 msg_Dbg( p_access, "Check: Using adapter %ld", l_tuner_used );
2107 /* success!
2108 * already set l_tuner_used,
2109 * p_tuning_space
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" );
2114 return S_OK;
2118 /******************************************************************************
2119 * Build
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()
2131 HRESULT hr = S_OK;
2132 long l_capture_used;
2133 long l_tif_used;
2134 AM_MEDIA_TYPE grabber_media_type;
2136 class localComPtr
2138 public:
2139 ITuningSpaceContainer* p_tuning_space_container;
2140 localComPtr():
2141 p_tuning_space_container(NULL)
2143 ~localComPtr()
2145 if( p_tuning_space_container )
2146 p_tuning_space_container->Release();
2148 } l;
2150 msg_Dbg( p_access, "Build: entering");
2152 /* at this point, you've connected to a scanning tuner of the right
2153 * network type.
2155 if( !p_scanning_tuner || !p_tuner_device )
2157 msg_Warn( p_access, "Build: "\
2158 "Scanning Tuner does not exist" );
2159 return E_FAIL;
2162 hr = p_scanning_tuner->get_TuneRequest( &p_tune_request );
2163 if( FAILED( hr ) )
2165 msg_Warn( p_access, "Build: no tune request" );
2166 return hr;
2168 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
2169 if( FAILED( hr ) )
2171 msg_Warn( p_access, "Build: no tuning space" );
2172 return hr;
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 );
2184 if( FAILED( hr ) )
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 ) );
2201 if( FAILED( hr ) )
2203 msg_Warn( p_access, "Build: "\
2204 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
2205 return hr;
2208 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
2209 if( FAILED( hr ) )
2211 msg_Warn( p_access, "Build: "\
2212 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
2213 return hr;
2216 /* create the sample grabber */
2217 if( p_grabber )
2218 p_grabber->Release();
2219 p_grabber = NULL;
2220 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
2221 reinterpret_cast<void**>( &p_grabber ) );
2222 if( FAILED( hr ) )
2224 msg_Warn( p_access, "Build: "\
2225 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
2226 return hr;
2229 /* Try the possible stream type */
2230 hr = E_FAIL;
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" );
2247 break;
2249 msg_Warn( p_access, "Build: "\
2250 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr, 1+i );
2252 else
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" );
2259 if( FAILED( hr ) )
2261 msg_Warn( p_access, "Build: "\
2262 "Cannot use capture device: hr=0x%8lx", hr );
2263 return 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" );
2270 if( p_mpeg_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 ) );
2276 if( FAILED( hr ) )
2278 msg_Warn( p_access, "Build: "\
2279 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
2280 return hr;
2283 //msg_Dbg( p_access, "Build: adding demux" );
2284 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
2285 if( FAILED( hr ) )
2287 msg_Warn( p_access, "Build: "\
2288 "Cannot add demux filter to graph: hr=0x%8lx", hr );
2289 return hr;
2292 hr = Connect( p_sample_grabber, p_mpeg_demux );
2293 if( FAILED( hr ) )
2295 msg_Warn( p_access, "Build: "\
2296 "Cannot connect demux to grabber: hr=0x%8lx", hr );
2297 return 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*/
2303 l_tif_used = -1;
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 );
2311 if( FAILED( hr ) )
2313 msg_Warn( p_access, "Build: "\
2314 "Cannot load TIF onto demux: hr=0x%8lx", hr );
2315 return hr;
2318 /* Configure the Sample Grabber to buffer the samples continuously */
2319 hr = p_grabber->SetBufferSamples( true );
2320 if( FAILED( hr ) )
2322 msg_Warn( p_access, "Build: "\
2323 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
2324 return hr;
2327 hr = p_grabber->SetOneShot( false );
2328 if( FAILED( hr ) )
2330 msg_Warn( p_access, "Build: "\
2331 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
2332 return hr;
2335 /* Second parameter to SetCallback specifies the callback method; 0 uses
2336 * the ISampleGrabberCB::SampleCB method, which receives an IMediaSample
2337 * pointer. */
2338 //msg_Dbg( p_access, "Build: Adding grabber callback" );
2339 hr = p_grabber->SetCallback( this, 0 );
2340 if( FAILED( hr ) )
2342 msg_Warn( p_access, "Build: "\
2343 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
2344 return hr;
2347 hr = Register(); /* creates d_graph_register */
2348 if( FAILED( hr ) )
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 ) );
2361 if( FAILED( hr ) )
2363 msg_Warn( p_access, "Build: "\
2364 "Cannot QI Media Control: hr=0x%8lx", hr );
2365 return hr;
2368 /* success! */
2369 //msg_Dbg( p_access, "Build: succeeded: hr=0x%8lx", hr );
2370 return S_OK;
2373 /* debugging */
2374 HRESULT BDAGraph::ListFilters( REFCLSID this_clsid )
2376 HRESULT hr = S_OK;
2378 class localComPtr
2380 public:
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;
2390 char* psz_bstr;
2391 int i_bstr_len;
2393 localComPtr():
2394 p_local_system_dev_enum(NULL),
2395 p_moniker_enum(NULL),
2396 p_moniker(NULL),
2397 p_filter(NULL),
2398 p_this_filter(NULL),
2399 p_bind_context( NULL ),
2400 p_property_bag(NULL),
2401 psz_downstream( NULL ),
2402 psz_bstr( NULL )
2404 ~localComPtr()
2406 if( p_property_bag )
2407 p_property_bag->Release();
2408 if( p_bind_context )
2409 p_bind_context->Release();
2410 if( p_filter )
2411 p_filter->Release();
2412 if( p_this_filter )
2413 p_this_filter->Release();
2414 if( p_moniker )
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();
2420 if( psz_bstr )
2421 delete[] psz_bstr;
2422 if( psz_downstream )
2423 delete[] psz_downstream;
2425 } l;
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 ) );
2434 if( FAILED( hr ) )
2436 msg_Warn( p_access, "ListFilters: "\
2437 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
2438 return 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 );
2447 if( FAILED( hr ) )
2449 msg_Warn( p_access, "ListFilters: "\
2450 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
2451 return 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");
2466 if( l.p_filter )
2467 l.p_filter->Release();
2468 l.p_filter = NULL;
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");
2474 if( l.p_moniker )
2475 l.p_moniker->Release();
2476 l.p_moniker = NULL;
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 );
2485 if( FAILED( hr ) )
2487 msg_Dbg( p_access, "ListFilters: "\
2488 "Cannot create bind_context, trying another: hr=0x%8lx", hr );
2489 continue;
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 ) );
2495 if( FAILED( hr ) )
2497 msg_Dbg( p_access, "ListFilters: "\
2498 "Cannot create p_filter, trying another: hr=0x%8lx", hr );
2499 continue;
2502 #ifdef DEBUG_MONIKER_NAME
2503 WCHAR* pwsz_downstream = NULL;
2505 hr = l.p_moniker->GetDisplayName(l.p_bind_context, NULL,
2506 &pwsz_downstream );
2507 if( FAILED( hr ) )
2509 msg_Dbg( p_access, "ListFilters: "\
2510 "Cannot get display name, trying another: hr=0x%8lx", hr );
2511 continue;
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 );
2522 LPMALLOC p_alloc;
2523 ::CoGetMalloc( 1, &p_alloc );
2524 p_alloc->Free( pwsz_downstream );
2525 p_alloc->Release();
2526 msg_Dbg( p_access, "ListFilters: "\
2527 "Moniker name is %s", l.psz_downstream );
2528 #else
2529 l.psz_downstream = strdup( "Downstream" );
2530 #endif
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 ) );
2534 if( FAILED( hr ) )
2536 msg_Dbg( p_access, "ListFilters: "\
2537 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
2538 continue;
2541 //msg_Dbg( p_access, "ListFilters: displaying another" );
2543 while( true );
2545 return S_OK;
2548 /******************************************************************************
2549 * FindFilter
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
2553 * another match.
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 )
2560 HRESULT hr = S_OK;
2561 int i_moniker_index = -1;
2562 class localComPtr
2564 public:
2565 IEnumMoniker* p_moniker_enum;
2566 IMoniker* p_moniker;
2567 IBindCtx* p_bind_context;
2568 IPropertyBag* p_property_bag;
2569 char* psz_upstream;
2571 char* psz_downstream;
2572 VARIANT var_bstr;
2573 int i_bstr_len;
2574 localComPtr():
2575 p_moniker_enum(NULL),
2576 p_moniker(NULL),
2577 p_bind_context( NULL ),
2578 p_property_bag(NULL),
2579 psz_upstream( NULL ),
2580 psz_downstream( NULL )
2582 ::VariantInit(&var_bstr);
2584 ~localComPtr()
2586 if( p_moniker_enum )
2587 p_moniker_enum->Release();
2588 if( p_moniker )
2589 p_moniker->Release();
2590 if( p_bind_context )
2591 p_bind_context->Release();
2592 if( p_property_bag )
2593 p_property_bag->Release();
2594 if( psz_upstream )
2595 delete[] psz_upstream;
2596 if( psz_downstream )
2597 delete[] psz_downstream;
2599 ::VariantClear(&var_bstr);
2601 } l;
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 ) );
2610 if( FAILED( hr ) )
2612 msg_Warn( p_access, "FindFilter: "\
2613 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
2614 return 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 );
2621 if( FAILED( hr ) )
2623 msg_Warn( p_access, "FindFilter: "\
2624 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
2625 return hr;
2628 msg_Dbg( p_access, "FindFilter: get filter name");
2629 hr = GetFilterName( p_upstream, &l.psz_upstream );
2630 if( FAILED( hr ) )
2632 msg_Warn( p_access, "FindFilter: "\
2633 "Cannot GetFilterName: hr=0x%8lx", hr );
2634 return 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");
2654 if( l.p_moniker )
2655 l.p_moniker->Release();
2656 msg_Dbg( p_access, "FindFilter: null moniker");
2657 l.p_moniker = NULL;
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;
2665 i_moniker_index++;
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 );
2676 if( FAILED( hr ) )
2678 msg_Dbg( p_access, "FindFilter: "\
2679 "Cannot create bind_context, trying another: hr=0x%8lx", hr );
2680 continue;
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 ) );
2687 if( FAILED( hr ) )
2689 msg_Dbg( p_access, "FindFilter: "\
2690 "Cannot bind to downstream, trying another: hr=0x%8lx", hr );
2691 continue;
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,
2700 &pwsz_downstream );
2701 if( FAILED( hr ) )
2703 msg_Dbg( p_access, "FindFilter: "\
2704 "Cannot get display name, trying another: hr=0x%8lx", hr );
2705 continue;
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 );
2716 LPMALLOC p_alloc;
2717 ::CoGetMalloc( 1, &p_alloc );
2718 p_alloc->Free( pwsz_downstream );
2719 p_alloc->Release();
2720 #else
2721 l.psz_downstream = strdup( "Downstream" );
2722 #endif
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 ) );
2729 if( FAILED( hr ) )
2731 msg_Dbg( p_access, "FindFilter: "\
2732 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
2733 continue;
2736 msg_Dbg( p_access, "FindFilter: read friendly name");
2737 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
2738 if( FAILED( hr ) )
2740 msg_Dbg( p_access, "FindFilter: "\
2741 "Cannot read friendly name, next?: hr=0x%8lx", hr );
2742 continue;
2745 msg_Dbg( p_access, "FindFilter: add filter to graph" );
2746 hr = p_filter_graph->AddFilter( *p_p_downstream, l.var_bstr.bstrVal );
2747 if( FAILED( hr ) )
2749 msg_Dbg( p_access, "FindFilter: "\
2750 "Cannot add filter, trying another: hr=0x%8lx", hr );
2751 continue;
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 );
2760 return S_OK;
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 );
2768 if( FAILED( hr ) )
2770 msg_Warn( p_access, "FindFilter: "\
2771 "Failed unloading Filter: hr=0x%8lx", hr );
2772 continue;
2774 msg_Dbg( p_access, "FindFilter: trying another" );
2776 while( true );
2778 /* nothing found */
2779 msg_Warn( p_access, "FindFilter: No filter connected" );
2780 hr = E_FAIL;
2781 return hr;
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;
2790 class localComPtr
2792 public:
2793 IPin* p_pin_upstream;
2794 IPin* p_pin_downstream;
2795 IEnumPins* p_pin_upstream_enum;
2796 IEnumPins* p_pin_downstream_enum;
2797 IPin* p_pin_temp;
2798 char* psz_upstream;
2799 char* psz_downstream;
2801 localComPtr():
2802 p_pin_upstream(NULL), p_pin_downstream(NULL),
2803 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
2804 p_pin_temp(NULL),
2805 psz_upstream( NULL ),
2806 psz_downstream( NULL )
2807 { };
2808 ~localComPtr()
2810 if( p_pin_temp )
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();
2820 if( psz_upstream )
2821 delete[] psz_upstream;
2822 if( psz_downstream )
2823 delete[] psz_downstream;
2825 } l;
2827 PIN_DIRECTION pin_dir;
2829 //msg_Dbg( p_access, "Connect: entering" );
2830 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
2831 if( FAILED( hr ) )
2833 msg_Warn( p_access, "Connect: "\
2834 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
2835 return 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 );
2850 if( FAILED( hr ) )
2852 msg_Warn( p_access, "Connect: "\
2853 "Cannot GetPinName: hr=0x%8lx", hr );
2854 return hr;
2856 //msg_Dbg( p_access, "Connect: p_pin_upstream = %s", l.psz_upstream );
2858 hr = l.p_pin_upstream->QueryDirection( &pin_dir );
2859 if( FAILED( hr ) )
2861 msg_Warn( p_access, "Connect: "\
2862 "Cannot get upstream filter pin direction: hr=0x%8lx", hr );
2863 return 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 );
2877 return 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 );
2886 if( FAILED( hr ) )
2888 msg_Warn( p_access, "Connect: Cannot get "\
2889 "downstream filter enumerator: hr=0x%8lx", hr );
2890 return 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 );
2905 if( FAILED( hr ) )
2907 msg_Warn( p_access, "Connect: "\
2908 "Cannot GetPinName: hr=0x%8lx", hr );
2909 return hr;
2912 msg_Dbg( p_access, "Connect: Trying p_downstream = %s",
2913 l.psz_downstream );
2916 hr = l.p_pin_downstream->QueryDirection( &pin_dir );
2917 if( FAILED( hr ) )
2919 msg_Warn( p_access, "Connect: Cannot get "\
2920 "downstream filter pin direction: hr=0x%8lx", hr );
2921 return 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 )
2936 if( FAILED( hr ) )
2938 msg_Warn( p_access, "Connect: Cannot check "\
2939 "downstream filter connection: hr=0x%8lx", hr );
2940 return 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
2954 * pins. */
2955 return S_OK;
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 */
2962 while( true );
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 */
2976 while( true );
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" );
2980 return E_FAIL;
2983 /*****************************************************************************
2984 * Start uses MediaControl to start the graph
2985 *****************************************************************************/
2986 HRESULT BDAGraph::Start()
2988 HRESULT hr = S_OK;
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" );
2996 return E_FAIL;
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 );
3004 return S_OK;
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 )
3011 if( FAILED( hr ) )
3013 msg_Warn( p_access,
3014 "Start: Cannot get Graph state: hr=0x%8lx", hr );
3015 return 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 );
3023 return S_OK;
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() */
3029 if( FAILED( hr ) )
3031 msg_Warn( p_access,
3032 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
3033 return hr;
3036 return E_FAIL;
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 );
3067 if( p_block )
3069 memcpy( p_block->p_buffer, p_sample_data, i_sample_size );
3070 output.Push( p_block );
3073 return S_OK;
3076 STDMETHODIMP BDAGraph::BufferCB( double /*date*/, BYTE* /*buffer*/,
3077 long /*buffer_len*/ )
3079 return E_FAIL;
3082 /******************************************************************************
3083 * removes each filter from the graph
3084 ******************************************************************************/
3085 HRESULT BDAGraph::Destroy()
3087 HRESULT hr = S_OK;
3088 ULONG mem_ref = 0;
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 )
3095 Deregister();
3097 // msg_Dbg( p_access, "Destroy: calling Empty" );
3098 output.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 );
3106 if( FAILED( hr ) )
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" );
3115 if( p_mpeg_demux )
3117 p_filter_graph->RemoveFilter( p_mpeg_demux );
3118 if( FAILED( hr ) )
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" );
3127 if( p_grabber )
3129 mem_ref = p_grabber->Release();
3130 if( mem_ref != 0 )
3132 msg_Dbg( p_access, "Destroy: "\
3133 "Sample grabber mem_ref (varies): mem_ref=%ld", mem_ref );
3135 p_grabber = NULL;
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;
3143 if( FAILED( hr ) )
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 );
3154 if( FAILED( hr ) )
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;
3169 if( FAILED( hr ) )
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();
3180 if( mem_ref != 0 )
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;
3194 if( FAILED( hr ) )
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();
3205 if( mem_ref != 0 )
3207 msg_Dbg( p_access, "Destroy: "\
3208 "Filter graph mem_ref (normally 1 if active): mem_ref=%ld",
3209 mem_ref );
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();
3220 if( mem_ref != 0 )
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();
3233 if( mem_ref != 0 )
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;
3243 l_tuner_used = -1;
3244 guid_network_type = GUID_NULL;
3246 // msg_Dbg( p_access, "Destroy: returning" );
3247 return S_OK;
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()
3256 class localComPtr
3258 public:
3259 IMoniker* p_moniker;
3260 IRunningObjectTable* p_ro_table;
3261 localComPtr():
3262 p_moniker(NULL),
3263 p_ro_table(NULL)
3265 ~localComPtr()
3267 if( p_moniker )
3268 p_moniker->Release();
3269 if( p_ro_table )
3270 p_ro_table->Release();
3272 } l;
3273 WCHAR pwsz_graph_name[128];
3274 HRESULT hr;
3276 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
3277 if( FAILED( hr ) )
3279 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
3280 return 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 );
3288 if( FAILED( hr ) )
3290 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
3291 return hr;
3293 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
3294 p_filter_graph, l.p_moniker, &d_graph_register );
3295 if( FAILED( hr ) )
3297 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
3298 return hr;
3301 msg_Dbg( p_access, "Register: registered Graph: %S", pwsz_graph_name );
3302 return hr;
3305 void BDAGraph::Deregister()
3307 HRESULT hr;
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;
3320 HRESULT hr = S_OK;
3322 hr = p_filter->QueryFilterInfo(&filter_info);
3323 if( FAILED( hr ) )
3324 return hr;
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();
3335 return S_OK;
3338 HRESULT BDAGraph::GetPinName( IPin* p_pin, char** psz_bstr_name )
3340 PIN_INFO pin_info;
3341 HRESULT hr = S_OK;
3343 hr = p_pin->QueryPinInfo(&pin_info);
3344 if( FAILED( hr ) )
3345 return hr;
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();
3356 return S_OK;
3359 IPin* BDAGraph::FindPinOnFilter( IBaseFilter* pBaseFilter, const char* pPinName)
3361 HRESULT hr;
3362 IEnumPins *pEnumPin = NULL;
3363 ULONG CountReceived = 0;
3364 IPin *pPin = NULL, *pThePin = NULL;
3365 char String[80];
3366 char* pString;
3367 PIN_INFO PinInfo;
3368 int length;
3370 if (!pBaseFilter || !pPinName)
3371 return NULL;
3373 // enumerate of pins on the filter
3374 hr = pBaseFilter->EnumPins(&pEnumPin);
3375 if (hr == S_OK && pEnumPin)
3377 pEnumPin->Reset();
3378 while (pEnumPin->Next( 1, &pPin, &CountReceived) == S_OK && pPin)
3380 memset(String, 0, sizeof(String));
3382 hr = pPin->QueryPinInfo(&PinInfo);
3383 if (hr == S_OK)
3385 length = wcslen (PinInfo.achName) + 1;
3386 pString = new char [length];
3388 // get the pin name
3389 WideCharToMultiByte(CP_ACP, 0, PinInfo.achName, -1, pString, length,
3390 NULL, NULL);
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);
3396 // is there a match
3397 if (strstr(String, pPinName))
3398 pThePin = pPin; // yes
3399 else
3400 pPin = NULL; // no
3402 delete[] pString;
3405 else
3407 // need to release this pin
3408 pPin->Release();
3412 } // end if have pin
3414 // need to release the enumerator
3415 pEnumPin->Release();
3418 // return address of pin if found on the filter
3419 return pThePin;