1 /*****************************************************************************
2 * bdagraph.cpp : DirectShow BDA graph for vlc
3 *****************************************************************************
4 * Copyright (C) 2007 the VideoLAN team
5 * Copyright (C) 2011 RĂ©mi Denis-Courmont
6 * Copyright (C) 2012 John Freed
8 * Author: Ken Self <kenself(at)optusnet(dot)com(dot)au>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_block.h>
34 #include "dtv/bdagraph.hpp"
36 #undef DEBUG_MONIKER_NAME
38 static ModulationType dvb_parse_modulation (const char *mod)
40 if (!strcmp (mod, "16QAM")) return BDA_MOD_16QAM;
41 if (!strcmp (mod, "32QAM")) return BDA_MOD_32QAM;
42 if (!strcmp (mod, "64QAM")) return BDA_MOD_64QAM;
43 if (!strcmp (mod, "128QAM")) return BDA_MOD_128QAM;
44 if (!strcmp (mod, "256QAM")) return BDA_MOD_256QAM;
45 return BDA_MOD_NOT_SET;
48 static BinaryConvolutionCodeRate dvb_parse_fec (uint32_t fec)
52 case VLC_FEC(1,2): return BDA_BCC_RATE_1_2;
53 case VLC_FEC(2,3): return BDA_BCC_RATE_2_3;
54 case VLC_FEC(3,4): return BDA_BCC_RATE_3_4;
55 case VLC_FEC(5,6): return BDA_BCC_RATE_5_6;
56 case VLC_FEC(7,8): return BDA_BCC_RATE_7_8;
58 return BDA_BCC_RATE_NOT_SET;
61 static GuardInterval dvb_parse_guard (uint32_t guard)
65 case VLC_GUARD(1, 4): return BDA_GUARD_1_4;
66 case VLC_GUARD(1, 8): return BDA_GUARD_1_8;
67 case VLC_GUARD(1,16): return BDA_GUARD_1_16;
68 case VLC_GUARD(1,32): return BDA_GUARD_1_32;
70 return BDA_GUARD_NOT_SET;
73 static TransmissionMode dvb_parse_transmission (int transmit)
77 case 2: return BDA_XMIT_MODE_2K;
78 case 8: return BDA_XMIT_MODE_8K;
80 return BDA_XMIT_MODE_NOT_SET;
83 static HierarchyAlpha dvb_parse_hierarchy (int hierarchy)
87 case 1: return BDA_HALPHA_1;
88 case 2: return BDA_HALPHA_2;
89 case 4: return BDA_HALPHA_4;
91 return BDA_HALPHA_NOT_SET;
94 static Polarisation dvb_parse_polarization (char pol)
98 case 'H': return BDA_POLARISATION_LINEAR_H;
99 case 'V': return BDA_POLARISATION_LINEAR_V;
100 case 'L': return BDA_POLARISATION_CIRCULAR_L;
101 case 'R': return BDA_POLARISATION_CIRCULAR_R;
103 return BDA_POLARISATION_NOT_SET;
106 static SpectralInversion dvb_parse_inversion (int inversion)
110 case 0: return BDA_SPECTRAL_INVERSION_NORMAL;
111 case 1: return BDA_SPECTRAL_INVERSION_INVERTED;
112 case -1: return BDA_SPECTRAL_INVERSION_AUTOMATIC;
114 /* should never happen */
115 return BDA_SPECTRAL_INVERSION_NOT_SET;
118 /****************************************************************************
119 * Interfaces for calls from C
120 ****************************************************************************/
125 /* DVB-S property cache */
131 uint32_t lowf, highf, switchf;
134 dvb_device_t *dvb_open (vlc_object_t *obj)
136 dvb_device_t *d = new dvb_device_t;
138 d->module = new BDAGraph (obj);
141 d->fec = VLC_FEC_AUTO;
144 d->lowf = d->highf = d->switchf = 0;
148 void dvb_close (dvb_device_t *d)
154 ssize_t dvb_read (dvb_device_t *d, void *buf, size_t len)
156 return d->module->Pop(buf, len);
159 int dvb_add_pid (dvb_device_t *, uint16_t)
164 void dvb_remove_pid (dvb_device_t *, uint16_t)
168 unsigned dvb_enum_systems (dvb_device_t *d)
170 return d->module->EnumSystems( );
173 float dvb_get_signal_strength (dvb_device_t *d)
175 return d->module->GetSignalStrength( );
178 float dvb_get_snr (dvb_device_t *d)
180 return d->module->GetSignalNoiseRatio( );
183 int dvb_set_inversion (dvb_device_t *d, int inversion)
185 d->inversion = inversion;
186 return d->module->SetInversion( d->inversion );
189 int dvb_tune (dvb_device_t *d)
191 return d->module->SubmitTuneRequest ();
195 int dvb_set_dvbc (dvb_device_t *d, uint32_t freq, const char *mod,
196 uint32_t srate, uint32_t /*fec*/)
198 return d->module->SetDVBC (freq / 1000, mod, srate);
202 int dvb_set_dvbs (dvb_device_t *d, uint64_t freq, uint32_t srate, uint32_t fec)
204 d->frequency = freq / 1000;
207 return d->module->SetDVBS(d->frequency, d->srate, d->fec, d->inversion,
208 d->pol, d->lowf, d->highf, d->switchf);
211 int dvb_set_dvbs2 (dvb_device_t *, uint64_t /*freq*/, const char * /*mod*/,
212 uint32_t /*srate*/, uint32_t /*fec*/, int /*pilot*/, int /*rolloff*/,
218 int dvb_set_sec (dvb_device_t *d, uint64_t freq, char pol,
219 uint32_t lowf, uint32_t highf, uint32_t switchf)
221 d->frequency = freq / 1000;
225 d->switchf = switchf;
226 return d->module->SetDVBS(d->frequency, d->srate, d->fec, d->inversion,
227 d->pol, d->lowf, d->highf, d->switchf);
231 int dvb_set_dvbt (dvb_device_t *d, uint32_t freq, const char * /*mod*/,
232 uint32_t fec_hp, uint32_t fec_lp, uint32_t bandwidth,
233 int transmission, uint32_t guard, int hierarchy)
235 return d->module->SetDVBT(freq / 1000, fec_hp, fec_lp,
236 bandwidth, transmission, guard, hierarchy);
240 int dvb_set_dvbt2 (dvb_device_t *d, uint32_t freq, const char * /*mod*/,
241 uint32_t fec, uint32_t bandwidth, int transmission,
242 uint32_t guard, uint8_t plp)
244 return d->module->SetDVBT2(freq / 1000, fec,
245 bandwidth, transmission, guard, plp);
249 int dvb_set_isdbc (dvb_device_t *, uint32_t /*freq*/, const char * /*mod*/,
250 uint32_t /*srate*/, uint32_t /*fec*/)
256 int dvb_set_isdbs (dvb_device_t *, uint64_t /*freq*/, uint16_t /*ts_id*/)
262 int dvb_set_isdbt (dvb_device_t *, uint32_t /*freq*/, uint32_t /*bandwidth*/,
263 int /*transmit_mode*/, uint32_t /*guard*/,
264 const isdbt_layer_t /*layers*/[3])
270 int dvb_set_atsc (dvb_device_t *d, uint32_t freq, const char * /*mod*/)
272 return d->module->SetATSC(freq / 1000);
275 int dvb_set_cqam (dvb_device_t *d, uint32_t freq, const char * /*mod*/)
277 return d->module->SetCQAM(freq / 1000);
280 /*****************************************************************************
282 *****************************************************************************/
283 BDAOutput::BDAOutput( vlc_object_t *p_access ) :
284 p_access(p_access), p_first(NULL), pp_next(&p_first)
286 vlc_mutex_init( &lock );
287 vlc_cond_init( &wait );
290 BDAOutput::~BDAOutput()
293 vlc_mutex_destroy( &lock );
294 vlc_cond_destroy( &wait );
297 void BDAOutput::Push( block_t *p_block )
299 vlc_mutex_locker l( &lock );
301 block_ChainLastAppend( &pp_next, p_block );
302 vlc_cond_signal( &wait );
305 ssize_t BDAOutput::Pop(void *buf, size_t len)
307 vlc_mutex_locker l( &lock );
309 mtime_t i_deadline = mdate() + 250 * 1000;
312 if( vlc_cond_timedwait( &wait, &lock, i_deadline ) )
317 while( i_index < len )
319 size_t i_copy = __MIN( len - i_index, p_first->i_buffer );
320 memcpy( (uint8_t *)buf + i_index, p_first->p_buffer, i_copy );
324 p_first->p_buffer += i_copy;
325 p_first->i_buffer -= i_copy;
327 if( p_first->i_buffer <= 0 )
329 block_t *p_next = p_first->p_next;
330 block_Release( p_first );
343 void BDAOutput::Empty()
345 vlc_mutex_locker l( &lock );
348 block_ChainRelease( p_first );
353 /*****************************************************************************
355 *****************************************************************************/
356 BDAGraph::BDAGraph( vlc_object_t *p_this ):
358 guid_network_type(GUID_NULL),
361 d_graph_register( 0 ),
364 p_media_control = NULL;
366 p_tuning_space = NULL;
368 p_filter_graph = NULL;
369 p_system_dev_enum = NULL;
370 p_network_provider = p_tuner_device = p_capture_device = NULL;
371 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
372 p_scanning_tuner = NULL;
375 CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
378 /*****************************************************************************
380 *****************************************************************************/
381 BDAGraph::~BDAGraph()
386 p_tuning_space->Release();
387 p_tuning_space = NULL;
393 /*****************************************************************************
396 *****************************************************************************/
397 unsigned BDAGraph::GetSystem( REFCLSID clsid )
401 if( clsid == CLSID_DVBTNetworkProvider )
403 if( clsid == CLSID_DVBCNetworkProvider )
405 if( clsid == CLSID_DVBSNetworkProvider )
407 if( clsid == CLSID_ATSCNetworkProvider )
409 if( clsid == CLSID_DigitalCableNetworkType )
416 /*****************************************************************************
418 *****************************************************************************
419 * here is logic for special case where user uses an MRL that points
420 * to DTV but is not fully specific. This is usually dvb:// and can come
421 * either from a playlist, a channels.conf MythTV file, or from manual entry.
423 * Since this is done before the real tune request is submitted, we can
424 * use the global device enumerator, etc., so long as we do a Destroy() at
426 *****************************************************************************/
427 unsigned BDAGraph::EnumSystems()
430 GUID guid_network_provider = GUID_NULL;
432 msg_Dbg( p_access, "EnumSystems: Entering " );
436 hr = GetNextNetworkType( &guid_network_provider );
437 if( hr != S_OK ) break;
438 hr = Check( guid_network_provider );
440 msg_Dbg( p_access, "EnumSystems: Check failed, trying next" );
446 msg_Dbg( p_access, "EnumSystems: Returning systems 0x%08x", systems );
450 float BDAGraph::GetSignalNoiseRatio(void)
452 /* not implemented until Windows 7
453 * IBDA_Encoder::GetState */
457 float BDAGraph::GetSignalStrength(void)
461 msg_Dbg( p_access, "GetSignalStrength: entering" );
462 if( !p_scanning_tuner)
464 hr = p_scanning_tuner->get_SignalStrength( &l_strength );
467 msg_Warn( p_access, "GetSignalStrength: "
468 "Cannot get value: hr=0x%8lx", hr );
471 msg_Dbg( p_access, "GetSignalStrength: got %ld", l_strength );
472 if( l_strength == -1 )
474 return l_strength / 100.;
477 int BDAGraph::SubmitTuneRequest(void)
482 /* Build and Start the Graph. If a Tuner device is in use the graph will
483 * fail to start. Repeated calls to Build will check successive tuner
487 msg_Dbg( p_access, "SubmitTuneRequest: Building the Graph" );
492 msg_Warn( p_access, "SubmitTuneRequest: "
493 "Cannot Build the Graph: hr=0x%8lx", hr );
496 msg_Dbg( p_access, "SubmitTuneRequest: Starting the Graph" );
501 msg_Dbg( p_access, "SubmitTuneRequest: "
502 "Cannot Start the Graph, retrying: hr=0x%8lx", hr );
506 while( hr != S_OK && i < 10 ); /* give up after 10 tries */
510 msg_Warn( p_access, "SubmitTuneRequest: "
511 "Failed to Start the Graph: hr=0x%8lx", hr );
518 /*****************************************************************************
519 * Set Clear QAM (DigitalCable)
520 * Local ATSC Digital Antenna
521 *****************************************************************************/
522 int BDAGraph::SetCQAM(long l_frequency)
528 ITuneRequest* p_tune_request;
529 IDigitalCableTuneRequest* p_cqam_tune_request;
530 IDigitalCableLocator* p_cqam_locator;
532 p_tune_request(NULL),
533 p_cqam_tune_request(NULL),
539 p_tune_request->Release();
540 if( p_cqam_tune_request )
541 p_cqam_tune_request->Release();
543 p_cqam_locator->Release();
546 long l_minor_channel, l_physical_channel;
548 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
549 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
551 /* try to set p_scanning_tuner */
552 hr = Check( CLSID_DigitalCableNetworkType );
555 msg_Warn( p_access, "SetCQAM: "\
556 "Cannot create Tuning Space: hr=0x%8lx", hr );
560 if( !p_scanning_tuner )
562 msg_Warn( p_access, "SetCQAM: Cannot get scanning tuner" );
566 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
569 msg_Warn( p_access, "SetCQAM: "\
570 "Cannot get Tune Request: hr=0x%8lx", hr );
574 hr = l.p_tune_request->QueryInterface( IID_IDigitalCableTuneRequest,
575 reinterpret_cast<void**>( &l.p_cqam_tune_request ) );
578 msg_Warn( p_access, "SetCQAM: "\
579 "Cannot QI for IDigitalCableTuneRequest: hr=0x%8lx", hr );
583 hr = ::CoCreateInstance( CLSID_DigitalCableLocator, 0, CLSCTX_INPROC,
584 IID_IDigitalCableLocator, reinterpret_cast<void**>( &l.p_cqam_locator ) );
587 msg_Warn( p_access, "SetCQAM: "\
588 "Cannot create the CQAM locator: hr=0x%8lx", hr );
593 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
594 hr = l.p_cqam_locator->put_PhysicalChannel( l_physical_channel );
595 if( SUCCEEDED( hr ) && l_frequency > 0 )
596 hr = l.p_cqam_locator->put_CarrierFrequency( l_frequency );
597 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
598 hr = l.p_cqam_tune_request->put_MinorChannel( l_minor_channel );
601 msg_Warn( p_access, "SetCQAM: "\
602 "Cannot set tuning parameters: hr=0x%8lx", hr );
606 hr = l.p_cqam_tune_request->put_Locator( l.p_cqam_locator );
609 msg_Warn( p_access, "SetCQAM: "\
610 "Cannot put the locator: hr=0x%8lx", hr );
614 hr = p_scanning_tuner->Validate( l.p_cqam_tune_request );
617 msg_Dbg( p_access, "SetCQAM: "\
618 "Tune Request cannot be validated: hr=0x%8lx", hr );
620 /* increments ref count for scanning tuner */
621 hr = p_scanning_tuner->put_TuneRequest( l.p_cqam_tune_request );
624 msg_Warn( p_access, "SetCQAM: "\
625 "Cannot put the tune request: hr=0x%8lx", hr );
632 /*****************************************************************************
634 *****************************************************************************/
635 int BDAGraph::SetATSC(long l_frequency)
641 ITuneRequest* p_tune_request;
642 IATSCChannelTuneRequest* p_atsc_tune_request;
643 IATSCLocator* p_atsc_locator;
645 p_tune_request(NULL),
646 p_atsc_tune_request(NULL),
652 p_tune_request->Release();
653 if( p_atsc_tune_request )
654 p_atsc_tune_request->Release();
656 p_atsc_locator->Release();
659 long l_major_channel, l_minor_channel, l_physical_channel;
661 /* fixme: these parameters should have dtv prefix, not dvb */
662 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
663 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
664 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
666 /* try to set p_scanning_tuner */
667 hr = Check( CLSID_ATSCNetworkProvider );
670 msg_Warn( p_access, "SetATSC: "\
671 "Cannot create Tuning Space: hr=0x%8lx", hr );
675 if( !p_scanning_tuner )
677 msg_Warn( p_access, "SetATSC: Cannot get scanning tuner" );
681 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
684 msg_Warn( p_access, "SetATSC: "\
685 "Cannot get Tune Request: hr=0x%8lx", hr );
689 hr = l.p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
690 reinterpret_cast<void**>( &l.p_atsc_tune_request ) );
693 msg_Warn( p_access, "SetATSC: "\
694 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
698 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
699 IID_IATSCLocator, reinterpret_cast<void**>( &l.p_atsc_locator ) );
702 msg_Warn( p_access, "SetATSC: "\
703 "Cannot create the ATSC locator: hr=0x%8lx", hr );
708 if( l_frequency > 0 )
709 hr = l.p_atsc_locator->put_CarrierFrequency( l_frequency );
710 if( l_major_channel > 0 )
711 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
712 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
713 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
714 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
715 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
718 msg_Warn( p_access, "SetATSC: "\
719 "Cannot set tuning parameters: hr=0x%8lx", hr );
723 hr = l.p_atsc_tune_request->put_Locator( l.p_atsc_locator );
726 msg_Warn( p_access, "SetATSC: "\
727 "Cannot put the locator: hr=0x%8lx", hr );
731 hr = p_scanning_tuner->Validate( l.p_atsc_tune_request );
734 msg_Dbg( p_access, "SetATSC: "\
735 "Tune Request cannot be validated: hr=0x%8lx", hr );
737 /* increments ref count for scanning tuner */
738 hr = p_scanning_tuner->put_TuneRequest( l.p_atsc_tune_request );
741 msg_Warn( p_access, "SetATSC: "\
742 "Cannot put the tune request: hr=0x%8lx", hr );
749 /*****************************************************************************
752 * This provides the tune request that everything else is built upon.
754 * Stores the tune request to the scanning tuner, where it is pulled out by
755 * dvb_tune a/k/a SubmitTuneRequest.
756 ******************************************************************************/
757 int BDAGraph::SetDVBT(long l_frequency, uint32_t fec_hp, uint32_t fec_lp,
758 long l_bandwidth, int transmission, uint32_t guard, int hierarchy)
765 ITuneRequest* p_tune_request;
766 IDVBTuneRequest* p_dvb_tune_request;
767 IDVBTLocator* p_dvbt_locator;
768 IDVBTuningSpace2* p_dvb_tuning_space;
770 p_tune_request(NULL),
771 p_dvb_tune_request(NULL),
772 p_dvbt_locator(NULL),
773 p_dvb_tuning_space(NULL)
778 p_tune_request->Release();
779 if( p_dvb_tune_request )
780 p_dvb_tune_request->Release();
782 p_dvbt_locator->Release();
783 if( p_dvb_tuning_space )
784 p_dvb_tuning_space->Release();
788 /* create local dvbt-specific tune request and locator
789 * then put it to existing scanning tuner */
790 BinaryConvolutionCodeRate i_hp_fec = dvb_parse_fec(fec_hp);
791 BinaryConvolutionCodeRate i_lp_fec = dvb_parse_fec(fec_lp);
792 GuardInterval i_guard = dvb_parse_guard(guard);
793 TransmissionMode i_transmission = dvb_parse_transmission(transmission);
794 HierarchyAlpha i_hierarchy = dvb_parse_hierarchy(hierarchy);
796 /* try to set p_scanning_tuner */
797 msg_Dbg( p_access, "SetDVBT: set up scanning tuner" );
798 hr = Check( CLSID_DVBTNetworkProvider );
801 msg_Warn( p_access, "SetDVBT: "\
802 "Cannot create Tuning Space: hr=0x%8lx", hr );
806 if( !p_scanning_tuner )
808 msg_Warn( p_access, "SetDVBT: Cannot get scanning tuner" );
812 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
815 msg_Warn( p_access, "SetDVBT: "\
816 "Cannot get Tune Request: hr=0x%8lx", hr );
820 msg_Dbg( p_access, "SetDVBT: Creating DVB tune request" );
821 hr = l.p_tune_request->QueryInterface( IID_IDVBTuneRequest,
822 reinterpret_cast<void**>( &l.p_dvb_tune_request ) );
825 msg_Warn( p_access, "SetDVBT: "\
826 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
830 l.p_dvb_tune_request->put_ONID( -1 );
831 l.p_dvb_tune_request->put_SID( -1 );
832 l.p_dvb_tune_request->put_TSID( -1 );
834 msg_Dbg( p_access, "SetDVBT: get TS" );
835 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
838 msg_Dbg( p_access, "SetDVBT: "\
839 "cannot get tuning space: hr=0x%8lx", hr );
843 msg_Dbg( p_access, "SetDVBT: QI to DVBT TS" );
844 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
845 reinterpret_cast<void**>( &l.p_dvb_tuning_space ) );
848 msg_Warn( p_access, "SetDVBT: "\
849 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
853 msg_Dbg( p_access, "SetDVBT: Creating local locator" );
854 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
855 IID_IDVBTLocator, reinterpret_cast<void**>( &l.p_dvbt_locator ) );
858 msg_Warn( p_access, "SetDVBT: "\
859 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
863 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
864 if( SUCCEEDED( hr ) && l_frequency > 0 )
865 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
866 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
867 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
868 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
869 hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
870 if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
871 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
872 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
873 hr = l.p_dvbt_locator->put_Guard( i_guard );
874 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
875 hr = l.p_dvbt_locator->put_Mode( i_transmission );
876 if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
877 hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
881 msg_Warn( p_access, "SetDVBT: "\
882 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
886 msg_Dbg( p_access, "SetDVBT: putting DVBT locator into local tune request" );
888 hr = l.p_dvb_tune_request->put_Locator( l.p_dvbt_locator );
891 msg_Warn( p_access, "SetDVBT: "\
892 "Cannot put the locator: hr=0x%8lx", hr );
896 msg_Dbg( p_access, "SetDVBT: putting local Tune Request to scanning tuner" );
897 hr = p_scanning_tuner->Validate( l.p_dvb_tune_request );
900 msg_Dbg( p_access, "SetDVBT: "\
901 "Tune Request cannot be validated: hr=0x%8lx", hr );
903 /* increments ref count for scanning tuner */
904 hr = p_scanning_tuner->put_TuneRequest( l.p_dvb_tune_request );
907 msg_Warn( p_access, "SetDVBT: "\
908 "Cannot put the tune request: hr=0x%8lx", hr );
912 msg_Dbg( p_access, "SetDVBT: return success" );
916 /*****************************************************************************
919 * This provides the tune request that everything else is built upon.
921 * Stores the tune request to the scanning tuner, where it is pulled out by
922 * dvb_tune a/k/a SubmitTuneRequest.
923 ******************************************************************************/
924 int BDAGraph::SetDVBT2(long l_frequency, uint32_t fec,
925 long l_bandwidth, int transmission, uint32_t guard, int plp)
932 ITuneRequest* p_tune_request;
933 IDVBTuneRequest* p_dvb_tune_request;
934 IDVBTLocator2* p_dvbt_locator;
935 IDVBTuningSpace2* p_dvb_tuning_space;
937 p_tune_request(NULL),
938 p_dvb_tune_request(NULL),
939 p_dvbt_locator(NULL),
940 p_dvb_tuning_space(NULL)
945 p_tune_request->Release();
946 if( p_dvb_tune_request )
947 p_dvb_tune_request->Release();
949 p_dvbt_locator->Release();
950 if( p_dvb_tuning_space )
951 p_dvb_tuning_space->Release();
955 /* create local dvbt-specific tune request and locator
956 * then put it to existing scanning tuner */
957 BinaryConvolutionCodeRate i_fec = dvb_parse_fec(fec);
958 GuardInterval i_guard = dvb_parse_guard(guard);
959 TransmissionMode i_transmission = dvb_parse_transmission(transmission);
962 /* try to set p_scanning_tuner */
963 msg_Dbg( p_access, "SetDVBT: set up scanning tuner" );
964 hr = Check( CLSID_DVBTNetworkProvider );
967 msg_Warn( p_access, "SetDVBT: "\
968 "Cannot create Tuning Space: hr=0x%8lx", hr );
972 if( !p_scanning_tuner )
974 msg_Warn( p_access, "SetDVBT: Cannot get scanning tuner" );
978 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
981 msg_Warn( p_access, "SetDVBT: "\
982 "Cannot get Tune Request: hr=0x%8lx", hr );
986 msg_Dbg( p_access, "SetDVBT: Creating DVB tune request" );
987 hr = l.p_tune_request->QueryInterface( IID_IDVBTuneRequest,
988 reinterpret_cast<void**>( &l.p_dvb_tune_request ) );
991 msg_Warn( p_access, "SetDVBT: "\
992 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
996 l.p_dvb_tune_request->put_ONID( -1 );
997 l.p_dvb_tune_request->put_SID( -1 );
998 l.p_dvb_tune_request->put_TSID( -1 );
1000 msg_Dbg( p_access, "SetDVBT: get TS" );
1001 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
1004 msg_Dbg( p_access, "SetDVBT: "\
1005 "cannot get tuning space: hr=0x%8lx", hr );
1006 return VLC_EGENERIC;
1009 msg_Dbg( p_access, "SetDVBT: QI to DVBT TS" );
1010 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
1011 reinterpret_cast<void**>( &l.p_dvb_tuning_space ) );
1014 msg_Warn( p_access, "SetDVBT: "\
1015 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
1016 return VLC_EGENERIC;
1019 msg_Dbg( p_access, "SetDVBT: Creating local locator2" );
1021 hr = ::CoCreateInstance( CLSID_DVBTLocator2, 0, CLSCTX_INPROC,
1022 IID_IDVBTLocator2, reinterpret_cast<void**>( &l.p_dvbt_locator ) );
1027 msg_Warn( p_access, "SetDVBT: "\
1028 "Cannot create the DVBT Locator2: hr=0x%8lx", hr );
1029 return VLC_EGENERIC;
1032 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Terrestrial );
1033 if( SUCCEEDED( hr ) && l_frequency > 0 )
1034 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
1035 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
1036 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
1037 if( SUCCEEDED( hr ) && i_fec != BDA_BCC_RATE_NOT_SET )
1038 hr = l.p_dvbt_locator->put_InnerFECRate( i_fec );
1039 if( SUCCEEDED( hr ) && i_fec != BDA_BCC_RATE_NOT_SET )
1040 hr = l.p_dvbt_locator->put_LPInnerFECRate( i_fec );
1041 if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
1042 hr = l.p_dvbt_locator->put_Guard( i_guard );
1043 if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
1044 hr = l.p_dvbt_locator->put_Mode( i_transmission );
1045 if( SUCCEEDED( hr ) && l_plp > 0 ){
1046 hr = l.p_dvbt_locator->put_PhysicalLayerPipeId( l_plp);
1051 msg_Warn( p_access, "SetDVBT: "\
1052 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
1053 return VLC_EGENERIC;
1056 msg_Dbg( p_access, "SetDVBT: putting DVBT locator into local tune request" );
1058 hr = l.p_dvb_tune_request->put_Locator( l.p_dvbt_locator );
1061 msg_Warn( p_access, "SetDVBT: "\
1062 "Cannot put the locator: hr=0x%8lx", hr );
1063 return VLC_EGENERIC;
1066 msg_Dbg( p_access, "SetDVBT: putting local Tune Request to scanning tuner" );
1067 hr = p_scanning_tuner->Validate( l.p_dvb_tune_request );
1070 msg_Dbg( p_access, "SetDVBT: "\
1071 "Tune Request cannot be validated: hr=0x%8lx", hr );
1073 /* increments ref count for scanning tuner */
1074 hr = p_scanning_tuner->put_TuneRequest( l.p_dvb_tune_request );
1077 msg_Warn( p_access, "SetDVBT: "\
1078 "Cannot put the tune request: hr=0x%8lx", hr );
1079 return VLC_EGENERIC;
1082 /* TBS tuner PLP set workaround */
1083 /* TODO: Check TBS tuner is present */
1084 IPin* pinInput0 = FindPinOnFilter( p_tuner_device, "Input0");
1087 msg_Dbg( p_access, "SetDVBT: pin Input0 found on tuner filter, trying to get IKsPropertySet interface for TBS tuner..." );
1088 IKsPropertySet* p_ksPropertySet;
1089 hr = pinInput0->QueryInterface(IID_IKsPropertySet, reinterpret_cast<void**>(&p_ksPropertySet));
1092 msg_Dbg( p_access, "SetDVBT: Cannot query for IKsPropertySet (this can be normal if not TBS tuner) : hr=0x%8lx", hr );
1096 msg_Dbg( p_access, "SetDVBT: found IKsPropertySet interface (using TBS tuner PLP-set workaround)");
1097 TBS_PLP_INFO plp_info;
1098 ZeroMemory( &plp_info, sizeof( TBS_PLP_INFO));
1099 plp_info.plpId = plp;
1100 p_ksPropertySet->Set( KSPROPSETID_BdaTunerExtensionProperties,
1101 KSPROPERTY_BDA_PLPINFO,
1105 sizeof( TBS_PLP_INFO ));
1106 msg_Dbg( p_access, "SetDVBT: TBS tuner set PLP: %d", plp);
1107 p_ksPropertySet->Release();
1109 pinInput0->Release();
1113 msg_Dbg( p_access, "SetDVBT: no pin Input0 found on tuner filter (this can be normal if not TBS tuner)" );
1116 msg_Dbg( p_access, "SetDVBT: return success" );
1121 /*****************************************************************************
1123 ******************************************************************************/
1124 int BDAGraph::SetDVBC(long l_frequency, const char *mod, long l_symbolrate)
1131 ITuneRequest* p_tune_request;
1132 IDVBTuneRequest* p_dvb_tune_request;
1133 IDVBCLocator* p_dvbc_locator;
1134 IDVBTuningSpace2* p_dvb_tuning_space;
1137 p_tune_request(NULL),
1138 p_dvb_tune_request(NULL),
1139 p_dvbc_locator(NULL),
1140 p_dvb_tuning_space(NULL)
1144 if( p_tune_request )
1145 p_tune_request->Release();
1146 if( p_dvb_tune_request )
1147 p_dvb_tune_request->Release();
1148 if( p_dvbc_locator )
1149 p_dvbc_locator->Release();
1150 if( p_dvb_tuning_space )
1151 p_dvb_tuning_space->Release();
1155 ModulationType i_qam_mod = dvb_parse_modulation(mod);
1157 /* try to set p_scanning_tuner */
1158 hr = Check( CLSID_DVBCNetworkProvider );
1159 msg_Dbg( p_access, "SetDVBC: returned from Check" );
1163 msg_Warn( p_access, "SetDVBC: "\
1164 "Cannot create Tuning Space: hr=0x%8lx", hr );
1165 return VLC_EGENERIC;
1168 msg_Dbg( p_access, "SetDVBC: check on scanning tuner" );
1169 if( !p_scanning_tuner )
1171 msg_Warn( p_access, "SetDVBC: Cannot get scanning tuner" );
1172 return VLC_EGENERIC;
1175 msg_Dbg( p_access, "SetDVBC: get tune request" );
1176 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
1179 msg_Warn( p_access, "SetDVBC: "\
1180 "Cannot get Tune Request: hr=0x%8lx", hr );
1181 return VLC_EGENERIC;
1184 msg_Dbg( p_access, "SetDVBC: QI for dvb tune request" );
1185 hr = l.p_tune_request->QueryInterface( IID_IDVBTuneRequest,
1186 reinterpret_cast<void**>( &l.p_dvb_tune_request ) );
1189 msg_Warn( p_access, "SetDVBC: "\
1190 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
1191 return VLC_EGENERIC;
1194 l.p_dvb_tune_request->put_ONID( -1 );
1195 l.p_dvb_tune_request->put_SID( -1 );
1196 l.p_dvb_tune_request->put_TSID( -1 );
1198 msg_Dbg( p_access, "SetDVBC: create dvbc locator" );
1199 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
1200 IID_IDVBCLocator, reinterpret_cast<void**>( &l.p_dvbc_locator ) );
1203 msg_Warn( p_access, "SetDVBC: "\
1204 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
1205 return VLC_EGENERIC;
1209 msg_Dbg( p_access, "SetDVBC: get TS" );
1210 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
1213 msg_Dbg( p_access, "SetDVBC: "\
1214 "cannot get tuning space: hr=0x%8lx", hr );
1215 return VLC_EGENERIC;
1218 msg_Dbg( p_access, "SetDVBC: QI for dvb tuning space" );
1219 hr = p_tuning_space->QueryInterface( IID_IDVBTuningSpace2,
1220 reinterpret_cast<void**>( &l.p_dvb_tuning_space ) );
1223 msg_Warn( p_access, "SetDVBC: "\
1224 "Cannot QI for IDVBTuningSpace2: hr=0x%8lx", hr );
1225 return VLC_EGENERIC;
1228 msg_Dbg( p_access, "SetDVBC: set up locator" );
1230 hr = l.p_dvb_tuning_space->put_SystemType( DVB_Cable );
1232 if( SUCCEEDED( hr ) && l_frequency > 0 )
1233 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
1234 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
1235 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
1236 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
1237 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
1241 msg_Warn( p_access, "SetDVBC: "\
1242 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
1243 return VLC_EGENERIC;
1246 msg_Dbg( p_access, "SetDVBC: put locator to dvb tune request" );
1247 hr = l.p_dvb_tune_request->put_Locator( l.p_dvbc_locator );
1250 msg_Warn( p_access, "SetDVBC: "\
1251 "Cannot put the locator: hr=0x%8lx", hr );
1252 return VLC_EGENERIC;
1255 msg_Dbg( p_access, "SetDVBC: validate dvb tune request" );
1256 hr = p_scanning_tuner->Validate( l.p_dvb_tune_request );
1259 msg_Dbg( p_access, "SetDVBC: "\
1260 "Tune Request cannot be validated: hr=0x%8lx", hr );
1263 /* increments ref count for scanning tuner */
1264 msg_Dbg( p_access, "SetDVBC: put dvb tune request to tuner" );
1265 hr = p_scanning_tuner->put_TuneRequest( l.p_dvb_tune_request );
1268 msg_Warn( p_access, "SetDVBC: "\
1269 "Cannot put the tune request: hr=0x%8lx", hr );
1270 return VLC_EGENERIC;
1272 msg_Dbg( p_access, "SetDVBC: return success" );
1277 /*****************************************************************************
1279 ******************************************************************************/
1280 int BDAGraph::SetInversion(int inversion)
1286 IDVBSTuningSpace* p_dvbs_tuning_space;
1288 p_dvbs_tuning_space(NULL)
1292 if( p_dvbs_tuning_space )
1293 p_dvbs_tuning_space->Release();
1297 SpectralInversion i_inversion = dvb_parse_inversion( inversion );
1299 if( !p_scanning_tuner )
1301 msg_Warn( p_access, "SetInversion: "\
1302 "No scanning tuner" );
1303 return VLC_EGENERIC;
1306 /* SetInversion is called for all DVB tuners, before the dvb_tune(),
1307 * in access.c. Since DVBT and DVBC don't support spectral
1308 * inversion, we need to return VLC_SUCCESS in those cases
1309 * so that dvb_tune() will be called */
1310 if( ( GetSystem( guid_network_type ) & ( DVB_S | DVB_S2 | ISDB_S ) ) == 0 )
1312 msg_Dbg( p_access, "SetInversion: Not Satellite type" );
1316 msg_Dbg( p_access, "SetInversion: get TS" );
1317 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
1320 msg_Warn( p_access, "SetInversion: "\
1321 "cannot get tuning space: hr=0x%8lx", hr );
1322 return VLC_EGENERIC;
1325 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
1326 reinterpret_cast<void**>( &l.p_dvbs_tuning_space ) );
1329 msg_Warn( p_access, "SetInversion: "\
1330 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
1331 return VLC_EGENERIC;
1334 if( i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
1335 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
1338 msg_Warn( p_access, "SetInversion: "\
1339 "Cannot put inversion: hr=0x%8lx", hr );
1340 return VLC_EGENERIC;
1346 /*****************************************************************************
1348 ******************************************************************************/
1349 int BDAGraph::SetDVBS(long l_frequency, long l_symbolrate, uint32_t fec,
1350 int inversion, char pol,
1351 long l_lnb_lof1, long l_lnb_lof2, long l_lnb_slof)
1358 ITuneRequest* p_tune_request;
1359 IDVBTuneRequest* p_dvb_tune_request;
1360 IDVBSLocator* p_dvbs_locator;
1361 IDVBSTuningSpace* p_dvbs_tuning_space;
1362 char* psz_polarisation;
1363 char* psz_input_range;
1364 BSTR bstr_input_range;
1365 WCHAR* pwsz_input_range;
1368 p_tune_request(NULL),
1369 p_dvb_tune_request(NULL),
1370 p_dvbs_locator(NULL),
1371 p_dvbs_tuning_space(NULL),
1372 psz_polarisation(NULL),
1373 psz_input_range(NULL),
1374 bstr_input_range(NULL),
1375 pwsz_input_range(NULL),
1380 if( p_tune_request )
1381 p_tune_request->Release();
1382 if( p_dvb_tune_request )
1383 p_dvb_tune_request->Release();
1384 if( p_dvbs_locator )
1385 p_dvbs_locator->Release();
1386 if( p_dvbs_tuning_space )
1387 p_dvbs_tuning_space->Release();
1388 SysFreeString( bstr_input_range );
1389 if( pwsz_input_range )
1390 delete[] pwsz_input_range;
1391 free( psz_input_range );
1392 free( psz_polarisation );
1395 long l_azimuth, l_elevation, l_longitude;
1397 VARIANT_BOOL b_west;
1399 BinaryConvolutionCodeRate i_hp_fec = dvb_parse_fec( fec );
1400 Polarisation i_polar = dvb_parse_polarization( pol );
1401 SpectralInversion i_inversion = dvb_parse_inversion( inversion );
1403 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
1404 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
1405 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
1406 l_network_id = var_GetInteger( p_access, "dvb-network-id" );
1408 if( asprintf( &l.psz_polarisation, "%c", pol ) == -1 )
1411 b_west = ( l_longitude < 0 );
1413 l.psz_input_range = var_GetNonEmptyString( p_access, "dvb-range" );
1414 l.i_range_len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
1415 l.psz_input_range, -1, l.pwsz_input_range, 0 );
1416 if( l.i_range_len > 0 )
1418 l.pwsz_input_range = new WCHAR[l.i_range_len];
1419 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
1420 l.psz_input_range, -1, l.pwsz_input_range, l.i_range_len );
1421 l.bstr_input_range = SysAllocString( l.pwsz_input_range );
1424 /* try to set p_scanning_tuner */
1425 hr = Check( CLSID_DVBSNetworkProvider );
1428 msg_Warn( p_access, "SetDVBS: "\
1429 "Cannot create Tuning Space: hr=0x%8lx", hr );
1430 return VLC_EGENERIC;
1433 if( !p_scanning_tuner )
1435 msg_Warn( p_access, "SetDVBS: Cannot get scanning tuner" );
1436 return VLC_EGENERIC;
1439 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
1442 msg_Warn( p_access, "SetDVBS: "\
1443 "Cannot get Tune Request: hr=0x%8lx", hr );
1444 return VLC_EGENERIC;
1447 hr = l.p_tune_request->QueryInterface( IID_IDVBTuneRequest,
1448 reinterpret_cast<void**>( &l.p_dvb_tune_request ) );
1451 msg_Warn( p_access, "SetDVBS: "\
1452 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
1453 return VLC_EGENERIC;
1456 l.p_dvb_tune_request->put_ONID( -1 );
1457 l.p_dvb_tune_request->put_SID( -1 );
1458 l.p_dvb_tune_request->put_TSID( -1 );
1460 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
1461 IID_IDVBSLocator, reinterpret_cast<void**>( &l.p_dvbs_locator ) );
1464 msg_Warn( p_access, "SetDVBS: "\
1465 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
1466 return VLC_EGENERIC;
1469 msg_Dbg( p_access, "SetDVBS: get TS" );
1470 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
1473 msg_Dbg( p_access, "SetDVBS: "\
1474 "cannot get tuning space: hr=0x%8lx", hr );
1475 return VLC_EGENERIC;
1478 hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
1479 reinterpret_cast<void**>( &l.p_dvbs_tuning_space ) );
1482 msg_Warn( p_access, "SetDVBS: "\
1483 "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
1484 return VLC_EGENERIC;
1487 hr = l.p_dvbs_tuning_space->put_SystemType( DVB_Satellite );
1488 if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
1489 hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
1490 if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
1491 hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
1492 if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
1493 hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
1494 if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
1495 hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
1496 if( SUCCEEDED( hr ) && l_network_id > 0 )
1497 hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
1498 if( SUCCEEDED( hr ) && l.i_range_len > 0 )
1499 hr = l.p_dvbs_tuning_space->put_InputRange( l.bstr_input_range );
1501 if( SUCCEEDED( hr ) && l_frequency > 0 )
1502 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
1503 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
1504 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
1505 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
1506 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
1507 if( SUCCEEDED( hr ) )
1508 hr = l.p_dvbs_locator->put_Modulation( BDA_MOD_QPSK );
1509 if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
1510 hr = l.p_dvbs_locator->put_InnerFECRate( i_hp_fec );
1512 if( SUCCEEDED( hr ) && l_azimuth > 0 )
1513 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
1514 if( SUCCEEDED( hr ) && l_elevation > 0 )
1515 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
1516 if( SUCCEEDED( hr ) )
1517 hr = l.p_dvbs_locator->put_WestPosition( b_west );
1518 if( SUCCEEDED( hr ) )
1519 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
1523 msg_Warn( p_access, "SetDVBS: "\
1524 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
1525 return VLC_EGENERIC;
1528 hr = l.p_dvb_tune_request->put_Locator( l.p_dvbs_locator );
1531 msg_Warn( p_access, "SetDVBS: "\
1532 "Cannot put the locator: hr=0x%8lx", hr );
1533 return VLC_EGENERIC;
1536 hr = p_scanning_tuner->Validate( l.p_dvb_tune_request );
1539 msg_Dbg( p_access, "SetDVBS: "\
1540 "Tune Request cannot be validated: hr=0x%8lx", hr );
1543 /* increments ref count for scanning tuner */
1544 hr = p_scanning_tuner->put_TuneRequest( l.p_dvb_tune_request );
1547 msg_Warn( p_access, "SetDVBS: "\
1548 "Cannot put the tune request: hr=0x%8lx", hr );
1549 return VLC_EGENERIC;
1555 /*****************************************************************************
1557 ******************************************************************************
1558 * Sets up global p_scanning_tuner and sets guid_network_type according
1559 * to the Network Type requested.
1561 * Logic: if tuner is set up and is the right network type, use it.
1562 * Otherwise, poll the tuner for the right tuning space.
1564 * Then set up a tune request and try to validate it. Finally, put
1565 * tune request and tuning space to tuner
1567 * on success, sets globals: p_scanning_tuner and guid_network_type
1569 ******************************************************************************/
1570 HRESULT BDAGraph::SetUpTuner( REFCLSID guid_this_network_type )
1576 ITuningSpaceContainer* p_tuning_space_container;
1577 IEnumTuningSpaces* p_tuning_space_enum;
1578 ITuningSpace* p_test_tuning_space;
1579 ITuneRequest* p_tune_request;
1580 IDVBTuneRequest* p_dvb_tune_request;
1582 IDigitalCableTuneRequest* p_cqam_tune_request;
1583 IATSCChannelTuneRequest* p_atsc_tune_request;
1584 ILocator* p_locator;
1585 IDVBTLocator* p_dvbt_locator;
1586 IDVBCLocator* p_dvbc_locator;
1587 IDVBSLocator* p_dvbs_locator;
1591 CLSID guid_test_network_type;
1592 char* psz_network_name;
1593 char* psz_bstr_name;
1597 p_tuning_space_container(NULL),
1598 p_tuning_space_enum(NULL),
1599 p_test_tuning_space(NULL),
1600 p_tune_request(NULL),
1601 p_dvb_tune_request(NULL),
1602 p_cqam_tune_request(NULL),
1603 p_atsc_tune_request(NULL),
1605 p_dvbt_locator(NULL),
1606 p_dvbc_locator(NULL),
1607 p_dvbs_locator(NULL),
1609 guid_test_network_type(GUID_NULL),
1610 psz_network_name(NULL),
1611 psz_bstr_name(NULL),
1616 if( p_tuning_space_enum )
1617 p_tuning_space_enum->Release();
1618 if( p_tuning_space_container )
1619 p_tuning_space_container->Release();
1620 if( p_test_tuning_space )
1621 p_test_tuning_space->Release();
1622 if( p_tune_request )
1623 p_tune_request->Release();
1624 if( p_dvb_tune_request )
1625 p_dvb_tune_request->Release();
1626 if( p_cqam_tune_request )
1627 p_cqam_tune_request->Release();
1628 if( p_atsc_tune_request )
1629 p_atsc_tune_request->Release();
1631 p_locator->Release();
1632 if( p_dvbt_locator )
1633 p_dvbt_locator->Release();
1634 if( p_dvbc_locator )
1635 p_dvbc_locator->Release();
1636 if( p_dvbs_locator )
1637 p_dvbs_locator->Release();
1638 SysFreeString( bstr_name );
1639 delete[] psz_bstr_name;
1640 free( psz_network_name );
1644 msg_Dbg( p_access, "SetUpTuner: entering" );
1647 /* We shall test for a specific Tuning space name supplied on the command
1648 * line as dvb-network-name=xxx.
1649 * For some users with multiple cards and/or multiple networks this could
1650 * be useful. This allows us to reasonably safely apply updates to the
1651 * System Tuning Space in the registry without disrupting other streams. */
1653 l.psz_network_name = var_GetNonEmptyString( p_access, "dvb-network-name" );
1655 if( l.psz_network_name )
1657 msg_Dbg( p_access, "SetUpTuner: Find Tuning Space: %s",
1658 l.psz_network_name );
1662 l.psz_network_name = new char[1];
1663 *l.psz_network_name = '\0';
1666 /* Tuner may already have been set up. If it is for the same
1667 * network type then all is well. Otherwise, reset the Tuning Space and get
1669 msg_Dbg( p_access, "SetUpTuner: Checking for tuning space" );
1670 if( !p_scanning_tuner )
1672 msg_Warn( p_access, "SetUpTuner: "\
1673 "Cannot find scanning tuner" );
1677 if( p_tuning_space )
1679 msg_Dbg( p_access, "SetUpTuner: get network type" );
1680 hr = p_tuning_space->get__NetworkType( &l.guid_test_network_type );
1683 msg_Warn( p_access, "Check: "\
1684 "Cannot get network type: hr=0x%8lx", hr );
1685 l.guid_test_network_type = GUID_NULL;
1688 msg_Dbg( p_access, "SetUpTuner: see if it's the right one" );
1689 if( l.guid_test_network_type == guid_this_network_type )
1691 msg_Dbg( p_access, "SetUpTuner: it's the right one" );
1692 SysFreeString( l.bstr_name );
1694 hr = p_tuning_space->get_UniqueName( &l.bstr_name );
1697 /* should never fail on a good tuning space */
1698 msg_Dbg( p_access, "SetUpTuner: "\
1699 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
1703 /* Test for a specific Tuning space name supplied on the command
1704 * line as dvb-network-name=xxx */
1705 if( l.psz_bstr_name )
1706 delete[] l.psz_bstr_name;
1707 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1708 l.psz_bstr_name, 0, NULL, NULL );
1709 l.psz_bstr_name = new char[ l.i_name_len ];
1710 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1711 l.psz_bstr_name, l.i_name_len, NULL, NULL );
1713 /* if no name was requested on command line, or if the name
1714 * requested equals the name of this space, we are OK */
1715 if( *l.psz_network_name == '\0' ||
1716 strcmp( l.psz_network_name, l.psz_bstr_name ) == 0 )
1718 msg_Dbg( p_access, "SetUpTuner: Using Tuning Space: %s",
1720 /* p_tuning_space and guid_network_type are already set */
1721 /* you probably already have a tune request, also */
1722 hr = p_scanning_tuner->get_TuneRequest( &l.p_tune_request );
1723 if( SUCCEEDED( hr ) )
1727 /* CreateTuneRequest adds l.p_tune_request to p_tuning_space
1728 * l.p_tune_request->RefCount = 1 */
1729 hr = p_tuning_space->CreateTuneRequest( &l.p_tune_request );
1730 if( SUCCEEDED( hr ) )
1734 msg_Warn( p_access, "SetUpTuner: "\
1735 "Cannot Create Tune Request: hr=0x%8lx", hr );
1736 /* fall through to NoTuningSpace */
1740 /* else different guid_network_type */
1742 if( p_tuning_space )
1743 p_tuning_space->Release();
1744 p_tuning_space = NULL;
1745 /* pro forma; should have returned S_OK if we created this */
1746 if( l.p_tune_request )
1747 l.p_tune_request->Release();
1748 l.p_tune_request = NULL;
1752 /* p_tuning_space is null at this point; we have already
1753 returned S_OK if it was good. So find a tuning
1754 space on the scanning tuner. */
1756 msg_Dbg( p_access, "SetUpTuner: release TuningSpaces Enumerator" );
1757 if( l.p_tuning_space_enum )
1758 l.p_tuning_space_enum->Release();
1759 msg_Dbg( p_access, "SetUpTuner: nullify TuningSpaces Enumerator" );
1760 l.p_tuning_space_enum = NULL;
1761 msg_Dbg( p_access, "SetUpTuner: create TuningSpaces Enumerator" );
1763 hr = p_scanning_tuner->EnumTuningSpaces( &l.p_tuning_space_enum );
1766 msg_Warn( p_access, "SetUpTuner: "\
1767 "Cannot create TuningSpaces Enumerator: hr=0x%8lx", hr );
1773 msg_Dbg( p_access, "SetUpTuner: top of loop" );
1774 l.guid_test_network_type = GUID_NULL;
1775 if( l.p_test_tuning_space )
1776 l.p_test_tuning_space->Release();
1777 l.p_test_tuning_space = NULL;
1778 if( p_tuning_space )
1779 p_tuning_space->Release();
1780 p_tuning_space = NULL;
1781 SysFreeString( l.bstr_name );
1782 msg_Dbg( p_access, "SetUpTuner: need good TS enum" );
1783 if( !l.p_tuning_space_enum ) break;
1784 msg_Dbg( p_access, "SetUpTuner: next tuning space" );
1785 hr = l.p_tuning_space_enum->Next( 1, &l.p_test_tuning_space, NULL );
1786 if( hr != S_OK ) break;
1787 msg_Dbg( p_access, "SetUpTuner: get network type" );
1788 hr = l.p_test_tuning_space->get__NetworkType( &l.guid_test_network_type );
1791 msg_Warn( p_access, "Check: "\
1792 "Cannot get network type: hr=0x%8lx", hr );
1793 l.guid_test_network_type = GUID_NULL;
1795 if( l.guid_test_network_type == guid_this_network_type )
1797 msg_Dbg( p_access, "SetUpTuner: Found matching space on tuner" );
1799 SysFreeString( l.bstr_name );
1800 msg_Dbg( p_access, "SetUpTuner: get unique name" );
1802 hr = l.p_test_tuning_space->get_UniqueName( &l.bstr_name );
1805 /* should never fail on a good tuning space */
1806 msg_Dbg( p_access, "SetUpTuner: "\
1807 "Cannot get UniqueName for Tuning Space: hr=0x%8lx", hr );
1810 msg_Dbg( p_access, "SetUpTuner: convert w to multi" );
1811 if ( l.psz_bstr_name )
1812 delete[] l.psz_bstr_name;
1813 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1814 l.psz_bstr_name, 0, NULL, NULL );
1815 l.psz_bstr_name = new char[ l.i_name_len ];
1816 l.i_name_len = WideCharToMultiByte( CP_ACP, 0, l.bstr_name, -1,
1817 l.psz_bstr_name, l.i_name_len, NULL, NULL );
1818 msg_Dbg( p_access, "SetUpTuner: Using Tuning Space: %s",
1825 msg_Dbg( p_access, "SetUpTuner: checking what we got" );
1827 if( l.guid_test_network_type == GUID_NULL)
1829 msg_Dbg( p_access, "SetUpTuner: got null, try to clone" );
1833 msg_Dbg( p_access, "SetUpTuner: put TS" );
1834 hr = p_scanning_tuner->put_TuningSpace( l.p_test_tuning_space );
1837 msg_Dbg( p_access, "SetUpTuner: "\
1838 "cannot put tuning space: hr=0x%8lx", hr );
1842 msg_Dbg( p_access, "SetUpTuner: get default locator" );
1843 hr = l.p_test_tuning_space->get_DefaultLocator( &l.p_locator );
1846 msg_Dbg( p_access, "SetUpTuner: "\
1847 "cannot get default locator: hr=0x%8lx", hr );
1851 msg_Dbg( p_access, "SetUpTuner: create tune request" );
1852 hr = l.p_test_tuning_space->CreateTuneRequest( &l.p_tune_request );
1855 msg_Dbg( p_access, "SetUpTuner: "\
1856 "cannot create tune request: hr=0x%8lx", hr );
1860 msg_Dbg( p_access, "SetUpTuner: put locator" );
1861 hr = l.p_tune_request->put_Locator( l.p_locator );
1864 msg_Dbg( p_access, "SetUpTuner: "\
1865 "cannot put locator: hr=0x%8lx", hr );
1869 msg_Dbg( p_access, "SetUpTuner: try to validate tune request" );
1870 hr = p_scanning_tuner->Validate( l.p_tune_request );
1873 msg_Dbg( p_access, "SetUpTuner: "\
1874 "Tune Request cannot be validated: hr=0x%8lx", hr );
1877 msg_Dbg( p_access, "SetUpTuner: Attach tune request to Scanning Tuner");
1878 /* increments ref count for scanning tuner */
1879 hr = p_scanning_tuner->put_TuneRequest( l.p_tune_request );
1882 msg_Warn( p_access, "SetUpTuner: "\
1883 "Cannot submit the tune request: hr=0x%8lx", hr );
1887 msg_Dbg( p_access, "SetUpTuner: Tuning Space and Tune Request created" );
1890 /* Get the SystemTuningSpaces container
1891 * p_tuning_space_container->Refcount = 1 */
1893 msg_Warn( p_access, "SetUpTuner: won't try to clone " );
1897 /*****************************************************************************
1898 * GetNextNetworkType
1899 * helper function; this is probably best done as an Enumeration of
1901 *****************************************************************************/
1902 HRESULT BDAGraph::GetNextNetworkType( CLSID* guid_this_network_type )
1905 if( *guid_this_network_type == GUID_NULL )
1907 msg_Dbg( p_access, "GetNextNetworkType: DVB-C" );
1908 *guid_this_network_type = CLSID_DVBCNetworkProvider;
1911 if( *guid_this_network_type == CLSID_DVBCNetworkProvider )
1913 msg_Dbg( p_access, "GetNextNetworkType: DVB-T" );
1914 *guid_this_network_type = CLSID_DVBTNetworkProvider;
1917 if( *guid_this_network_type == CLSID_DVBTNetworkProvider )
1919 msg_Dbg( p_access, "GetNextNetworkType: DVB-S" );
1920 *guid_this_network_type = CLSID_DVBSNetworkProvider;
1923 if( *guid_this_network_type == CLSID_DVBSNetworkProvider )
1925 msg_Dbg( p_access, "GetNextNetworkType: ATSC" );
1926 *guid_this_network_type = CLSID_ATSCNetworkProvider;
1929 msg_Dbg( p_access, "GetNextNetworkType: failed" );
1930 *guid_this_network_type = GUID_NULL;
1936 /******************************************************************************
1938 *******************************************************************************
1939 * Check if tuner supports this network type
1941 * on success, sets globals:
1942 * systems, l_tuner_used, p_network_provider, p_scanning_tuner, p_tuner_device,
1943 * p_tuning_space, p_filter_graph
1944 ******************************************************************************/
1945 HRESULT BDAGraph::Check( REFCLSID guid_this_network_type )
1952 ITuningSpaceContainer* p_tuning_space_container;
1955 p_tuning_space_container(NULL)
1959 if( p_tuning_space_container )
1960 p_tuning_space_container->Release();
1964 msg_Dbg( p_access, "Check: entering ");
1966 /* Note that the systems global is persistent across Destroy().
1967 * So we need to see if a tuner has been physically removed from
1968 * the system since the last Check. Before we do anything,
1969 * assume that this Check will fail and remove this network type
1970 * from systems. It will be restored if the Check passes.
1973 systems &= ~( GetSystem( guid_this_network_type ) );
1976 /* If we have already have a filter graph, rebuild it*/
1977 msg_Dbg( p_access, "Check: Destroying filter graph" );
1978 if( p_filter_graph )
1980 p_filter_graph = NULL;
1981 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1982 IID_IGraphBuilder, reinterpret_cast<void**>( &p_filter_graph ) );
1985 msg_Warn( p_access, "Check: "\
1986 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
1990 /* First filter in the graph is the Network Provider and
1991 * its Scanning Tuner which takes the Tune Request */
1992 if( p_network_provider )
1993 p_network_provider->Release();
1994 p_network_provider = NULL;
1995 hr = ::CoCreateInstance( guid_this_network_type, NULL, CLSCTX_INPROC_SERVER,
1996 IID_IBaseFilter, reinterpret_cast<void**>( &p_network_provider ) );
1999 msg_Warn( p_access, "Check: "\
2000 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
2004 msg_Dbg( p_access, "Check: adding Network Provider to graph");
2005 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
2008 msg_Warn( p_access, "Check: "\
2009 "Cannot load network provider: hr=0x%8lx", hr );
2013 /* Add the Network Tuner to the Network Provider. On subsequent calls,
2014 * l_tuner_used will cause a different tuner to be selected.
2016 * To select a specific device first get the parameter that nominates the
2017 * device (dvb-adapter) and use the value to initialise l_tuner_used.
2018 * Note that dvb-adapter is 1-based, while l_tuner_used is 0-based.
2019 * When FindFilter returns, check the contents of l_tuner_used.
2020 * If it is not what was selected, then the requested device was not
2021 * available, so return with an error. */
2023 long l_adapter = -1;
2024 l_adapter = var_GetInteger( p_access, "dvb-adapter" );
2025 if( l_tuner_used < 0 && l_adapter >= 0 )
2026 l_tuner_used = l_adapter - 1;
2028 /* If tuner is in cold state, we have to do a successful put_TuneRequest
2029 * before it will Connect. */
2030 msg_Dbg( p_access, "Check: Creating Scanning Tuner");
2031 if( p_scanning_tuner )
2032 p_scanning_tuner->Release();
2033 p_scanning_tuner = NULL;
2034 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
2035 reinterpret_cast<void**>( &p_scanning_tuner ) );
2038 msg_Warn( p_access, "Check: "\
2039 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
2043 /* try to set up p_scanning_tuner */
2044 msg_Dbg( p_access, "Check: Calling SetUpTuner" );
2045 hr = SetUpTuner( guid_this_network_type );
2048 msg_Dbg( p_access, "Check: "\
2049 "Cannot set up scanner in Check mode: hr=0x%8lx", hr );
2053 msg_Dbg( p_access, "Check: "\
2054 "Calling FindFilter for KSCATEGORY_BDA_NETWORK_TUNER with "\
2055 "p_network_provider; l_tuner_used=%ld", l_tuner_used );
2056 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
2057 p_network_provider, &p_tuner_device );
2060 msg_Warn( p_access, "Check: "\
2061 "Cannot load tuner device and connect network provider: "\
2066 if( l_adapter > 0 && l_tuner_used != l_adapter )
2068 msg_Warn( p_access, "Check: "\
2069 "Tuner device %ld is not available", l_adapter );
2073 msg_Dbg( p_access, "Check: Using adapter %ld", l_tuner_used );
2075 * already set l_tuner_used,
2078 msg_Dbg( p_access, "Check: check succeeded: hr=0x%8lx", hr );
2079 systems |= GetSystem( guid_this_network_type );
2080 msg_Dbg( p_access, "Check: returning from Check mode" );
2085 /******************************************************************************
2087 *******************************************************************************
2088 * Build the Filter Graph
2090 * connects filters and
2091 * creates the media control and registers the graph
2092 * on success, sets globals:
2093 * d_graph_register, p_media_control, p_grabber, p_sample_grabber,
2094 * p_mpeg_demux, p_transport_info
2095 ******************************************************************************/
2096 HRESULT BDAGraph::Build()
2099 long l_capture_used;
2101 AM_MEDIA_TYPE grabber_media_type;
2106 ITuningSpaceContainer* p_tuning_space_container;
2108 p_tuning_space_container(NULL)
2112 if( p_tuning_space_container )
2113 p_tuning_space_container->Release();
2117 msg_Dbg( p_access, "Build: entering");
2119 /* at this point, you've connected to a scanning tuner of the right
2122 if( !p_scanning_tuner || !p_tuner_device )
2124 msg_Warn( p_access, "Build: "\
2125 "Scanning Tuner does not exist" );
2129 hr = p_scanning_tuner->get_TuneRequest( &p_tune_request );
2132 msg_Warn( p_access, "Build: no tune request" );
2135 hr = p_scanning_tuner->get_TuningSpace( &p_tuning_space );
2138 msg_Warn( p_access, "Build: no tuning space" );
2141 hr = p_tuning_space->get__NetworkType( &guid_network_type );
2144 /* Always look for all capture devices to match the Network Tuner */
2145 l_capture_used = -1;
2146 msg_Dbg( p_access, "Build: "\
2147 "Calling FindFilter for KSCATEGORY_BDA_RECEIVER_COMPONENT with "\
2148 "p_tuner_device; l_capture_used=%ld", l_capture_used );
2149 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
2150 p_tuner_device, &p_capture_device );
2153 /* Some BDA drivers do not provide a Capture Device Filter so force
2154 * the Sample Grabber to connect directly to the Tuner Device */
2155 msg_Dbg( p_access, "Build: "\
2156 "Cannot find Capture device. Connect to tuner "\
2157 "and AddRef() : hr=0x%8lx", hr );
2158 p_capture_device = p_tuner_device;
2159 p_capture_device->AddRef();
2162 if( p_sample_grabber )
2163 p_sample_grabber->Release();
2164 p_sample_grabber = NULL;
2165 /* Insert the Sample Grabber to tap into the Transport Stream. */
2166 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
2167 IID_IBaseFilter, reinterpret_cast<void**>( &p_sample_grabber ) );
2170 msg_Warn( p_access, "Build: "\
2171 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
2175 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
2178 msg_Warn( p_access, "Build: "\
2179 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
2183 /* create the sample grabber */
2185 p_grabber->Release();
2187 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
2188 reinterpret_cast<void**>( &p_grabber ) );
2191 msg_Warn( p_access, "Build: "\
2192 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
2196 /* Try the possible stream type */
2198 for( int i = 0; i < 2; i++ )
2200 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
2201 grabber_media_type.majortype = MEDIATYPE_Stream;
2202 grabber_media_type.subtype = i == 0 ? MEDIASUBTYPE_MPEG2_TRANSPORT : KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT;
2203 msg_Dbg( p_access, "Build: "
2204 "Trying connecting with subtype %s",
2205 i == 0 ? "MEDIASUBTYPE_MPEG2_TRANSPORT" : "KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT" );
2206 hr = p_grabber->SetMediaType( &grabber_media_type );
2207 if( SUCCEEDED( hr ) )
2209 hr = Connect( p_capture_device, p_sample_grabber );
2210 if( SUCCEEDED( hr ) )
2212 msg_Dbg( p_access, "Build: "\
2213 "Connected capture device to sample grabber" );
2216 msg_Warn( p_access, "Build: "\
2217 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx (try %d/2)", hr, 1+i );
2221 msg_Warn( p_access, "Build: "\
2222 "Cannot set media type on grabber filter: hr=0x%8lx (try %d/2", hr, 1+i );
2225 msg_Dbg( p_access, "Build: This is where it used to return upon success" );
2228 msg_Warn( p_access, "Build: "\
2229 "Cannot use capture device: hr=0x%8lx", hr );
2233 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
2234 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
2235 * the Network Provider filter to set up the stream */
2236 //msg_Dbg( p_access, "Build: using MPEG2 demux" );
2238 p_mpeg_demux->Release();
2239 p_mpeg_demux = NULL;
2240 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
2241 CLSCTX_INPROC_SERVER, IID_IBaseFilter,
2242 reinterpret_cast<void**>( &p_mpeg_demux ) );
2245 msg_Warn( p_access, "Build: "\
2246 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
2250 //msg_Dbg( p_access, "Build: adding demux" );
2251 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
2254 msg_Warn( p_access, "Build: "\
2255 "Cannot add demux filter to graph: hr=0x%8lx", hr );
2259 hr = Connect( p_sample_grabber, p_mpeg_demux );
2262 msg_Warn( p_access, "Build: "\
2263 "Cannot connect demux to grabber: hr=0x%8lx", hr );
2267 //msg_Dbg( p_access, "Build: Connected sample grabber to demux" );
2268 /* Always look for the Transport Information Filter from the start
2269 * of the collection*/
2271 msg_Dbg( p_access, "Check: "\
2272 "Calling FindFilter for KSCATEGORY_BDA_TRANSPORT_INFORMATION with "\
2273 "p_mpeg_demux; l_tif_used=%ld", l_tif_used );
2276 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
2277 p_mpeg_demux, &p_transport_info );
2280 msg_Warn( p_access, "Build: "\
2281 "Cannot load TIF onto demux: hr=0x%8lx", hr );
2285 /* Configure the Sample Grabber to buffer the samples continuously */
2286 hr = p_grabber->SetBufferSamples( true );
2289 msg_Warn( p_access, "Build: "\
2290 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
2294 hr = p_grabber->SetOneShot( false );
2297 msg_Warn( p_access, "Build: "\
2298 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
2302 /* Second parameter to SetCallback specifies the callback method; 0 uses
2303 * the ISampleGrabberCB::SampleCB method, which receives an IMediaSample
2305 //msg_Dbg( p_access, "Build: Adding grabber callback" );
2306 hr = p_grabber->SetCallback( this, 0 );
2309 msg_Warn( p_access, "Build: "\
2310 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
2314 hr = Register(); /* creates d_graph_register */
2317 d_graph_register = 0;
2318 msg_Dbg( p_access, "Build: "\
2319 "Cannot register graph: hr=0x%8lx", hr );
2322 /* The Media Control is used to Run and Stop the Graph */
2323 if( p_media_control )
2324 p_media_control->Release();
2325 p_media_control = NULL;
2326 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
2327 reinterpret_cast<void**>( &p_media_control ) );
2330 msg_Warn( p_access, "Build: "\
2331 "Cannot QI Media Control: hr=0x%8lx", hr );
2336 //msg_Dbg( p_access, "Build: succeeded: hr=0x%8lx", hr );
2341 HRESULT BDAGraph::ListFilters( REFCLSID this_clsid )
2348 ICreateDevEnum* p_local_system_dev_enum;
2349 IEnumMoniker* p_moniker_enum;
2350 IMoniker* p_moniker;
2351 IBaseFilter* p_filter;
2352 IBaseFilter* p_this_filter;
2353 IBindCtx* p_bind_context;
2354 IPropertyBag* p_property_bag;
2356 char* psz_downstream;
2361 p_local_system_dev_enum(NULL),
2362 p_moniker_enum(NULL),
2365 p_this_filter(NULL),
2366 p_bind_context( NULL ),
2367 p_property_bag(NULL),
2368 psz_downstream( NULL ),
2373 if( p_property_bag )
2374 p_property_bag->Release();
2375 if( p_bind_context )
2376 p_bind_context->Release();
2378 p_filter->Release();
2380 p_this_filter->Release();
2382 p_moniker->Release();
2383 if( p_moniker_enum )
2384 p_moniker_enum->Release();
2385 if( p_local_system_dev_enum )
2386 p_local_system_dev_enum->Release();
2389 if( psz_downstream )
2390 delete[] psz_downstream;
2395 // msg_Dbg( p_access, "ListFilters: Create local system_dev_enum");
2396 if( l.p_local_system_dev_enum )
2397 l.p_local_system_dev_enum->Release();
2398 l.p_local_system_dev_enum = NULL;
2399 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
2400 IID_ICreateDevEnum, reinterpret_cast<void**>( &l.p_local_system_dev_enum ) );
2403 msg_Warn( p_access, "ListFilters: "\
2404 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
2408 //msg_Dbg( p_access, "ListFilters: Create p_moniker_enum");
2409 if( l.p_moniker_enum )
2410 l.p_moniker_enum->Release();
2411 l.p_moniker_enum = NULL;
2412 hr = l.p_local_system_dev_enum->CreateClassEnumerator( this_clsid,
2413 &l.p_moniker_enum, 0 );
2416 msg_Warn( p_access, "ListFilters: "\
2417 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
2421 //msg_Dbg( p_access, "ListFilters: Entering main loop" );
2424 /* We are overwriting l.p_moniker so we should Release and nullify
2425 * It is important that p_moniker and p_property_bag are fully released
2426 * l.p_filter may not be dereferenced so we could force to NULL */
2427 /* msg_Dbg( p_access, "ListFilters: top of main loop");*/
2428 //msg_Dbg( p_access, "ListFilters: releasing property bag");
2429 if( l.p_property_bag )
2430 l.p_property_bag->Release();
2431 l.p_property_bag = NULL;
2432 //msg_Dbg( p_access, "ListFilters: releasing filter");
2434 l.p_filter->Release();
2436 //msg_Dbg( p_access, "ListFilters: releasing bind context");
2437 if( l.p_bind_context )
2438 l.p_bind_context->Release();
2439 l.p_bind_context = NULL;
2440 //msg_Dbg( p_access, "ListFilters: releasing moniker");
2442 l.p_moniker->Release();
2444 //msg_Dbg( p_access, "ListFilters: trying a moniker");
2446 if( !l.p_moniker_enum ) break;
2447 hr = l.p_moniker_enum->Next( 1, &l.p_moniker, 0 );
2448 if( hr != S_OK ) break;
2450 /* l.p_bind_context is Released at the top of the loop */
2451 hr = CreateBindCtx( 0, &l.p_bind_context );
2454 msg_Dbg( p_access, "ListFilters: "\
2455 "Cannot create bind_context, trying another: hr=0x%8lx", hr );
2459 /* l.p_filter is Released at the top of the loop */
2460 hr = l.p_moniker->BindToObject( l.p_bind_context, NULL, IID_IBaseFilter,
2461 reinterpret_cast<void**>( &l.p_filter ) );
2464 msg_Dbg( p_access, "ListFilters: "\
2465 "Cannot create p_filter, trying another: hr=0x%8lx", hr );
2469 #ifdef DEBUG_MONIKER_NAME
2470 WCHAR* pwsz_downstream = NULL;
2472 hr = l.p_moniker->GetDisplayName(l.p_bind_context, NULL,
2476 msg_Dbg( p_access, "ListFilters: "\
2477 "Cannot get display name, trying another: hr=0x%8lx", hr );
2481 if( l.psz_downstream )
2482 delete[] l.psz_downstream;
2483 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0, pwsz_downstream, -1,
2484 l.psz_downstream, 0, NULL, NULL );
2485 l.psz_downstream = new char[ l.i_bstr_len ];
2486 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0, pwsz_downstream, -1,
2487 l.psz_downstream, l.i_bstr_len, NULL, NULL );
2490 ::CoGetMalloc( 1, &p_alloc );
2491 p_alloc->Free( pwsz_downstream );
2493 msg_Dbg( p_access, "ListFilters: "\
2494 "Moniker name is %s", l.psz_downstream );
2496 l.psz_downstream = strdup( "Downstream" );
2498 /* l.p_property_bag is released at the top of the loop */
2499 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
2500 reinterpret_cast<void**>( &l.p_property_bag ) );
2503 msg_Dbg( p_access, "ListFilters: "\
2504 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
2508 //msg_Dbg( p_access, "ListFilters: displaying another" );
2515 /******************************************************************************
2517 * Looks up all filters in a category and connects to the upstream filter until
2518 * a successful match is found. The index of the connected filter is returned.
2519 * On subsequent calls, this can be used to start from that point to find
2521 * This is used when the graph does not run because a tuner device is in use so
2522 * another one needs to be selected.
2523 ******************************************************************************/
2524 HRESULT BDAGraph::FindFilter( REFCLSID this_clsid, long* i_moniker_used,
2525 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
2528 int i_moniker_index = -1;
2532 IEnumMoniker* p_moniker_enum;
2533 IMoniker* p_moniker;
2534 IBindCtx* p_bind_context;
2535 IPropertyBag* p_property_bag;
2539 char* psz_downstream;
2543 p_moniker_enum(NULL),
2545 p_bind_context( NULL ),
2546 p_property_bag(NULL),
2547 psz_upstream( NULL ),
2548 psz_downstream( NULL )
2550 ::VariantInit(&var_bstr);
2554 if( p_moniker_enum )
2555 p_moniker_enum->Release();
2557 p_moniker->Release();
2558 if( p_bind_context )
2559 p_bind_context->Release();
2560 if( p_property_bag )
2561 p_property_bag->Release();
2563 delete[] psz_upstream;
2564 if( psz_downstream )
2565 delete[] psz_downstream;
2567 ::VariantClear(&var_bstr);
2571 /* create system_dev_enum the first time through, or preserve the
2572 * existing one to loop through classes */
2573 if( !p_system_dev_enum )
2575 msg_Dbg( p_access, "FindFilter: Create p_system_dev_enum");
2576 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
2577 IID_ICreateDevEnum, reinterpret_cast<void**>( &p_system_dev_enum ) );
2580 msg_Warn( p_access, "FindFilter: "\
2581 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
2586 msg_Dbg( p_access, "FindFilter: Create p_moniker_enum");
2587 hr = p_system_dev_enum->CreateClassEnumerator( this_clsid,
2588 &l.p_moniker_enum, 0 );
2591 msg_Warn( p_access, "FindFilter: "\
2592 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
2596 msg_Dbg( p_access, "FindFilter: get filter name");
2597 hr = GetFilterName( p_upstream, &l.psz_upstream );
2600 msg_Warn( p_access, "FindFilter: "\
2601 "Cannot GetFilterName: hr=0x%8lx", hr );
2605 msg_Dbg( p_access, "FindFilter: "\
2606 "called with i_moniker_used=%ld, " \
2607 "p_upstream = %s", *i_moniker_used, l.psz_upstream );
2611 /* We are overwriting l.p_moniker so we should Release and nullify
2612 * It is important that p_moniker and p_property_bag are fully released */
2613 msg_Dbg( p_access, "FindFilter: top of main loop");
2614 if( l.p_property_bag )
2615 l.p_property_bag->Release();
2616 l.p_property_bag = NULL;
2617 msg_Dbg( p_access, "FindFilter: releasing bind context");
2618 if( l.p_bind_context )
2619 l.p_bind_context->Release();
2620 l.p_bind_context = NULL;
2621 msg_Dbg( p_access, "FindFilter: releasing moniker");
2623 l.p_moniker->Release();
2624 msg_Dbg( p_access, "FindFilter: null moniker");
2627 msg_Dbg( p_access, "FindFilter: quit if no enum");
2628 if( !l.p_moniker_enum ) break;
2629 msg_Dbg( p_access, "FindFilter: trying a moniker");
2630 hr = l.p_moniker_enum->Next( 1, &l.p_moniker, 0 );
2631 if( hr != S_OK ) break;
2635 /* Skip over devices already found on previous calls */
2636 msg_Dbg( p_access, "FindFilter: skip previously found devices");
2638 if( i_moniker_index <= *i_moniker_used ) continue;
2639 *i_moniker_used = i_moniker_index;
2641 /* l.p_bind_context is Released at the top of the loop */
2642 msg_Dbg( p_access, "FindFilter: create bind context");
2643 hr = CreateBindCtx( 0, &l.p_bind_context );
2646 msg_Dbg( p_access, "FindFilter: "\
2647 "Cannot create bind_context, trying another: hr=0x%8lx", hr );
2651 msg_Dbg( p_access, "FindFilter: try to create downstream filter");
2652 *p_p_downstream = NULL;
2653 hr = l.p_moniker->BindToObject( l.p_bind_context, NULL, IID_IBaseFilter,
2654 reinterpret_cast<void**>( p_p_downstream ) );
2657 msg_Dbg( p_access, "FindFilter: "\
2658 "Cannot bind to downstream, trying another: hr=0x%8lx", hr );
2662 #ifdef DEBUG_MONIKER_NAME
2663 msg_Dbg( p_access, "FindFilter: get downstream filter name");
2665 WCHAR* pwsz_downstream = NULL;
2667 hr = l.p_moniker->GetDisplayName(l.p_bind_context, NULL,
2671 msg_Dbg( p_access, "FindFilter: "\
2672 "Cannot get display name, trying another: hr=0x%8lx", hr );
2676 if( l.psz_downstream )
2677 delete[] l.psz_downstream;
2678 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0, pwsz_downstream, -1,
2679 l.psz_downstream, 0, NULL, NULL );
2680 l.psz_downstream = new char[ l.i_bstr_len ];
2681 l.i_bstr_len = WideCharToMultiByte( CP_ACP, 0, pwsz_downstream, -1,
2682 l.psz_downstream, l.i_bstr_len, NULL, NULL );
2685 ::CoGetMalloc( 1, &p_alloc );
2686 p_alloc->Free( pwsz_downstream );
2689 l.psz_downstream = strdup( "Downstream" );
2692 /* l.p_property_bag is released at the top of the loop */
2693 msg_Dbg( p_access, "FindFilter: "\
2694 "Moniker name is %s, binding to storage", l.psz_downstream );
2695 hr = l.p_moniker->BindToStorage( l.p_bind_context, NULL,
2696 IID_IPropertyBag, reinterpret_cast<void**>( &l.p_property_bag ) );
2699 msg_Dbg( p_access, "FindFilter: "\
2700 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
2704 msg_Dbg( p_access, "FindFilter: read friendly name");
2705 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
2708 msg_Dbg( p_access, "FindFilter: "\
2709 "Cannot read friendly name, next?: hr=0x%8lx", hr );
2713 msg_Dbg( p_access, "FindFilter: add filter to graph" );
2714 hr = p_filter_graph->AddFilter( *p_p_downstream, l.var_bstr.bstrVal );
2717 msg_Dbg( p_access, "FindFilter: "\
2718 "Cannot add filter, trying another: hr=0x%8lx", hr );
2722 msg_Dbg( p_access, "FindFilter: "\
2723 "Trying to Connect %s to %s", l.psz_upstream, l.psz_downstream );
2724 hr = Connect( p_upstream, *p_p_downstream );
2725 if( SUCCEEDED( hr ) )
2727 msg_Dbg( p_access, "FindFilter: Connected %s", l.psz_downstream );
2731 /* Not the filter we want so unload and try the next one */
2732 /* Warning: RemoveFilter does an undocumented Release()
2733 * on pointer but does not set it to NULL */
2734 msg_Dbg( p_access, "FindFilter: Removing filter" );
2735 hr = p_filter_graph->RemoveFilter( *p_p_downstream );
2738 msg_Warn( p_access, "FindFilter: "\
2739 "Failed unloading Filter: hr=0x%8lx", hr );
2742 msg_Dbg( p_access, "FindFilter: trying another" );
2747 msg_Warn( p_access, "FindFilter: No filter connected" );
2752 /*****************************************************************************
2753 * Connect is called from Build to enumerate and connect pins
2754 *****************************************************************************/
2755 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
2757 HRESULT hr = E_FAIL;
2761 IPin* p_pin_upstream;
2762 IPin* p_pin_downstream;
2763 IEnumPins* p_pin_upstream_enum;
2764 IEnumPins* p_pin_downstream_enum;
2767 char* psz_downstream;
2770 p_pin_upstream(NULL), p_pin_downstream(NULL),
2771 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
2773 psz_upstream( NULL ),
2774 psz_downstream( NULL )
2779 p_pin_temp->Release();
2780 if( p_pin_downstream )
2781 p_pin_downstream->Release();
2782 if( p_pin_upstream )
2783 p_pin_upstream->Release();
2784 if( p_pin_downstream_enum )
2785 p_pin_downstream_enum->Release();
2786 if( p_pin_upstream_enum )
2787 p_pin_upstream_enum->Release();
2789 delete[] psz_upstream;
2790 if( psz_downstream )
2791 delete[] psz_downstream;
2795 PIN_DIRECTION pin_dir;
2797 //msg_Dbg( p_access, "Connect: entering" );
2798 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
2801 msg_Warn( p_access, "Connect: "\
2802 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
2808 /* Release l.p_pin_upstream before next iteration */
2809 if( l.p_pin_upstream )
2810 l.p_pin_upstream ->Release();
2811 l.p_pin_upstream = NULL;
2812 if( !l.p_pin_upstream_enum ) break;
2813 hr = l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 );
2814 if( hr != S_OK ) break;
2816 //msg_Dbg( p_access, "Connect: get pin name");
2817 hr = GetPinName( l.p_pin_upstream, &l.psz_upstream );
2820 msg_Warn( p_access, "Connect: "\
2821 "Cannot GetPinName: hr=0x%8lx", hr );
2824 //msg_Dbg( p_access, "Connect: p_pin_upstream = %s", l.psz_upstream );
2826 hr = l.p_pin_upstream->QueryDirection( &pin_dir );
2829 msg_Warn( p_access, "Connect: "\
2830 "Cannot get upstream filter pin direction: hr=0x%8lx", hr );
2834 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
2835 if( SUCCEEDED( hr ) )
2837 l.p_pin_downstream->Release();
2838 l.p_pin_downstream = NULL;
2841 if( FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
2843 msg_Warn( p_access, "Connect: "\
2844 "Cannot check upstream filter connection: hr=0x%8lx", hr );
2848 if( ( pin_dir == PINDIR_OUTPUT ) && ( hr == VFW_E_NOT_CONNECTED ) )
2850 /* The upstream pin is not yet connected so check each pin on the
2851 * downstream filter */
2852 //msg_Dbg( p_access, "Connect: enumerating downstream pins" );
2853 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
2856 msg_Warn( p_access, "Connect: Cannot get "\
2857 "downstream filter enumerator: hr=0x%8lx", hr );
2863 /* Release l.p_pin_downstream before next iteration */
2864 if( l.p_pin_downstream )
2865 l.p_pin_downstream ->Release();
2866 l.p_pin_downstream = NULL;
2867 if( !l.p_pin_downstream_enum ) break;
2868 hr = l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 );
2869 if( hr != S_OK ) break;
2871 //msg_Dbg( p_access, "Connect: get pin name");
2872 hr = GetPinName( l.p_pin_downstream, &l.psz_downstream );
2875 msg_Warn( p_access, "Connect: "\
2876 "Cannot GetPinName: hr=0x%8lx", hr );
2880 msg_Dbg( p_access, "Connect: Trying p_downstream = %s",
2884 hr = l.p_pin_downstream->QueryDirection( &pin_dir );
2887 msg_Warn( p_access, "Connect: Cannot get "\
2888 "downstream filter pin direction: hr=0x%8lx", hr );
2892 /* Looking for a free Pin to connect to
2893 * A connected Pin may have an reference count > 1
2894 * so Release and nullify the pointer */
2895 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
2896 if( SUCCEEDED( hr ) )
2898 l.p_pin_temp->Release();
2899 l.p_pin_temp = NULL;
2902 if( hr != VFW_E_NOT_CONNECTED )
2906 msg_Warn( p_access, "Connect: Cannot check "\
2907 "downstream filter connection: hr=0x%8lx", hr );
2912 if( ( pin_dir == PINDIR_INPUT ) &&
2913 ( hr == VFW_E_NOT_CONNECTED ) )
2915 //msg_Dbg( p_access, "Connect: trying to connect pins" );
2917 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
2918 l.p_pin_downstream, NULL );
2919 if( SUCCEEDED( hr ) )
2921 /* If we arrive here then we have a matching pair of
2926 /* If we arrive here it means this downstream pin is not
2927 * suitable so try the next downstream pin.
2928 * l.p_pin_downstream is released at the top of the loop */
2931 /* If we arrive here then we ran out of pins before we found a
2932 * suitable one. Release outstanding refcounts */
2933 if( l.p_pin_downstream_enum )
2934 l.p_pin_downstream_enum->Release();
2935 l.p_pin_downstream_enum = NULL;
2936 if( l.p_pin_downstream )
2937 l.p_pin_downstream->Release();
2938 l.p_pin_downstream = NULL;
2940 /* If we arrive here it means this upstream pin is not suitable
2941 * so try the next upstream pin
2942 * l.p_pin_upstream is released at the top of the loop */
2945 /* If we arrive here it means we did not find any pair of suitable pins
2946 * Outstanding refcounts are released in the destructor */
2947 //msg_Dbg( p_access, "Connect: No pins connected" );
2951 /*****************************************************************************
2952 * Start uses MediaControl to start the graph
2953 *****************************************************************************/
2954 HRESULT BDAGraph::Start()
2957 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
2959 msg_Dbg( p_access, "Start: entering" );
2961 if( !p_media_control )
2963 msg_Warn( p_access, "Start: Media Control has not been created" );
2967 msg_Dbg( p_access, "Start: Run()" );
2968 hr = p_media_control->Run();
2969 if( SUCCEEDED( hr ) )
2971 msg_Dbg( p_access, "Start: Graph started, hr=0x%lx", hr );
2975 msg_Dbg( p_access, "Start: would not start, will retry" );
2976 /* Query the state of the graph - timeout after 100 milliseconds */
2977 while( (hr = p_media_control->GetState( 100, &i_state) ) != S_OK )
2982 "Start: Cannot get Graph state: hr=0x%8lx", hr );
2987 msg_Dbg( p_access, "Start: got state" );
2988 if( i_state == State_Running )
2990 msg_Dbg( p_access, "Graph started after a delay, hr=0x%lx", hr );
2994 /* The Graph is not running so stop it and return an error */
2995 msg_Warn( p_access, "Start: Graph not started: %d", (int)i_state );
2996 hr = p_media_control->StopWhenReady(); /* Instead of Stop() */
3000 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
3007 /*****************************************************************************
3008 * Pop the stream of data
3009 *****************************************************************************/
3010 ssize_t BDAGraph::Pop(void *buf, size_t len)
3012 return output.Pop(buf, len);
3015 /******************************************************************************
3016 * SampleCB - Callback when the Sample Grabber has a sample
3017 ******************************************************************************/
3018 STDMETHODIMP BDAGraph::SampleCB( double /*date*/, IMediaSample *p_sample )
3020 if( p_sample->IsDiscontinuity() == S_OK )
3021 msg_Warn( p_access, "BDA SampleCB: Sample Discontinuity.");
3023 const size_t i_sample_size = p_sample->GetActualDataLength();
3025 /* The buffer memory is owned by the media sample object, and is automatically
3026 * released when the media sample is destroyed. The caller should not free or
3027 * reallocate the buffer. */
3028 BYTE *p_sample_data;
3029 p_sample->GetPointer( &p_sample_data );
3031 if( i_sample_size > 0 && p_sample_data )
3033 block_t *p_block = block_Alloc( i_sample_size );
3037 memcpy( p_block->p_buffer, p_sample_data, i_sample_size );
3038 output.Push( p_block );
3044 STDMETHODIMP BDAGraph::BufferCB( double /*date*/, BYTE* /*buffer*/,
3045 long /*buffer_len*/ )
3050 /******************************************************************************
3051 * removes each filter from the graph
3052 ******************************************************************************/
3053 HRESULT BDAGraph::Destroy()
3057 // msg_Dbg( p_access, "Destroy: media control 1" );
3058 if( p_media_control )
3059 p_media_control->StopWhenReady(); /* Instead of Stop() */
3061 // msg_Dbg( p_access, "Destroy: deregistering graph" );
3062 if( d_graph_register )
3065 // msg_Dbg( p_access, "Destroy: calling Empty" );
3068 // msg_Dbg( p_access, "Destroy: TIF" );
3069 if( p_transport_info )
3071 /* Warning: RemoveFilter does an undocumented Release()
3072 * on pointer but does not set it to NULL */
3073 hr = p_filter_graph->RemoveFilter( p_transport_info );
3076 msg_Dbg( p_access, "Destroy: "\
3077 "Failed unloading TIF: hr=0x%8lx", hr );
3079 p_transport_info = NULL;
3082 // msg_Dbg( p_access, "Destroy: demux" );
3085 p_filter_graph->RemoveFilter( p_mpeg_demux );
3088 msg_Dbg( p_access, "Destroy: "\
3089 "Failed unloading demux: hr=0x%8lx", hr );
3091 p_mpeg_demux = NULL;
3094 // msg_Dbg( p_access, "Destroy: sample grabber" );
3097 mem_ref = p_grabber->Release();
3100 msg_Dbg( p_access, "Destroy: "\
3101 "Sample grabber mem_ref (varies): mem_ref=%ld", mem_ref );
3106 // msg_Dbg( p_access, "Destroy: sample grabber filter" );
3107 if( p_sample_grabber )
3109 hr = p_filter_graph->RemoveFilter( p_sample_grabber );
3110 p_sample_grabber = NULL;
3113 msg_Dbg( p_access, "Destroy: "\
3114 "Failed unloading sampler: hr=0x%8lx", hr );
3118 // msg_Dbg( p_access, "Destroy: capture device" );
3119 if( p_capture_device )
3121 p_filter_graph->RemoveFilter( p_capture_device );
3124 msg_Dbg( p_access, "Destroy: "\
3125 "Failed unloading capture device: hr=0x%8lx", hr );
3127 p_capture_device = NULL;
3130 // msg_Dbg( p_access, "Destroy: tuner device" );
3131 if( p_tuner_device )
3133 //msg_Dbg( p_access, "Destroy: remove filter on tuner device" );
3134 hr = p_filter_graph->RemoveFilter( p_tuner_device );
3135 //msg_Dbg( p_access, "Destroy: force tuner device to NULL" );
3136 p_tuner_device = NULL;
3139 msg_Dbg( p_access, "Destroy: "\
3140 "Failed unloading tuner device: hr=0x%8lx", hr );
3144 // msg_Dbg( p_access, "Destroy: scanning tuner" );
3145 if( p_scanning_tuner )
3147 mem_ref = p_scanning_tuner->Release();
3150 msg_Dbg( p_access, "Destroy: "\
3151 "Scanning tuner mem_ref (normally 2 if warm, "\
3152 "3 if active): mem_ref=%ld", mem_ref );
3154 p_scanning_tuner = NULL;
3157 // msg_Dbg( p_access, "Destroy: net provider" );
3158 if( p_network_provider )
3160 hr = p_filter_graph->RemoveFilter( p_network_provider );
3161 p_network_provider = NULL;
3164 msg_Dbg( p_access, "Destroy: "\
3165 "Failed unloading net provider: hr=0x%8lx", hr );
3169 // msg_Dbg( p_access, "Destroy: filter graph" );
3170 if( p_filter_graph )
3172 mem_ref = p_filter_graph->Release();
3175 msg_Dbg( p_access, "Destroy: "\
3176 "Filter graph mem_ref (normally 1 if active): mem_ref=%ld",
3179 p_filter_graph = NULL;
3182 /* first call to FindFilter creates p_system_dev_enum */
3184 // msg_Dbg( p_access, "Destroy: system dev enum" );
3185 if( p_system_dev_enum )
3187 mem_ref = p_system_dev_enum->Release();
3190 msg_Dbg( p_access, "Destroy: "\
3191 "System_dev_enum mem_ref: mem_ref=%ld", mem_ref );
3193 p_system_dev_enum = NULL;
3196 // msg_Dbg( p_access, "Destroy: media control 2" );
3197 if( p_media_control )
3199 msg_Dbg( p_access, "Destroy: release media control" );
3200 mem_ref = p_media_control->Release();
3203 msg_Dbg( p_access, "Destroy: "\
3204 "Media control mem_ref: mem_ref=%ld", mem_ref );
3206 msg_Dbg( p_access, "Destroy: force media control to NULL" );
3207 p_media_control = NULL;
3210 d_graph_register = 0;
3212 guid_network_type = GUID_NULL;
3214 // msg_Dbg( p_access, "Destroy: returning" );
3218 /*****************************************************************************
3219 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
3220 * Allows GraphEdit to "spy" on a remote filter graph.
3221 ******************************************************************************/
3222 HRESULT BDAGraph::Register()
3227 IMoniker* p_moniker;
3228 IRunningObjectTable* p_ro_table;
3236 p_moniker->Release();
3238 p_ro_table->Release();
3241 WCHAR pwsz_graph_name[128];
3244 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
3247 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
3251 size_t len = sizeof(pwsz_graph_name) / sizeof(pwsz_graph_name[0]);
3252 _snwprintf( pwsz_graph_name, len - 1, L"VLC BDA Graph %08x Pid %08x",
3253 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
3254 pwsz_graph_name[len-1] = 0;
3255 hr = CreateItemMoniker( L"!", pwsz_graph_name, &l.p_moniker );
3258 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
3261 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
3262 p_filter_graph, l.p_moniker, &d_graph_register );
3265 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
3269 msg_Dbg( p_access, "Register: registered Graph: %S", pwsz_graph_name );
3273 void BDAGraph::Deregister()
3276 IRunningObjectTable* p_ro_table;
3277 hr = ::GetRunningObjectTable( 0, &p_ro_table );
3278 /* docs say this does a Release() on d_graph_register stuff */
3279 if( SUCCEEDED( hr ) )
3280 p_ro_table->Revoke( d_graph_register );
3281 d_graph_register = 0;
3282 p_ro_table->Release();
3285 HRESULT BDAGraph::GetFilterName( IBaseFilter* p_filter, char** psz_bstr_name )
3287 FILTER_INFO filter_info;
3290 hr = p_filter->QueryFilterInfo(&filter_info);
3293 int i_name_len = WideCharToMultiByte( CP_ACP, 0, filter_info.achName,
3294 -1, *psz_bstr_name, 0, NULL, NULL );
3295 *psz_bstr_name = new char[ i_name_len ];
3296 i_name_len = WideCharToMultiByte( CP_ACP, 0, filter_info.achName,
3297 -1, *psz_bstr_name, i_name_len, NULL, NULL );
3299 // The FILTER_INFO structure holds a pointer to the Filter Graph
3300 // Manager, with a reference count that must be released.
3301 if( filter_info.pGraph )
3302 filter_info.pGraph->Release();
3306 HRESULT BDAGraph::GetPinName( IPin* p_pin, char** psz_bstr_name )
3311 hr = p_pin->QueryPinInfo(&pin_info);
3314 int i_name_len = WideCharToMultiByte( CP_ACP, 0, pin_info.achName,
3315 -1, *psz_bstr_name, 0, NULL, NULL );
3316 *psz_bstr_name = new char[ i_name_len ];
3317 i_name_len = WideCharToMultiByte( CP_ACP, 0, pin_info.achName,
3318 -1, *psz_bstr_name, i_name_len, NULL, NULL );
3320 // The PIN_INFO structure holds a pointer to the Filter,
3321 // with a referenppce count that must be released.
3322 if( pin_info.pFilter )
3323 pin_info.pFilter->Release();
3327 IPin* BDAGraph::FindPinOnFilter( IBaseFilter* pBaseFilter, const char* pPinName)
3330 IEnumPins *pEnumPin = NULL;
3331 ULONG CountReceived = 0;
3332 IPin *pPin = NULL, *pThePin = NULL;
3338 if (!pBaseFilter || !pPinName)
3341 // enumerate of pins on the filter
3342 hr = pBaseFilter->EnumPins(&pEnumPin);
3343 if (hr == S_OK && pEnumPin)
3346 while (pEnumPin->Next( 1, &pPin, &CountReceived) == S_OK && pPin)
3348 memset(String, 0, sizeof(String));
3350 hr = pPin->QueryPinInfo(&PinInfo);
3353 length = wcslen (PinInfo.achName) + 1;
3354 pString = new char [length];
3357 WideCharToMultiByte(CP_ACP, 0, PinInfo.achName, -1, pString, length,
3360 //strcat (String, pString);
3361 //StringCbCat(String,strlen(String) + strlen(pString)+1,pString);
3362 snprintf( String, strlen(String) + strlen(pString) + 1, "%s%s", String, pString);
3365 if (strstr(String, pPinName))
3366 pThePin = pPin; // yes
3375 // need to release this pin
3380 } // end if have pin
3382 // need to release the enumerator
3383 pEnumPin->Release();
3386 // return address of pin if found on the filter