]> git.sesse.net Git - vlc/blob - modules/access/bda/bdagraph.cpp
pda gui: Set prio to 0, so it is not eligible for automatic selection. This is bad...
[vlc] / modules / access / bda / bdagraph.cpp
1 /*****************************************************************************
2  * bdagraph.cpp : DirectShow BDA graph for vlc
3  *****************************************************************************
4  * Copyright( C ) 2007 the VideoLAN team
5  *
6  * Author: Ken Self <kens@campoz.fslife.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  *( at your option ) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include "bdagraph.h"
27 #include <ctype.h>
28
29 /****************************************************************************
30  * Interfaces for calls from C
31  ****************************************************************************/
32 extern "C" {
33
34     void dvb_newBDAGraph( access_t* p_access )
35     {
36         p_access->p_sys->p_bda_module = new BDAGraph( p_access );
37     };
38
39     void dvb_deleteBDAGraph( access_t* p_access )
40     {
41         if( p_access->p_sys->p_bda_module )
42             delete p_access->p_sys->p_bda_module;
43     };
44
45     int dvb_SubmitATSCTuneRequest( access_t* p_access )
46     {
47         if( p_access->p_sys->p_bda_module )
48             return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
49         return VLC_EGENERIC;
50     };
51
52     int dvb_SubmitDVBTTuneRequest( access_t* p_access )
53     {
54         if( p_access->p_sys->p_bda_module )
55             return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
56         return VLC_EGENERIC;
57     };
58
59     int dvb_SubmitDVBCTuneRequest( access_t* p_access )
60     {
61         if( p_access->p_sys->p_bda_module )
62             return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
63         return VLC_EGENERIC;
64     };
65
66     int dvb_SubmitDVBSTuneRequest( access_t* p_access )
67     {
68         if( p_access->p_sys->p_bda_module )
69             return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
70         return VLC_EGENERIC;
71     };
72
73     long dvb_GetBufferSize( access_t* p_access )
74     {
75         if( p_access->p_sys->p_bda_module )
76             return p_access->p_sys->p_bda_module->GetBufferSize();
77         return -1;
78     };
79
80     long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
81     {
82         if( p_access->p_sys->p_bda_module )
83             return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
84                 p_buff );
85         return -1;
86     };
87 };
88
89 /*****************************************************************************
90 * Constructor
91 *****************************************************************************/
92 BDAGraph::BDAGraph( access_t* p_this ):
93     p_access( p_this ),
94     guid_network_type(GUID_NULL),
95     l_tuner_used(-1),
96     d_graph_register( 0 )
97 {
98     b_ready = FALSE;
99     p_tuning_space = NULL;
100     p_tune_request = NULL;
101     p_media_control = NULL;
102     p_filter_graph = NULL;
103     p_system_dev_enum = NULL;
104     p_network_provider = p_tuner_device = p_capture_device = NULL;
105     p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
106     p_scanning_tuner = NULL;
107     p_grabber = NULL;
108
109     /* Initialize COM - MS says to use CoInitializeEx in preference to
110      * CoInitialize */
111     CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
112 }
113
114 /*****************************************************************************
115 * Destructor
116 *****************************************************************************/
117 BDAGraph::~BDAGraph()
118 {
119     Destroy();
120     CoUninitialize();
121 }
122
123 /*****************************************************************************
124 * Submit an ATSC Tune Request
125 *****************************************************************************/
126 int BDAGraph::SubmitATSCTuneRequest()
127 {
128     HRESULT hr = S_OK;
129     class localComPtr
130     {
131         public:
132         IATSCChannelTuneRequest* p_atsc_tune_request;
133         IATSCLocator* p_atsc_locator;
134         localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
135         ~localComPtr()
136         {
137             if( p_atsc_tune_request )
138                 p_atsc_tune_request->Release();
139             if( p_atsc_locator )
140                 p_atsc_locator->Release();
141         }
142     } l;
143     long l_major_channel, l_minor_channel, l_physical_channel;
144
145     l_major_channel = l_minor_channel = l_physical_channel = -1;
146 /*
147     l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
148     l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
149     l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
150 */
151
152     guid_network_type = CLSID_ATSCNetworkProvider;
153     hr = CreateTuneRequest();
154     if( FAILED( hr ) )
155     {
156         msg_Warn( p_access, "SubmitATSCTuneRequest: "\
157             "Cannot create Tuning Space: hr=0x%8lx", hr );
158         return VLC_EGENERIC;
159     }
160
161     hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
162         (void**)&l.p_atsc_tune_request );
163     if( FAILED( hr ) )
164     {
165         msg_Warn( p_access, "SubmitATSCTuneRequest: "\
166             "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
167         return VLC_EGENERIC;
168     }
169     hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
170                              IID_IATSCLocator, (void**)&l.p_atsc_locator );
171     if( FAILED( hr ) )
172     {
173         msg_Warn( p_access, "SubmitATSCTuneRequest: "\
174             "Cannot create the ATSC locator: hr=0x%8lx", hr );
175         return VLC_EGENERIC;
176     }
177
178     hr = S_OK;
179     if( l_major_channel > 0 )
180         hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
181     if( SUCCEEDED( hr ) && l_minor_channel > 0 )
182         hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
183     if( SUCCEEDED( hr ) && l_physical_channel > 0 )
184         hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
185     if( FAILED( hr ) )
186     {
187         msg_Warn( p_access, "SubmitATSCTuneRequest: "\
188             "Cannot set tuning parameters: hr=0x%8lx", hr );
189         return VLC_EGENERIC;
190     }
191
192     hr = p_tune_request->put_Locator( l.p_atsc_locator );
193     if( FAILED( hr ) )
194     {
195         msg_Warn( p_access, "SubmitATSCTuneRequest: "\
196             "Cannot put the locator: hr=0x%8lx", hr );
197         return VLC_EGENERIC;
198     }
199
200     /* Build and Run the Graph. If a Tuner device is in use the graph will
201      * fail to run. Repeated calls to build will check successive tuner
202      * devices */
203     do
204     {
205         hr = Build();
206         if( FAILED( hr ) )
207         {
208             msg_Warn( p_access, "SubmitATSCTuneRequest: "\
209                 "Cannot Build the Graph: hr=0x%8lx", hr );
210             return VLC_EGENERIC;
211         }
212         hr = Start();
213     }
214     while( hr != S_OK );
215
216     return VLC_SUCCESS;
217 }
218
219 /*****************************************************************************
220 * Submit a DVB-T Tune Request
221 ******************************************************************************/
222 int BDAGraph::SubmitDVBTTuneRequest()
223 {
224     HRESULT hr = S_OK;
225     class localComPtr
226     {
227         public:
228         IDVBTuneRequest* p_dvbt_tune_request;
229         IDVBTLocator* p_dvbt_locator;
230         localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
231         ~localComPtr()
232         {
233             if( p_dvbt_tune_request )
234                 p_dvbt_tune_request->Release();
235             if( p_dvbt_locator )
236                 p_dvbt_locator->Release();
237         }
238     } l;
239     long l_frequency, l_bandwidth, l_hp_fec, l_lp_fec, l_guard;
240     long l_transmission, l_hierarchy;
241     BinaryConvolutionCodeRate i_hp_fec, i_lp_fec;
242     GuardInterval             i_guard;
243     TransmissionMode          i_transmission;
244     HierarchyAlpha            i_hierarchy;
245
246     l_frequency = l_bandwidth = l_hp_fec = l_lp_fec = l_guard = -1;
247     l_transmission = l_hierarchy = -1;
248     l_frequency = var_GetInteger( p_access, "dvb-frequency" );
249     l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
250     l_hp_fec = var_GetInteger( p_access, "dvb-code-rate-hp" );
251     l_lp_fec = var_GetInteger( p_access, "dvb-code-rate-lp" );
252     l_guard = var_GetInteger( p_access, "dvb-guard" );
253     l_transmission = var_GetInteger( p_access, "dvb-transmission" );
254     l_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
255
256     i_hp_fec = BDA_BCC_RATE_NOT_SET;
257     if( l_hp_fec == 1 )
258         i_hp_fec = BDA_BCC_RATE_1_2;
259     if( l_hp_fec == 2 )
260         i_hp_fec = BDA_BCC_RATE_2_3;
261     if( l_hp_fec == 3 )
262         i_hp_fec = BDA_BCC_RATE_3_4;
263     if( l_hp_fec == 4 )
264         i_hp_fec = BDA_BCC_RATE_5_6;
265     if( l_hp_fec == 5 )
266         i_hp_fec = BDA_BCC_RATE_7_8;
267
268     i_lp_fec = BDA_BCC_RATE_NOT_SET;
269     if( l_lp_fec == 1 )
270         i_lp_fec = BDA_BCC_RATE_1_2;
271     if( l_lp_fec == 2 )
272         i_lp_fec = BDA_BCC_RATE_2_3;
273     if( l_lp_fec == 3 )
274         i_lp_fec = BDA_BCC_RATE_3_4;
275     if( l_lp_fec == 4 )
276         i_lp_fec = BDA_BCC_RATE_5_6;
277     if( l_lp_fec == 5 )
278         i_lp_fec = BDA_BCC_RATE_7_8;
279
280     i_guard = BDA_GUARD_NOT_SET;
281     if( l_guard == 32 )
282         i_guard = BDA_GUARD_1_32;
283     if( l_guard == 16 )
284         i_guard = BDA_GUARD_1_16;
285     if( l_guard == 8 )
286         i_guard = BDA_GUARD_1_8;
287     if( l_guard == 4 )
288         i_guard = BDA_GUARD_1_4;
289
290     i_transmission = BDA_XMIT_MODE_NOT_SET;
291     if( l_transmission == 2 )
292         i_transmission = BDA_XMIT_MODE_2K;
293     if( l_transmission == 8 )
294         i_transmission = BDA_XMIT_MODE_8K;
295
296     i_hierarchy = BDA_HALPHA_NOT_SET;
297     if( l_hierarchy == 1 )
298         i_hierarchy = BDA_HALPHA_1;
299     if( l_hierarchy == 2 )
300         i_hierarchy = BDA_HALPHA_2;
301     if( l_hierarchy == 4 )
302         i_hierarchy = BDA_HALPHA_4;
303
304     guid_network_type = CLSID_DVBTNetworkProvider;
305     hr = CreateTuneRequest();
306     if( FAILED( hr ) )
307     {
308         msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
309             "Cannot create Tune Request: hr=0x%8lx", hr );
310         return VLC_EGENERIC;
311     }
312
313     hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
314         (void**)&l.p_dvbt_tune_request );
315     if( FAILED( hr ) )
316     {
317         msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
318             "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
319         return VLC_EGENERIC;
320     }
321     l.p_dvbt_tune_request->put_ONID( -1 );
322     l.p_dvbt_tune_request->put_SID( -1 );
323     l.p_dvbt_tune_request->put_TSID( -1 );
324
325     hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
326         IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
327     if( FAILED( hr ) )
328     {
329         msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
330             "Cannot create the DVBT Locator: hr=0x%8lx", hr );
331         return VLC_EGENERIC;
332     }
333
334     hr = S_OK;
335     if( l_frequency > 0 )
336         hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
337     if( SUCCEEDED( hr ) && l_bandwidth > 0 )
338         hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
339     if( SUCCEEDED( hr ) && i_hp_fec != BDA_BCC_RATE_NOT_SET )
340         hr = l.p_dvbt_locator->put_InnerFECRate( i_hp_fec );
341     if( SUCCEEDED( hr ) && i_lp_fec != BDA_BCC_RATE_NOT_SET )
342         hr = l.p_dvbt_locator->put_LPInnerFECRate( i_lp_fec );
343     if( SUCCEEDED( hr ) && i_guard != BDA_GUARD_NOT_SET )
344         hr = l.p_dvbt_locator->put_Guard( i_guard );
345     if( SUCCEEDED( hr ) && i_transmission != BDA_XMIT_MODE_NOT_SET )
346         hr = l.p_dvbt_locator->put_Mode( i_transmission );
347     if( SUCCEEDED( hr ) && i_hierarchy != BDA_HALPHA_NOT_SET )
348         hr = l.p_dvbt_locator->put_HAlpha( i_hierarchy );
349     if( FAILED( hr ) )
350     {
351         msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
352             "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
353         return VLC_EGENERIC;
354     }
355
356     hr = p_tune_request->put_Locator( l.p_dvbt_locator );
357     if( FAILED( hr ) )
358     {
359         msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
360             "Cannot put the locator: hr=0x%8lx", hr );
361         return VLC_EGENERIC;
362     }
363
364     /* Build and Run the Graph. If a Tuner device is in use the graph will
365      * fail to run. Repeated calls to build will check successive tuner
366      * devices */
367     do
368     {
369         hr = Build();
370         if( FAILED( hr ) )
371         {
372             msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
373                 "Cannot Build the Graph: hr=0x%8lx", hr );
374             return VLC_EGENERIC;
375         }
376         hr = Start();
377     }
378     while( hr != S_OK );
379
380     return VLC_SUCCESS;
381 }
382
383 /*****************************************************************************
384 * Submit a DVB-C Tune Request
385 ******************************************************************************/
386 int BDAGraph::SubmitDVBCTuneRequest()
387 {
388     HRESULT hr = S_OK;
389
390     class localComPtr
391     {
392         public:
393         IDVBTuneRequest* p_dvbc_tune_request;
394         IDVBCLocator* p_dvbc_locator;
395         localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
396         ~localComPtr()
397         {
398             if( p_dvbc_tune_request )
399                 p_dvbc_tune_request->Release();
400             if( p_dvbc_locator )
401                 p_dvbc_locator->Release();
402         }
403     } l;
404
405     long l_frequency, l_symbolrate;
406     int  i_qam;
407     ModulationType i_qam_mod;
408
409     l_frequency = l_symbolrate = i_qam = -1;
410     l_frequency = var_GetInteger( p_access, "dvb-frequency" );
411     l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
412     i_qam = var_GetInteger( p_access, "dvb-modulation" );
413     i_qam_mod = BDA_MOD_NOT_SET;
414     if( i_qam == 16 )
415         i_qam_mod = BDA_MOD_16QAM;
416     if( i_qam == 32 )
417         i_qam_mod = BDA_MOD_32QAM;
418     if( i_qam == 64 )
419         i_qam_mod = BDA_MOD_64QAM;
420     if( i_qam == 128 )
421         i_qam_mod = BDA_MOD_128QAM;
422     if( i_qam == 256 )
423         i_qam_mod = BDA_MOD_256QAM;
424
425     guid_network_type = CLSID_DVBCNetworkProvider;
426     hr = CreateTuneRequest();
427     if( FAILED( hr ) )
428     {
429         msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
430             "Cannot create Tune Request: hr=0x%8lx", hr );
431         return VLC_EGENERIC;
432     }
433
434     hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
435         (void**)&l.p_dvbc_tune_request );
436     if( FAILED( hr ) )
437     {
438         msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
439             "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
440         return VLC_EGENERIC;
441     }
442     l.p_dvbc_tune_request->put_ONID( -1 );
443     l.p_dvbc_tune_request->put_SID( -1 );
444     l.p_dvbc_tune_request->put_TSID( -1 );
445
446     hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
447         IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
448     if( FAILED( hr ) )
449     {
450         msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
451             "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
452         return VLC_EGENERIC;
453     }
454
455     hr = S_OK;
456     if( l_frequency > 0 )
457         hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
458     if( SUCCEEDED( hr ) && l_symbolrate > 0 )
459         hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
460     if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
461         hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
462     if( FAILED( hr ) )
463     {
464         msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
465             "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
466         return VLC_EGENERIC;
467     }
468
469     hr = p_tune_request->put_Locator( l.p_dvbc_locator );
470     if( FAILED( hr ) )
471     {
472         msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
473             "Cannot put the locator: hr=0x%8lx", hr );
474         return VLC_EGENERIC;
475     }
476
477     /* Build and Run the Graph. If a Tuner device is in use the graph will
478      * fail to run. Repeated calls to build will check successive tuner
479      * devices */
480     do
481     {
482         hr = Build();
483         if( FAILED( hr ) )
484         {
485             msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
486                 "Cannot Build the Graph: hr=0x%8lx", hr );
487             return VLC_EGENERIC;
488         }
489         hr = Start();
490     }
491     while( hr != S_OK );
492
493     return VLC_SUCCESS;
494 }
495
496 /*****************************************************************************
497 * Submit a DVB-S Tune Request
498 ******************************************************************************/
499 int BDAGraph::SubmitDVBSTuneRequest()
500 {
501     HRESULT hr = S_OK;
502
503     class localComPtr
504     {
505         public:
506         IDVBTuneRequest* p_dvbs_tune_request;
507         IDVBSLocator* p_dvbs_locator;
508         IDVBSTuningSpace* p_dvbs_tuning_space;
509         localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL),
510             p_dvbs_tuning_space(NULL) {};
511         ~localComPtr()
512         {
513             if( p_dvbs_tuning_space )
514                 p_dvbs_tuning_space->Release();
515             if( p_dvbs_tune_request )
516                 p_dvbs_tune_request->Release();
517             if( p_dvbs_locator )
518                 p_dvbs_locator->Release();
519         }
520     } l;
521     long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
522     long l_lnb_lof1, l_lnb_lof2, l_lnb_slof, l_inversion, l_network_id;
523     char* psz_polarisation;
524     Polarisation i_polar;
525     SpectralInversion i_inversion;
526     VARIANT_BOOL b_west;
527
528     l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
529     l_lnb_lof1 = l_lnb_lof2 = l_lnb_slof = l_inversion = l_network_id = -1;
530     l_frequency = var_GetInteger( p_access, "dvb-frequency" );
531     l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
532     l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
533     l_elevation = var_GetInteger( p_access, "dvb-elevation" );
534     l_longitude = var_GetInteger( p_access, "dvb-longitude" );
535     l_lnb_lof1 = var_GetInteger( p_access, "dvb-lnb-lof1" );
536     l_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
537     l_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
538     psz_polarisation = var_GetNonEmptyString( p_access, "dvb-polarisation" );
539     l_inversion = var_GetInteger( p_access, "dvb-inversion" );
540     l_network_id = var_GetInteger( p_access, "dvb-network_id" );
541
542     b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
543
544     i_polar = BDA_POLARISATION_NOT_SET;
545     if( psz_polarisation != NULL )
546         switch( toupper( psz_polarisation[0] ) )
547         {
548             case 'H':
549                 i_polar = BDA_POLARISATION_LINEAR_H;
550                 break;
551             case 'V':
552                 i_polar = BDA_POLARISATION_LINEAR_V;
553                 break;
554             case 'L':
555                 i_polar = BDA_POLARISATION_CIRCULAR_L;
556                 break;
557             case 'R':
558                 i_polar = BDA_POLARISATION_CIRCULAR_R;
559                 break;
560         }
561
562     i_inversion = BDA_SPECTRAL_INVERSION_NOT_SET;
563     if( l_inversion == 0 )
564         i_inversion = BDA_SPECTRAL_INVERSION_NORMAL;
565     if( l_inversion == 1 )
566         i_inversion = BDA_SPECTRAL_INVERSION_INVERTED;
567     if( l_inversion == 2 )
568         i_inversion = BDA_SPECTRAL_INVERSION_AUTOMATIC;
569
570     guid_network_type = CLSID_DVBSNetworkProvider;
571     hr = CreateTuneRequest();
572     if( FAILED( hr ) )
573     {
574         msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
575             "Cannot create Tune Request: hr=0x%8lx", hr );
576         return VLC_EGENERIC;
577     }
578
579     hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
580         (void**)&l.p_dvbs_tune_request );
581     if( FAILED( hr ) )
582     {
583         msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
584             "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
585         return VLC_EGENERIC;
586     }
587     l.p_dvbs_tune_request->put_ONID( -1 );
588     l.p_dvbs_tune_request->put_SID( -1 );
589     l.p_dvbs_tune_request->put_TSID( -1 );
590
591     hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
592         IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
593     if( FAILED( hr ) )
594     {
595         msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
596             "Cannot create the DVBS Locator: hr=0x%8lx", hr );
597         return VLC_EGENERIC;
598     }
599
600     hr = p_tuning_space->QueryInterface( IID_IDVBSTuningSpace,
601         (void**)&l.p_dvbs_tuning_space );
602     if( FAILED( hr ) )
603     {
604         msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
605             "Cannot QI for IDVBSTuningSpace: hr=0x%8lx", hr );
606         return VLC_EGENERIC;
607     }
608
609     hr = S_OK;
610     if( l_frequency > 0 )
611         hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
612     if( SUCCEEDED( hr ) && l_symbolrate > 0 )
613         hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
614     if( SUCCEEDED( hr ) && l_azimuth > 0 )
615         hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
616     if( SUCCEEDED( hr ) && l_elevation > 0 )
617         hr = l.p_dvbs_locator->put_Elevation( l_elevation );
618     if( SUCCEEDED( hr ) )
619         hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
620     if( SUCCEEDED( hr ) )
621         hr = l.p_dvbs_locator->put_WestPosition( b_west );
622     if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
623         hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
624     if( SUCCEEDED( hr ) && l_lnb_lof1 > 0 )
625         hr = l.p_dvbs_tuning_space->put_LowOscillator( l_lnb_lof1 );
626     if( SUCCEEDED( hr ) && l_lnb_lof2 > 0 )
627         hr = l.p_dvbs_tuning_space->put_HighOscillator( l_lnb_lof2 );
628     if( SUCCEEDED( hr ) && l_lnb_slof > 0 )
629         hr = l.p_dvbs_tuning_space->put_LNBSwitch( l_lnb_slof );
630     if( SUCCEEDED( hr ) && i_inversion != BDA_SPECTRAL_INVERSION_NOT_SET )
631         hr = l.p_dvbs_tuning_space->put_SpectralInversion( i_inversion );
632     if( SUCCEEDED( hr ) && l_network_id > 0 )
633         hr = l.p_dvbs_tuning_space->put_NetworkID( l_network_id );
634     if( FAILED( hr ) )
635     {
636         msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
637             "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
638         return VLC_EGENERIC;
639     }
640
641     hr = p_tune_request->put_Locator( l.p_dvbs_locator );
642     if( FAILED( hr ) )
643     {
644         msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
645             "Cannot put the locator: hr=0x%8lx", hr );
646         return VLC_EGENERIC;
647     }
648
649     /* Build and Run the Graph. If a Tuner device is in use the graph will
650      * fail to run. Repeated calls to build will check successive tuner
651      * devices */
652     do
653     {
654         hr = Build();
655         if( FAILED( hr ) )
656         {
657             msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
658                 "Cannot Build the Graph: hr=0x%8lx", hr );
659             return VLC_EGENERIC;
660         }
661         hr = Start();
662     }
663     while( hr != S_OK );
664
665     return VLC_SUCCESS;
666 }
667
668 /*****************************************************************************
669 * Load the Tuning Space from System Tuning Spaces according to the
670 * Network Type requested
671 ******************************************************************************/
672 HRESULT BDAGraph::CreateTuneRequest()
673 {
674     HRESULT hr = S_OK;
675     GUID guid_this_network_type;
676     class localComPtr
677     {
678         public:
679         ITuningSpaceContainer*  p_tuning_space_container;
680         IEnumTuningSpaces*      p_tuning_space_enum;
681         ITuningSpace*           p_this_tuning_space;
682         localComPtr(): p_tuning_space_container(NULL),
683             p_tuning_space_enum(NULL), p_this_tuning_space(NULL) {};
684         ~localComPtr()
685         {
686             if( p_tuning_space_container )
687                 p_tuning_space_container->Release();
688             if( p_tuning_space_enum )
689                 p_tuning_space_enum->Release();
690             if( p_this_tuning_space )
691                 p_this_tuning_space->Release();
692         }
693     } l;
694
695     /* A Tuning Space may already have been set up. If it is for the same
696      * network type then all is well. Otherwise, reset the Tuning Space and get
697      * a new one */
698     if( p_tuning_space )
699     {
700         hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
701         if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
702         if( guid_this_network_type == guid_network_type )
703         {
704             return S_OK;
705         }
706         else
707         {
708             p_tuning_space->Release();
709             p_tuning_space = NULL;
710         }
711     }
712
713     /* Force use of the first available Tuner Device during Build */
714     l_tuner_used = -1;
715
716     /* Get the SystemTuningSpaces container to enumerate through all the
717      * defined tuning spaces */
718     hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
719         IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
720     if( FAILED( hr ) )
721     {
722         msg_Warn( p_access, "CreateTuneRequest: "\
723             "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
724         return hr;
725     }
726
727     hr = l.p_tuning_space_container->get_EnumTuningSpaces(
728          &l.p_tuning_space_enum );
729     if( FAILED( hr ) )
730     {
731         msg_Warn( p_access, "CreateTuneRequest: "\
732             "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
733         return hr;
734     }
735
736     while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
737         S_OK )
738     {
739        hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
740
741         /* GUID_NULL means a non-BDA network was found e.g analog
742          * Ignore failures and non-BDA networks and keep looking */
743         if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
744
745         if( guid_this_network_type == guid_network_type )
746         {
747             hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
748                 (void**)&p_tuning_space );
749             if( FAILED( hr ) )
750             {
751                 msg_Warn( p_access, "CreateTuneRequest: "\
752                     "Cannot QI Tuning Space: hr=0x%8lx", hr );
753                 return hr;
754             }
755             hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
756             if( FAILED( hr ) )
757             {
758                 msg_Warn( p_access, "CreateTuneRequest: "\
759                     "Cannot Create Tune Request: hr=0x%8lx", hr );
760                 return hr;
761             }
762             return hr;
763         }
764     }
765     hr = E_FAIL;
766     if( FAILED( hr ) )
767     {
768         msg_Warn( p_access, "CreateTuneRequest: "\
769             "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
770         return hr;
771     }
772     return hr;
773 }
774
775 /******************************************************************************
776 * Build
777 * Step 4: Build the Filter Graph
778 * Build sets up devices, adds and connects filters
779 ******************************************************************************/
780 HRESULT BDAGraph::Build()
781 {
782     HRESULT hr = S_OK;
783     long l_capture_used, l_tif_used;
784     AM_MEDIA_TYPE grabber_media_type;
785
786     /* If we have already have a filter graph, rebuild it*/
787     Destroy();
788
789     hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
790         IID_IGraphBuilder, (void**)&p_filter_graph );
791     if( FAILED( hr ) )
792     {
793         msg_Warn( p_access, "Build: "\
794             "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
795         return hr;
796     }
797
798     /* First filter in the graph is the Network Provider and
799      * its Scanning Tuner which takes the Tune Request*/
800     hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
801         IID_IBaseFilter, (void**)&p_network_provider);
802     if( FAILED( hr ) )
803     {
804         msg_Warn( p_access, "Build: "\
805             "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
806         return hr;
807     }
808     hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
809     if( FAILED( hr ) )
810     {
811         msg_Warn( p_access, "Build: "\
812             "Cannot load network provider: hr=0x%8lx", hr );
813         return hr;
814     }
815
816     hr = p_network_provider->QueryInterface( IID_IScanningTuner,
817         (void**)&p_scanning_tuner );
818     if( FAILED( hr ) )
819     {
820         msg_Warn( p_access, "Build: "\
821             "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
822         return hr;
823     }
824
825     hr = p_scanning_tuner->Validate( p_tune_request );
826     if( FAILED( hr ) )
827     {
828         msg_Warn( p_access, "Build: "\
829             "Tune Request is invalid: hr=0x%8lx", hr );
830         return hr;
831     }
832     hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
833     if( FAILED( hr ) )
834     {
835         msg_Warn( p_access, "Build: "\
836             "Cannot submit the tune request: hr=0x%8lx", hr );
837         return hr;
838     }
839
840     /* Add the Network Tuner to the Network Provider. On subsequent calls,
841      * l_tuner_used will cause a different tuner to be selected */
842     hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
843         p_network_provider, &p_tuner_device );
844     if( FAILED( hr ) )
845     {
846         msg_Warn( p_access, "Build: "\
847             "Cannot load tuner device and connect network provider: "\
848             "hr=0x%8lx", hr );
849         return hr;
850     }
851
852     /* Always look for all capture devices to match the Network Tuner */
853     l_capture_used = -1;
854     hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
855         p_tuner_device, &p_capture_device );
856     if( FAILED( hr ) )
857     {
858         /* Some BDA drivers do not provide a Capture Device Filter so force
859          * the Sample Grabber to connect directly to the Tuner Device */
860         p_capture_device = p_tuner_device;
861         p_tuner_device = NULL;
862         msg_Warn( p_access, "Build: "\
863             "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
864     }
865
866     /* Insert the Sample Grabber to tap into the Transport Stream. */
867     hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
868         IID_IBaseFilter, (void**)&p_sample_grabber );
869     if( FAILED( hr ) )
870     {
871         msg_Warn( p_access, "Build: "\
872             "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
873         return hr;
874     }
875     hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
876     if( FAILED( hr ) )
877     {
878         msg_Warn( p_access, "Build: "\
879             "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
880         return hr;
881     }
882
883     hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
884         (void**)&p_grabber );
885     if( FAILED( hr ) )
886     {
887         msg_Warn( p_access, "Build: "\
888             "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
889         return hr;
890     }
891
892     ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
893     grabber_media_type.majortype == MEDIATYPE_Stream;
894     grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
895     hr = p_grabber->SetMediaType( &grabber_media_type );
896     if( FAILED( hr ) )
897     {
898         msg_Warn( p_access, "Build: "\
899             "Cannot set media type on grabber filter: hr=0x%8lx", hr );
900         return hr;
901     }
902     hr = Connect( p_capture_device, p_sample_grabber );
903     if( FAILED( hr ) )
904     {
905         msg_Warn( p_access, "Build: "\
906             "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
907         return hr;
908     }
909
910     /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
911      * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
912      * the Network Provider filter to set up the stream */
913     hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
914         CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
915     if( FAILED( hr ) )
916     {
917         msg_Warn( p_access, "Build: "\
918             "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
919         return hr;
920     }
921     hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
922     if( FAILED( hr ) )
923     {
924         msg_Warn( p_access, "Build: "\
925             "Cannot add demux filter to graph: hr=0x%8lx", hr );
926         return hr;
927     }
928
929     hr = Connect( p_sample_grabber, p_mpeg_demux );
930     if( FAILED( hr ) )
931     {
932         msg_Warn( p_access, "Build: "\
933             "Cannot connect demux to grabber: hr=0x%8lx", hr );
934         return hr;
935     }
936
937     /* Always look for the Transform Information Filter from the start
938      * of the collection*/
939     l_tif_used = -1;
940     hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
941         p_mpeg_demux, &p_transport_info );
942     if( FAILED( hr ) )
943     {
944         msg_Warn( p_access, "Build: "\
945             "Cannot load TIF onto demux: hr=0x%8lx", hr );
946         return hr;
947     }
948
949     /* Configure the Sample Grabber to buffer the samples continuously */
950     hr = p_grabber->SetBufferSamples( TRUE );
951     if( FAILED( hr ) )
952     {
953         msg_Warn( p_access, "Build: "\
954             "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
955         return hr;
956     }
957     hr = p_grabber->SetOneShot( FALSE );
958     if( FAILED( hr ) )
959     {
960         msg_Warn( p_access, "Build: "\
961             "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
962         return hr;
963     }
964     hr = p_grabber->SetCallback( this, 0 );
965     if( FAILED( hr ) )
966     {
967         msg_Warn( p_access, "Build: "\
968             "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
969         return hr;
970     }
971
972     hr = Register();
973     if( FAILED( hr ) )
974     {
975         d_graph_register = 0;
976     }
977
978     /* The Media Control is used to Run and Stop the Graph */
979     hr = p_filter_graph->QueryInterface( IID_IMediaControl,
980         (void**)&p_media_control );
981     if( FAILED( hr ) )
982     {
983         msg_Warn( p_access, "Build: "\
984             "Cannot QI Media Control: hr=0x%8lx", hr );
985         return hr;
986     }
987     return hr;
988 }
989
990 /******************************************************************************
991 * FindFilter
992 * Looks up all filters in a category and connects to the upstream filter until
993 * a successful match is found. The index of the connected filter is returned.
994 * On subsequent calls, this can be used to start from that point to find
995 * another match.
996 * This is used when the graph does not run because a tuner device is in use so
997 * another one needs to be slected.
998 ******************************************************************************/
999 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
1000     IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
1001 {
1002     HRESULT                 hr = S_OK;
1003     int                     i_moniker_index = -1;
1004     class localComPtr
1005     {
1006         public:
1007         IMoniker*      p_moniker;
1008         IEnumMoniker*  p_moniker_enum;
1009         IBaseFilter*   p_filter;
1010         IPropertyBag*  p_property_bag;
1011         VARIANT        var_bstr;
1012         localComPtr():
1013             p_moniker(NULL),
1014             p_moniker_enum(NULL),
1015             p_filter(NULL),
1016             p_property_bag(NULL)
1017             { ::VariantInit(&var_bstr); };
1018         ~localComPtr()
1019         {
1020             if( p_moniker )
1021                 p_moniker->Release();
1022             if( p_moniker_enum )
1023                 p_moniker_enum->Release();
1024             if( p_filter )
1025                 p_filter->Release();
1026             if( p_property_bag )
1027                 p_property_bag->Release();
1028             ::VariantClear(&var_bstr);
1029         }
1030     } l;
1031
1032     if( !p_system_dev_enum )
1033     {
1034         hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
1035             IID_ICreateDevEnum, (void**)&p_system_dev_enum );
1036         if( FAILED( hr ) )
1037         {
1038             msg_Warn( p_access, "FindFilter: "\
1039                 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
1040             return hr;
1041         }
1042     }
1043
1044     hr = p_system_dev_enum->CreateClassEnumerator( clsid,
1045         &l.p_moniker_enum, 0 );
1046     if( hr != S_OK )
1047     {
1048         msg_Warn( p_access, "FindFilter: "\
1049             "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
1050         return E_FAIL;
1051     }
1052     while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
1053     {
1054         i_moniker_index++;
1055
1056         /* Skip over devices already found on previous calls */
1057         if( i_moniker_index <= *i_moniker_used ) continue;
1058         *i_moniker_used = i_moniker_index;
1059
1060         hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
1061             (void**)&l.p_filter );
1062         if( FAILED( hr ) )
1063         {
1064             if( l.p_moniker )
1065                 l.p_moniker->Release();
1066             l.p_moniker = NULL;
1067             if( l.p_filter)
1068                  l.p_filter->Release();
1069             l.p_filter = NULL;
1070             continue;
1071         }
1072
1073         hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
1074             (void**)&l.p_property_bag );
1075         if( FAILED( hr ) )
1076         {
1077             msg_Warn( p_access, "FindFilter: "\
1078                 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
1079             return hr;
1080         }
1081
1082         hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
1083         if( FAILED( hr ) )
1084         {
1085             msg_Warn( p_access, "FindFilter: "\
1086                 "Cannot read filter friendly name: hr=0x%8lx", hr );
1087             return hr;
1088         }
1089
1090         hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
1091         if( FAILED( hr ) )
1092         {
1093             msg_Warn( p_access, "FindFilter: "\
1094                 "Cannot add filter: hr=0x%8lx", hr );
1095             return hr;
1096         }
1097
1098         hr = Connect( p_upstream, l.p_filter );
1099         if( SUCCEEDED( hr ) )
1100         {
1101             msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
1102             l.p_filter->QueryInterface( IID_IBaseFilter,
1103                 (void**)p_p_downstream );
1104             return S_OK;
1105         }
1106         /* Not the filter we want so unload and try the next one */
1107         hr = p_filter_graph->RemoveFilter( l.p_filter );
1108         if( FAILED( hr ) )
1109         {
1110             msg_Warn( p_access, "FindFilter: "\
1111                 "Failed unloading Filter: hr=0x%8lx", hr );
1112             return hr;
1113         }
1114
1115         if( l.p_moniker )
1116             l.p_moniker->Release();
1117         l.p_moniker = NULL;
1118         if( l.p_filter)
1119             l.p_filter->Release();
1120         l.p_filter = NULL;
1121     }
1122
1123     hr = E_FAIL;
1124     msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1125     return hr;
1126 }
1127
1128 /*****************************************************************************
1129 * Connect is called from Build to enumerate and connect pins
1130 *****************************************************************************/
1131 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1132 {
1133     HRESULT             hr = E_FAIL;
1134     class localComPtr
1135     {
1136         public:
1137         IPin*      p_pin_upstream;
1138         IPin*      p_pin_downstream;
1139         IEnumPins* p_pin_upstream_enum;
1140         IEnumPins* p_pin_downstream_enum;
1141         IPin*      p_pin_temp;
1142         localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1143             p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1144             p_pin_temp(NULL) { };
1145         ~localComPtr()
1146         {
1147             if( p_pin_upstream )
1148                 p_pin_upstream->Release();
1149             if( p_pin_downstream )
1150                 p_pin_downstream->Release();
1151             if( p_pin_upstream_enum )
1152                 p_pin_upstream_enum->Release();
1153             if( p_pin_downstream_enum )
1154                 p_pin_downstream_enum->Release();
1155             if( p_pin_temp )
1156                 p_pin_temp->Release();
1157         }
1158     } l;
1159
1160     PIN_INFO            pin_info_upstream;
1161     PIN_INFO            pin_info_downstream;
1162
1163     hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1164     if( FAILED( hr ) )
1165     {
1166         msg_Warn( p_access, "Connect: "\
1167             "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1168         return hr;
1169     }
1170     while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
1171     {
1172         hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
1173         if( FAILED( hr ) )
1174         {
1175             msg_Warn( p_access, "Connect: "\
1176                 "Cannot get upstream filter pin information: hr=0x%8lx", hr );
1177             return hr;
1178         }
1179         hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1180         if( hr == S_OK )
1181             l.p_pin_downstream->Release();
1182         if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1183         {
1184             msg_Warn( p_access, "Connect: "\
1185                 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1186             return hr;
1187         }
1188         if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
1189            ( hr == VFW_E_NOT_CONNECTED ) )
1190         {
1191             /* The upstream pin is not yet connected so check each pin on the
1192              * downstream filter */
1193             hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1194             if( FAILED( hr ) )
1195             {
1196                 msg_Warn( p_access, "Connect: Cannot get "\
1197                     "downstream filter enumerator: hr=0x%8lx", hr );
1198                 return hr;
1199             }
1200             while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
1201                 == S_OK )
1202             {
1203                 hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
1204                 if( FAILED( hr ) )
1205                 {
1206                     msg_Warn( p_access, "Connect: Cannot get "\
1207                         "downstream filter pin information: hr=0x%8lx", hr );
1208                     return hr;
1209                 }
1210
1211                 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1212                 if( hr == S_OK ) l.p_pin_temp->Release();
1213                 if( hr != VFW_E_NOT_CONNECTED )
1214                 {
1215                     if( FAILED( hr ) )
1216                     {
1217                         msg_Warn( p_access, "Connect: Cannot check "\
1218                             "downstream filter connection: hr=0x%8lx", hr );
1219                         return hr;
1220                     }
1221                 }
1222                 if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
1223                    ( hr == VFW_E_NOT_CONNECTED ) )
1224                 {
1225                     hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1226                         l.p_pin_downstream, NULL );
1227                     if( SUCCEEDED( hr ) )
1228                     {
1229                         pin_info_downstream.pFilter->Release();
1230                         pin_info_upstream.pFilter->Release();
1231                         return S_OK;
1232                     }
1233                 }
1234                 /* If we fall out here it means this downstream pin was not
1235                  * suitable so try the next downstream pin */
1236                 l.p_pin_downstream = NULL;
1237                 pin_info_downstream.pFilter->Release();
1238             }
1239         }
1240
1241         /* If we fall out here it means we did not find any suitable downstream
1242          * pin so try the next upstream pin */
1243         l.p_pin_upstream = NULL;
1244         pin_info_upstream.pFilter->Release();
1245     }
1246
1247     /* If we fall out here it means we did not find any pair of suitable pins */
1248     return E_FAIL;
1249 }
1250
1251 /*****************************************************************************
1252 * Start uses MediaControl to start the graph
1253 *****************************************************************************/
1254 HRESULT BDAGraph::Start()
1255 {
1256     HRESULT hr = S_OK;
1257     OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1258
1259     if( !p_media_control )
1260     {
1261         msg_Dbg( p_access, "Start: Media Control has not been created" );
1262         return E_FAIL;
1263     }
1264     hr = p_media_control->Run();
1265     if( hr == S_OK )
1266         return hr;
1267
1268     /* Query the state of the graph - timeout after 100 milliseconds */
1269     while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1270     {
1271         if( FAILED( hr ) )
1272         {
1273             msg_Warn( p_access,
1274                 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1275             return hr;
1276         }
1277     }
1278     if( i_state == State_Running )
1279         return hr;
1280
1281     /* The Graph is not running so stop it and return an error */
1282     msg_Warn( p_access, "Start: Graph not started: %d", i_state );
1283     hr = p_media_control->Stop();
1284     if( FAILED( hr ) )
1285     {
1286         msg_Warn( p_access,
1287             "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1288         return hr;
1289     }
1290     return E_FAIL;
1291 }
1292
1293 /*****************************************************************************
1294 * Read the stream of data - query the buffer size required
1295 *****************************************************************************/
1296 long BDAGraph::GetBufferSize()
1297 {
1298     long l_buffer_size = 0;
1299     long l_queue_size;
1300
1301     b_ready = true;
1302
1303     for( int i_timer = 0; queue_sample.empty() && i_timer < 200; i_timer++ )
1304         Sleep( 10 );
1305
1306     l_queue_size = queue_sample.size();
1307     if( l_queue_size <= 0 )
1308     {
1309         msg_Warn( p_access, "BDA GetBufferSize: Timed Out waiting for sample" );
1310         return -1;
1311     }
1312
1313     /* Establish the length of the queue as it grows quickly. If the queue
1314      * size is checked dynamically there is a risk of not exiting the loop */
1315     for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1316     {
1317         l_buffer_size += queue_sample.front()->GetActualDataLength();
1318         queue_buffer.push( queue_sample.front() );
1319         queue_sample.pop();
1320     }
1321     return l_buffer_size;
1322 }
1323
1324 /*****************************************************************************
1325 * Read the stream of data - Retrieve from the buffer queue
1326 ******************************************************************************/
1327 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1328 {
1329     HRESULT hr = S_OK;
1330
1331     *pl_buffer_len = 0;
1332     BYTE *p_buff_temp;
1333
1334     while( !queue_buffer.empty() )
1335     {
1336         queue_buffer.front()->GetPointer( &p_buff_temp );
1337         hr = queue_buffer.front()->IsDiscontinuity();
1338         if( hr == S_OK )
1339             msg_Warn( p_access,
1340                 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1341         memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1342             queue_buffer.front()->GetActualDataLength() );
1343         *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1344         queue_buffer.front()->Release();
1345         queue_buffer.pop();
1346     }
1347
1348     return *pl_buffer_len;
1349 }
1350
1351 /******************************************************************************
1352 * SampleCB - Callback when the Sample Grabber has a sample
1353 ******************************************************************************/
1354 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1355 {
1356     if( b_ready )
1357     {
1358         p_sample->AddRef();
1359         queue_sample.push( p_sample );
1360     }
1361     else
1362     {
1363         msg_Warn( p_access, "BDA SampleCB: Not ready - dropped sample" );
1364     }
1365     return S_OK;
1366 }
1367
1368 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1369     long l_buffer_len )
1370 {
1371     return E_FAIL;
1372 }
1373
1374 /******************************************************************************
1375 * removes each filter from the graph
1376 ******************************************************************************/
1377 HRESULT BDAGraph::Destroy()
1378 {
1379     HRESULT hr = S_OK;
1380
1381     if( p_media_control )
1382         hr = p_media_control->Stop();
1383
1384     if( p_transport_info )
1385     {
1386         p_filter_graph->RemoveFilter( p_transport_info );
1387         p_transport_info->Release();
1388         p_transport_info = NULL;
1389     }
1390     if( p_mpeg_demux )
1391     {
1392         p_filter_graph->RemoveFilter( p_mpeg_demux );
1393         p_mpeg_demux->Release();
1394         p_mpeg_demux = NULL;
1395     }
1396     if( p_sample_grabber )
1397     {
1398         p_filter_graph->RemoveFilter( p_sample_grabber );
1399         p_sample_grabber->Release();
1400         p_sample_grabber = NULL;
1401     }
1402     if( p_capture_device )
1403     {
1404         p_filter_graph->RemoveFilter( p_capture_device );
1405         p_capture_device->Release();
1406         p_capture_device = NULL;
1407     }
1408     if( p_tuner_device )
1409     {
1410         p_filter_graph->RemoveFilter( p_tuner_device );
1411         p_tuner_device->Release();
1412         p_tuner_device = NULL;
1413     }
1414     if( p_network_provider )
1415     {
1416         p_filter_graph->RemoveFilter( p_network_provider );
1417         p_network_provider->Release();
1418         p_network_provider = NULL;
1419     }
1420
1421     if( p_scanning_tuner )
1422     {
1423         p_scanning_tuner->Release();
1424         p_scanning_tuner = NULL;
1425     }
1426     if( p_media_control )
1427     {
1428         p_media_control->Release();
1429         p_media_control = NULL;
1430     }
1431     if( p_filter_graph )
1432     {
1433         p_filter_graph->Release();
1434         p_filter_graph = NULL;
1435     }
1436
1437     if( d_graph_register )
1438     {
1439         Deregister();
1440     }
1441
1442     return S_OK;
1443 }
1444
1445 /*****************************************************************************
1446 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1447 * Allows GraphEdit to "spy" on a remote filter graph.
1448 ******************************************************************************/
1449 HRESULT BDAGraph::Register()
1450 {
1451     class localComPtr
1452     {
1453         public:
1454         IMoniker*             p_moniker;
1455         IRunningObjectTable*  p_ro_table;
1456         localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1457         ~localComPtr()
1458         {
1459             if( p_moniker )
1460                 p_moniker->Release();
1461             if( p_ro_table )
1462                 p_ro_table->Release();
1463         }
1464     } l;
1465     WCHAR     psz_w_graph_name[128];
1466     HRESULT   hr;
1467
1468     hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1469     if( FAILED( hr ) )
1470     {
1471         msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1472         return hr;
1473     }
1474
1475     wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1476         (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1477     hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1478     if( FAILED( hr ) )
1479     {
1480         msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1481         return hr;
1482     }
1483     hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1484         p_filter_graph, l.p_moniker, &d_graph_register );
1485     if( FAILED( hr ) )
1486     {
1487         msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1488         return hr;
1489     }
1490     msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1491     return hr;
1492 }
1493
1494 void BDAGraph::Deregister()
1495 {
1496     HRESULT   hr;
1497     IRunningObjectTable* p_ro_table;
1498     hr = ::GetRunningObjectTable( 0, &p_ro_table );
1499     if( SUCCEEDED( hr ) )
1500         p_ro_table->Revoke( d_graph_register );
1501     d_graph_register = 0;
1502     p_ro_table->Release();
1503 }