1 /*****************************************************************************
2 * bdagraph.cpp : DirectShow BDA graph for vlc
3 *****************************************************************************
4 * Copyright( C ) 2007 the VideoLAN team
6 * Author: Ken Self <kens@campoz.fslife.co.uk>
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.
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.
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 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
28 /****************************************************************************
29 * Interfaces for calls from C
30 ****************************************************************************/
33 void dvb_newBDAGraph( access_t* p_access )
35 p_access->p_sys->p_bda_module = new BDAGraph( p_access );
38 void dvb_deleteBDAGraph( access_t* p_access )
40 delete p_access->p_sys->p_bda_module;
43 int dvb_SubmitATSCTuneRequest( access_t* p_access )
45 return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
48 int dvb_SubmitDVBTTuneRequest( access_t* p_access )
50 return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
53 int dvb_SubmitDVBCTuneRequest( access_t* p_access )
55 return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
58 int dvb_SubmitDVBSTuneRequest( access_t* p_access )
60 return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
63 long dvb_GetBufferSize( access_t* p_access )
65 return p_access->p_sys->p_bda_module->GetBufferSize();
68 long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
70 return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
75 /*****************************************************************************
77 *****************************************************************************/
78 BDAGraph::BDAGraph( access_t* p_this ):
80 guid_network_type(GUID_NULL),
85 p_tuning_space = NULL;
86 p_tune_request = NULL;
87 p_media_control = NULL;
88 p_filter_graph = NULL;
89 p_system_dev_enum = NULL;
90 p_network_provider = p_tuner_device = p_capture_device = NULL;
91 p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
92 p_scanning_tuner = NULL;
95 /* Initialize COM - MS says to use CoInitializeEx in preference to
97 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
100 /*****************************************************************************
102 *****************************************************************************/
103 BDAGraph::~BDAGraph()
109 /*****************************************************************************
110 * Submit an ATSC Tune Request
111 *****************************************************************************/
112 int BDAGraph::SubmitATSCTuneRequest()
118 IATSCChannelTuneRequest* p_atsc_tune_request;
119 IATSCLocator* p_atsc_locator;
120 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
123 if( p_atsc_tune_request )
124 p_atsc_tune_request->Release();
126 p_atsc_locator->Release();
129 long l_major_channel, l_minor_channel, l_physical_channel;
131 l_major_channel = l_minor_channel = l_physical_channel = -1;
133 l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
134 l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
135 l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
138 guid_network_type = CLSID_ATSCNetworkProvider;
139 hr = CreateTuneRequest();
142 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
143 "Cannot create Tuning Space: hr=0x%8lx", hr );
147 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
148 (void**)&l.p_atsc_tune_request );
151 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
152 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
155 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
156 IID_IATSCLocator, (void**)&l.p_atsc_locator );
159 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
160 "Cannot create the ATSC locator: hr=0x%8lx", hr );
165 if( l_major_channel > 0 )
166 hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
167 if( SUCCEEDED( hr ) && l_minor_channel > 0 )
168 hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
169 if( SUCCEEDED( hr ) && l_physical_channel > 0 )
170 hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
173 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
174 "Cannot set tuning parameters: hr=0x%8lx", hr );
178 hr = p_tune_request->put_Locator( l.p_atsc_locator );
181 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
182 "Cannot put the locator: hr=0x%8lx", hr );
186 /* Build and Run the Graph. If a Tuner device is in use the graph will
187 * fail to run. Repeated calls to build will check successive tuner
194 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
195 "Cannot Build the Graph: hr=0x%8lx", hr );
205 /*****************************************************************************
206 * Submit a DVB-T Tune Request
207 ******************************************************************************/
208 int BDAGraph::SubmitDVBTTuneRequest()
214 IDVBTuneRequest* p_dvbt_tune_request;
215 IDVBTLocator* p_dvbt_locator;
216 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
219 if( p_dvbt_tune_request )
220 p_dvbt_tune_request->Release();
222 p_dvbt_locator->Release();
225 long l_frequency, l_bandwidth;
227 l_frequency = l_bandwidth = -1;
228 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
229 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
231 guid_network_type = CLSID_DVBTNetworkProvider;
232 hr = CreateTuneRequest();
235 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
236 "Cannot create Tune Request: hr=0x%8lx", hr );
240 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
241 (void**)&l.p_dvbt_tune_request );
244 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
245 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
248 l.p_dvbt_tune_request->put_ONID( -1 );
249 l.p_dvbt_tune_request->put_SID( -1 );
250 l.p_dvbt_tune_request->put_TSID( -1 );
252 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
253 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
256 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
257 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
262 if( l_frequency > 0 )
263 hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
264 if( SUCCEEDED( hr ) && l_bandwidth > 0 )
265 hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
268 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
269 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
273 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
276 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
277 "Cannot put the locator: hr=0x%8lx", hr );
281 /* Build and Run the Graph. If a Tuner device is in use the graph will
282 * fail to run. Repeated calls to build will check successive tuner
289 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
290 "Cannot Build the Graph: hr=0x%8lx", hr );
300 /*****************************************************************************
301 * Submit a DVB-C Tune Request
302 ******************************************************************************/
303 int BDAGraph::SubmitDVBCTuneRequest()
310 IDVBTuneRequest* p_dvbc_tune_request;
311 IDVBCLocator* p_dvbc_locator;
312 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
315 if( p_dvbc_tune_request )
316 p_dvbc_tune_request->Release();
318 p_dvbc_locator->Release();
322 long l_frequency, l_symbolrate;
324 ModulationType i_qam_mod;
326 l_frequency = l_symbolrate = i_qam = -1;
327 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
328 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
329 i_qam = var_GetInteger( p_access, "dvb-modulation" );
330 i_qam_mod = BDA_MOD_NOT_SET;
332 i_qam_mod = BDA_MOD_16QAM;
334 i_qam_mod = BDA_MOD_32QAM;
336 i_qam_mod = BDA_MOD_64QAM;
338 i_qam_mod = BDA_MOD_128QAM;
340 i_qam_mod = BDA_MOD_256QAM;
342 guid_network_type = CLSID_DVBCNetworkProvider;
343 hr = CreateTuneRequest();
346 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
347 "Cannot create Tune Request: hr=0x%8lx", hr );
351 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
352 (void**)&l.p_dvbc_tune_request );
355 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
356 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
359 l.p_dvbc_tune_request->put_ONID( -1 );
360 l.p_dvbc_tune_request->put_SID( -1 );
361 l.p_dvbc_tune_request->put_TSID( -1 );
363 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
364 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
367 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
368 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
373 if( l_frequency > 0 )
374 hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
375 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
376 hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
377 if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
378 hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
381 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
382 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
386 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
389 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
390 "Cannot put the locator: hr=0x%8lx", hr );
394 /* Build and Run the Graph. If a Tuner device is in use the graph will
395 * fail to run. Repeated calls to build will check successive tuner
402 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
403 "Cannot Build the Graph: hr=0x%8lx", hr );
413 /*****************************************************************************
414 * Submit a DVB-S Tune Request
415 ******************************************************************************/
416 int BDAGraph::SubmitDVBSTuneRequest()
423 IDVBTuneRequest* p_dvbs_tune_request;
424 IDVBSLocator* p_dvbs_locator;
425 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL) {};
428 if( p_dvbs_tune_request )
429 p_dvbs_tune_request->Release();
431 p_dvbs_locator->Release();
434 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
435 char* psz_polarisation;
436 Polarisation i_polar;
439 l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
440 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
441 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
442 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
443 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
444 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
445 psz_polarisation = var_GetString( p_access, "dvb-polarisation" );
447 b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
449 i_polar = BDA_POLARISATION_NOT_SET;
450 if( *psz_polarisation == 'H' || *psz_polarisation == 'h' )
451 i_polar = BDA_POLARISATION_LINEAR_H;
452 if( *psz_polarisation == 'V' || *psz_polarisation == 'v' )
453 i_polar = BDA_POLARISATION_LINEAR_V;
454 if( *psz_polarisation == 'L' || *psz_polarisation == 'l' )
455 i_polar = BDA_POLARISATION_CIRCULAR_L;
456 if( *psz_polarisation == 'R' || *psz_polarisation == 'r' )
457 i_polar = BDA_POLARISATION_CIRCULAR_R;
459 guid_network_type = CLSID_DVBSNetworkProvider;
460 hr = CreateTuneRequest();
463 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
464 "Cannot create Tune Request: hr=0x%8lx", hr );
468 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
469 (void**)&l.p_dvbs_tune_request );
472 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
473 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
476 l.p_dvbs_tune_request->put_ONID( -1 );
477 l.p_dvbs_tune_request->put_SID( -1 );
478 l.p_dvbs_tune_request->put_TSID( -1 );
480 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
481 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
484 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
485 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
490 if( l_frequency > 0 )
491 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
492 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
493 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
494 if( SUCCEEDED( hr ) && l_azimuth > 0 )
495 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
496 if( SUCCEEDED( hr ) && l_elevation > 0 )
497 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
498 if( SUCCEEDED( hr ) )
499 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
500 if( SUCCEEDED( hr ) )
501 hr = l.p_dvbs_locator->put_WestPosition( b_west );
502 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
503 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
506 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
507 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
511 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
514 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
515 "Cannot put the locator: hr=0x%8lx", hr );
519 /* Build and Run the Graph. If a Tuner device is in use the graph will
520 * fail to run. Repeated calls to build will check successive tuner
527 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
528 "Cannot Build the Graph: hr=0x%8lx", hr );
538 /*****************************************************************************
539 * Load the Tuning Space from System Tuning Spaces according to the
540 * Network Type requested
541 ******************************************************************************/
542 HRESULT BDAGraph::CreateTuneRequest()
545 GUID guid_this_network_type;
549 ITuningSpaceContainer* p_tuning_space_container;
550 IEnumTuningSpaces* p_tuning_space_enum;
551 ITuningSpace* p_this_tuning_space;
552 localComPtr(): p_tuning_space_container(NULL),
553 p_tuning_space_enum(NULL), p_this_tuning_space(NULL) {};
556 if( p_tuning_space_container )
557 p_tuning_space_container->Release();
558 if( p_tuning_space_enum )
559 p_tuning_space_enum->Release();
560 if( p_this_tuning_space )
561 p_this_tuning_space->Release();
565 /* A Tuning Space may already have been set up. If it is for the same
566 * network type then all is well. Otherwise, reset the Tuning Space and get
570 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
571 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
572 if( guid_this_network_type == guid_network_type )
578 p_tuning_space->Release();
579 p_tuning_space = NULL;
583 /* Force use of the first available Tuner Device during Build */
586 /* Get the SystemTuningSpaces container to enumerate through all the
587 * defined tuning spaces */
588 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
589 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
592 msg_Warn( p_access, "CreateTuneRequest: "\
593 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
597 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
598 &l.p_tuning_space_enum );
601 msg_Warn( p_access, "CreateTuneRequest: "\
602 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
606 while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
609 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
611 /* GUID_NULL means a non-BDA network was found e.g analog
612 * Ignore failures and non-BDA networks and keep looking */
613 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
615 if( guid_this_network_type == guid_network_type )
617 hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
618 (void**)&p_tuning_space );
621 msg_Warn( p_access, "CreateTuneRequest: "\
622 "Cannot QI Tuning Space: hr=0x%8lx", hr );
625 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
628 msg_Warn( p_access, "CreateTuneRequest: "\
629 "Cannot Create Tune Request: hr=0x%8lx", hr );
638 msg_Warn( p_access, "CreateTuneRequest: "\
639 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
645 /******************************************************************************
647 * Step 4: Build the Filter Graph
648 * Build sets up devices, adds and connects filters
649 ******************************************************************************/
650 HRESULT BDAGraph::Build()
653 long l_capture_used, l_tif_used;
654 AM_MEDIA_TYPE grabber_media_type;
656 /* If we have already have a filter graph, rebuild it*/
659 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
660 IID_IGraphBuilder, (void**)&p_filter_graph );
663 msg_Warn( p_access, "Build: "\
664 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
668 /* First filter in the graph is the Network Provider and
669 * its Scanning Tuner which takes the Tune Request*/
670 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
671 IID_IBaseFilter, (void**)&p_network_provider);
674 msg_Warn( p_access, "Build: "\
675 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
678 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
681 msg_Warn( p_access, "Build: "\
682 "Cannot load network provider: hr=0x%8lx", hr );
686 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
687 (void**)&p_scanning_tuner );
690 msg_Warn( p_access, "Build: "\
691 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
695 hr = p_scanning_tuner->Validate( p_tune_request );
698 msg_Warn( p_access, "Build: "\
699 "Tune Request is invalid: hr=0x%8lx", hr );
702 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
705 msg_Warn( p_access, "Build: "\
706 "Cannot submit the tune request: hr=0x%8lx", hr );
710 /* Add the Network Tuner to the Network Provider. On subsequent calls,
711 * l_tuner_used will cause a different tuner to be selected */
712 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
713 p_network_provider, &p_tuner_device );
716 msg_Warn( p_access, "Build: "\
717 "Cannot load tuner device and connect network provider: "\
722 /* Always look for all capture devices to match the Network Tuner */
724 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
725 p_tuner_device, &p_capture_device );
728 /* Some BDA drivers do not provide a Capture Device Filter so force
729 * the Sample Grabber to connect directly to the Tuner Device */
730 p_capture_device = p_tuner_device;
731 p_tuner_device = NULL;
732 msg_Warn( p_access, "Build: "\
733 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
736 /* Insert the Sample Grabber to tap into the Transport Stream. */
737 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
738 IID_IBaseFilter, (void**)&p_sample_grabber );
741 msg_Warn( p_access, "Build: "\
742 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
745 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
748 msg_Warn( p_access, "Build: "\
749 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
753 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
754 (void**)&p_grabber );
757 msg_Warn( p_access, "Build: "\
758 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
762 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
763 grabber_media_type.majortype == MEDIATYPE_Stream;
764 grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
765 hr = p_grabber->SetMediaType( &grabber_media_type );
768 msg_Warn( p_access, "Build: "\
769 "Cannot set media type on grabber filter: hr=0x%8lx", hr );
772 hr = Connect( p_capture_device, p_sample_grabber );
775 msg_Warn( p_access, "Build: "\
776 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
780 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
781 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
782 * the Network Provider filter to set up the stream */
783 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
784 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
787 msg_Warn( p_access, "Build: "\
788 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
791 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
794 msg_Warn( p_access, "Build: "\
795 "Cannot add demux filter to graph: hr=0x%8lx", hr );
799 hr = Connect( p_sample_grabber, p_mpeg_demux );
802 msg_Warn( p_access, "Build: "\
803 "Cannot connect demux to grabber: hr=0x%8lx", hr );
807 /* Always look for the Transform Information Filter from the start
808 * of the collection*/
810 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
811 p_mpeg_demux, &p_transport_info );
814 msg_Warn( p_access, "Build: "\
815 "Cannot load TIF onto demux: hr=0x%8lx", hr );
819 /* Configure the Sample Grabber to buffer the samples continuously */
820 hr = p_grabber->SetBufferSamples( TRUE );
823 msg_Warn( p_access, "Build: "\
824 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
827 hr = p_grabber->SetOneShot( FALSE );
830 msg_Warn( p_access, "Build: "\
831 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
834 hr = p_grabber->SetCallback( this, 0 );
837 msg_Warn( p_access, "Build: "\
838 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
845 d_graph_register = 0;
848 /* The Media Control is used to Run and Stop the Graph */
849 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
850 (void**)&p_media_control );
853 msg_Warn( p_access, "Build: "\
854 "Cannot QI Media Control: hr=0x%8lx", hr );
860 /******************************************************************************
862 * Looks up all filters in a category and connects to the upstream filter until
863 * a successful match is found. The index of the connected filter is returned.
864 * On subsequent calls, this can be used to start from that point to find
866 * This is used when the graph does not run because a tuner device is in use so
867 * another one needs to be slected.
868 ******************************************************************************/
869 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
870 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
873 int i_moniker_index = -1;
878 IEnumMoniker* p_moniker_enum;
879 IBaseFilter* p_filter;
880 IPropertyBag* p_property_bag;
884 p_moniker_enum(NULL),
887 { ::VariantInit(&var_bstr); };
891 p_moniker->Release();
893 p_moniker_enum->Release();
897 p_property_bag->Release();
898 ::VariantClear(&var_bstr);
902 if( !p_system_dev_enum )
904 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
905 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
908 msg_Warn( p_access, "FindFilter: "\
909 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
914 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
915 &l.p_moniker_enum, 0 );
918 msg_Warn( p_access, "FindFilter: "\
919 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
922 while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
926 /* Skip over devices already found on previous calls */
927 if( i_moniker_index <= *i_moniker_used ) continue;
928 *i_moniker_used = i_moniker_index;
930 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
931 (void**)&l.p_filter );
935 l.p_moniker->Release();
938 l.p_filter->Release();
943 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
944 (void**)&l.p_property_bag );
947 msg_Warn( p_access, "FindFilter: "\
948 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
952 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
955 msg_Warn( p_access, "FindFilter: "\
956 "Cannot read filter friendly name: hr=0x%8lx", hr );
960 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
963 msg_Warn( p_access, "FindFilter: "\
964 "Cannot add filter: hr=0x%8lx", hr );
968 hr = Connect( p_upstream, l.p_filter );
969 if( SUCCEEDED( hr ) )
971 msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
972 l.p_filter->QueryInterface( IID_IBaseFilter,
973 (void**)p_p_downstream );
976 /* Not the filter we want so unload and try the next one */
977 hr = p_filter_graph->RemoveFilter( l.p_filter );
980 msg_Warn( p_access, "FindFilter: "\
981 "Failed unloading Filter: hr=0x%8lx", hr );
986 l.p_moniker->Release();
989 l.p_filter->Release();
994 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
998 /*****************************************************************************
999 * Connect is called from Build to enumerate and connect pins
1000 *****************************************************************************/
1001 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1003 HRESULT hr = E_FAIL;
1007 IPin* p_pin_upstream;
1008 IPin* p_pin_downstream;
1009 IEnumPins* p_pin_upstream_enum;
1010 IEnumPins* p_pin_downstream_enum;
1012 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1013 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1014 p_pin_temp(NULL) { };
1017 if( p_pin_upstream )
1018 p_pin_upstream->Release();
1019 if( p_pin_downstream )
1020 p_pin_downstream->Release();
1021 if( p_pin_upstream_enum )
1022 p_pin_upstream_enum->Release();
1023 if( p_pin_downstream_enum )
1024 p_pin_downstream_enum->Release();
1026 p_pin_temp->Release();
1030 PIN_INFO pin_info_upstream;
1031 PIN_INFO pin_info_downstream;
1033 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1036 msg_Warn( p_access, "Connect: "\
1037 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1040 while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
1042 hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
1045 msg_Warn( p_access, "Connect: "\
1046 "Cannot get upstream filter pin information: hr=0x%8lx", hr );
1049 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1051 l.p_pin_downstream->Release();
1052 if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1054 msg_Warn( p_access, "Connect: "\
1055 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1058 if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
1059 ( hr == VFW_E_NOT_CONNECTED ) )
1061 /* The upstream pin is not yet connected so check each pin on the
1062 * downstream filter */
1063 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1066 msg_Warn( p_access, "Connect: Cannot get "\
1067 "downstream filter enumerator: hr=0x%8lx", hr );
1070 while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
1073 hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
1076 msg_Warn( p_access, "Connect: Cannot get "\
1077 "downstream filter pin information: hr=0x%8lx", hr );
1081 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1082 if( hr == S_OK ) l.p_pin_temp->Release();
1083 if( hr != VFW_E_NOT_CONNECTED )
1087 msg_Warn( p_access, "Connect: Cannot check "\
1088 "downstream filter connection: hr=0x%8lx", hr );
1092 if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
1093 ( hr == VFW_E_NOT_CONNECTED ) )
1095 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1096 l.p_pin_downstream, NULL );
1097 if( SUCCEEDED( hr ) )
1099 pin_info_downstream.pFilter->Release();
1100 pin_info_upstream.pFilter->Release();
1104 /* If we fall out here it means this downstream pin was not
1105 * suitable so try the next downstream pin */
1106 l.p_pin_downstream = NULL;
1107 pin_info_downstream.pFilter->Release();
1111 /* If we fall out here it means we did not find any suitable downstream
1112 * pin so try the next upstream pin */
1113 l.p_pin_upstream = NULL;
1114 pin_info_upstream.pFilter->Release();
1117 /* If we fall out here it means we did not find any pair of suitable pins */
1121 /*****************************************************************************
1122 * Start uses MediaControl to start the graph
1123 *****************************************************************************/
1124 HRESULT BDAGraph::Start()
1127 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1129 if( !p_media_control )
1131 msg_Dbg( p_access, "Start: Media Control has not been created" );
1134 hr = p_media_control->Run();
1138 /* Query the state of the graph - timeout after 100 milliseconds */
1139 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1144 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1148 if( i_state == State_Running )
1151 /* The Graph is not running so stop it and return an error */
1152 hr = p_media_control->Stop();
1156 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1162 /*****************************************************************************
1163 * Read the stream of data - query the buffer size required
1164 *****************************************************************************/
1165 long BDAGraph::GetBufferSize()
1167 long l_buffer_size = 0;
1172 for( int i_timer = 0; queue_sample.empty() && i_timer < 200; i_timer++ )
1175 l_queue_size = queue_sample.size();
1176 if( l_queue_size <= 0 )
1178 msg_Warn( p_access, "BDA GetBufferSize: Timed Out waiting for sample" );
1182 /* Establish the length of the queue as it grows quickly. If the queue
1183 * size is checked dynamically there is a risk of not exiting the loop */
1184 for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1186 l_buffer_size += queue_sample.front()->GetActualDataLength();
1187 queue_buffer.push( queue_sample.front() );
1190 return l_buffer_size;
1193 /*****************************************************************************
1194 * Read the stream of data - Retrieve from the buffer queue
1195 ******************************************************************************/
1196 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1203 while( !queue_buffer.empty() )
1205 queue_buffer.front()->GetPointer( &p_buff_temp );
1206 hr = queue_buffer.front()->IsDiscontinuity();
1209 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1210 memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1211 queue_buffer.front()->GetActualDataLength() );
1212 *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1213 queue_buffer.front()->Release();
1217 return *pl_buffer_len;
1220 /******************************************************************************
1221 * SampleCB - Callback when the Sample Grabber has a sample
1222 ******************************************************************************/
1223 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1228 queue_sample.push( p_sample );
1232 msg_Warn( p_access, "BDA SampleCB: Not ready - dropped sample" );
1237 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1243 /******************************************************************************
1244 * removes each filter from the graph
1245 ******************************************************************************/
1246 HRESULT BDAGraph::Destroy()
1250 if( p_media_control )
1251 hr = p_media_control->Stop();
1253 if( p_transport_info )
1255 p_filter_graph->RemoveFilter( p_transport_info );
1256 p_transport_info->Release();
1257 p_transport_info = NULL;
1261 p_filter_graph->RemoveFilter( p_mpeg_demux );
1262 p_mpeg_demux->Release();
1263 p_mpeg_demux = NULL;
1265 if( p_sample_grabber )
1267 p_filter_graph->RemoveFilter( p_sample_grabber );
1268 p_sample_grabber->Release();
1269 p_sample_grabber = NULL;
1271 if( p_capture_device )
1273 p_filter_graph->RemoveFilter( p_capture_device );
1274 p_capture_device->Release();
1275 p_capture_device = NULL;
1277 if( p_tuner_device )
1279 p_filter_graph->RemoveFilter( p_tuner_device );
1280 p_tuner_device->Release();
1281 p_tuner_device = NULL;
1283 if( p_network_provider )
1285 p_filter_graph->RemoveFilter( p_network_provider );
1286 p_network_provider->Release();
1287 p_network_provider = NULL;
1290 if( p_scanning_tuner )
1292 p_scanning_tuner->Release();
1293 p_scanning_tuner = NULL;
1295 if( p_media_control )
1297 p_media_control->Release();
1298 p_media_control = NULL;
1300 if( p_scanning_tuner )
1302 p_filter_graph->Release();
1303 p_filter_graph = NULL;
1306 if( d_graph_register )
1314 /*****************************************************************************
1315 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1316 * Allows GraphEdit to "spy" on a remote filter graph.
1317 ******************************************************************************/
1318 HRESULT BDAGraph::Register()
1323 IMoniker* p_moniker;
1324 IRunningObjectTable* p_ro_table;
1325 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1329 p_moniker->Release();
1331 p_ro_table->Release();
1334 WCHAR psz_w_graph_name[128];
1337 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1340 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1344 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1345 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1346 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1349 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1352 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1353 p_filter_graph, l.p_moniker, &d_graph_register );
1356 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1359 msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1363 void BDAGraph::Deregister()
1366 IRunningObjectTable* p_ro_table;
1367 hr = ::GetRunningObjectTable( 0, &p_ro_table );
1368 if( SUCCEEDED( hr ) )
1369 p_ro_table->Revoke( d_graph_register );
1370 d_graph_register = 0;
1371 p_ro_table->Release();