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