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 if( p_access->p_sys->p_bda_module )
41 delete p_access->p_sys->p_bda_module;
44 int dvb_SubmitATSCTuneRequest( access_t* p_access )
46 if( p_access->p_sys->p_bda_module )
47 return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
51 int dvb_SubmitDVBTTuneRequest( access_t* p_access )
53 if( p_access->p_sys->p_bda_module )
54 return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
58 int dvb_SubmitDVBCTuneRequest( access_t* p_access )
60 if( p_access->p_sys->p_bda_module )
61 return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
65 int dvb_SubmitDVBSTuneRequest( access_t* p_access )
67 if( p_access->p_sys->p_bda_module )
68 return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
72 long dvb_GetBufferSize( access_t* p_access )
74 if( p_access->p_sys->p_bda_module )
75 return p_access->p_sys->p_bda_module->GetBufferSize();
79 long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
81 if( p_access->p_sys->p_bda_module )
82 return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
88 /*****************************************************************************
90 *****************************************************************************/
91 BDAGraph::BDAGraph( access_t* p_this ):
93 guid_network_type(GUID_NULL),
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;
108 /* Initialize COM - MS says to use CoInitializeEx in preference to
110 CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
113 /*****************************************************************************
115 *****************************************************************************/
116 BDAGraph::~BDAGraph()
122 /*****************************************************************************
123 * Submit an ATSC Tune Request
124 *****************************************************************************/
125 int BDAGraph::SubmitATSCTuneRequest()
131 IATSCChannelTuneRequest* p_atsc_tune_request;
132 IATSCLocator* p_atsc_locator;
133 localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
136 if( p_atsc_tune_request )
137 p_atsc_tune_request->Release();
139 p_atsc_locator->Release();
142 long l_major_channel, l_minor_channel, l_physical_channel;
144 l_major_channel = l_minor_channel = l_physical_channel = -1;
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" );
151 guid_network_type = CLSID_ATSCNetworkProvider;
152 hr = CreateTuneRequest();
155 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
156 "Cannot create Tuning Space: hr=0x%8lx", hr );
160 hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
161 (void**)&l.p_atsc_tune_request );
164 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
165 "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
168 hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
169 IID_IATSCLocator, (void**)&l.p_atsc_locator );
172 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
173 "Cannot create the ATSC locator: hr=0x%8lx", hr );
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 );
186 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
187 "Cannot set tuning parameters: hr=0x%8lx", hr );
191 hr = p_tune_request->put_Locator( l.p_atsc_locator );
194 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
195 "Cannot put the locator: hr=0x%8lx", hr );
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
207 msg_Warn( p_access, "SubmitATSCTuneRequest: "\
208 "Cannot Build the Graph: hr=0x%8lx", hr );
218 /*****************************************************************************
219 * Submit a DVB-T Tune Request
220 ******************************************************************************/
221 int BDAGraph::SubmitDVBTTuneRequest()
227 IDVBTuneRequest* p_dvbt_tune_request;
228 IDVBTLocator* p_dvbt_locator;
229 localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
232 if( p_dvbt_tune_request )
233 p_dvbt_tune_request->Release();
235 p_dvbt_locator->Release();
238 long l_frequency, l_bandwidth;
240 l_frequency = l_bandwidth = -1;
241 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
242 l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
244 guid_network_type = CLSID_DVBTNetworkProvider;
245 hr = CreateTuneRequest();
248 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
249 "Cannot create Tune Request: hr=0x%8lx", hr );
253 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
254 (void**)&l.p_dvbt_tune_request );
257 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
258 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
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 );
265 hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
266 IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
269 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
270 "Cannot create the DVBT Locator: hr=0x%8lx", hr );
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 );
281 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
282 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
286 hr = p_tune_request->put_Locator( l.p_dvbt_locator );
289 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
290 "Cannot put the locator: hr=0x%8lx", hr );
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
302 msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
303 "Cannot Build the Graph: hr=0x%8lx", hr );
313 /*****************************************************************************
314 * Submit a DVB-C Tune Request
315 ******************************************************************************/
316 int BDAGraph::SubmitDVBCTuneRequest()
323 IDVBTuneRequest* p_dvbc_tune_request;
324 IDVBCLocator* p_dvbc_locator;
325 localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
328 if( p_dvbc_tune_request )
329 p_dvbc_tune_request->Release();
331 p_dvbc_locator->Release();
335 long l_frequency, l_symbolrate;
337 ModulationType i_qam_mod;
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;
345 i_qam_mod = BDA_MOD_16QAM;
347 i_qam_mod = BDA_MOD_32QAM;
349 i_qam_mod = BDA_MOD_64QAM;
351 i_qam_mod = BDA_MOD_128QAM;
353 i_qam_mod = BDA_MOD_256QAM;
355 guid_network_type = CLSID_DVBCNetworkProvider;
356 hr = CreateTuneRequest();
359 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
360 "Cannot create Tune Request: hr=0x%8lx", hr );
364 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
365 (void**)&l.p_dvbc_tune_request );
368 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
369 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
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 );
376 hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
377 IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
380 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
381 "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
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 );
394 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
395 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
399 hr = p_tune_request->put_Locator( l.p_dvbc_locator );
402 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
403 "Cannot put the locator: hr=0x%8lx", hr );
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
415 msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
416 "Cannot Build the Graph: hr=0x%8lx", hr );
426 /*****************************************************************************
427 * Submit a DVB-S Tune Request
428 ******************************************************************************/
429 int BDAGraph::SubmitDVBSTuneRequest()
436 IDVBTuneRequest* p_dvbs_tune_request;
437 IDVBSLocator* p_dvbs_locator;
438 localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL) {};
441 if( p_dvbs_tune_request )
442 p_dvbs_tune_request->Release();
444 p_dvbs_locator->Release();
447 long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
448 char* psz_polarisation;
449 Polarisation i_polar;
452 l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
453 l_frequency = var_GetInteger( p_access, "dvb-frequency" );
454 l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
455 l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
456 l_elevation = var_GetInteger( p_access, "dvb-elevation" );
457 l_longitude = var_GetInteger( p_access, "dvb-longitude" );
458 psz_polarisation = var_GetString( p_access, "dvb-polarisation" );
460 b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
462 i_polar = BDA_POLARISATION_NOT_SET;
463 if( *psz_polarisation == 'H' || *psz_polarisation == 'h' )
464 i_polar = BDA_POLARISATION_LINEAR_H;
465 if( *psz_polarisation == 'V' || *psz_polarisation == 'v' )
466 i_polar = BDA_POLARISATION_LINEAR_V;
467 if( *psz_polarisation == 'L' || *psz_polarisation == 'l' )
468 i_polar = BDA_POLARISATION_CIRCULAR_L;
469 if( *psz_polarisation == 'R' || *psz_polarisation == 'r' )
470 i_polar = BDA_POLARISATION_CIRCULAR_R;
472 guid_network_type = CLSID_DVBSNetworkProvider;
473 hr = CreateTuneRequest();
476 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
477 "Cannot create Tune Request: hr=0x%8lx", hr );
481 hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
482 (void**)&l.p_dvbs_tune_request );
485 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
486 "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
489 l.p_dvbs_tune_request->put_ONID( -1 );
490 l.p_dvbs_tune_request->put_SID( -1 );
491 l.p_dvbs_tune_request->put_TSID( -1 );
493 hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
494 IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
497 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
498 "Cannot create the DVBS Locator: hr=0x%8lx", hr );
503 if( l_frequency > 0 )
504 hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
505 if( SUCCEEDED( hr ) && l_symbolrate > 0 )
506 hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
507 if( SUCCEEDED( hr ) && l_azimuth > 0 )
508 hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
509 if( SUCCEEDED( hr ) && l_elevation > 0 )
510 hr = l.p_dvbs_locator->put_Elevation( l_elevation );
511 if( SUCCEEDED( hr ) )
512 hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
513 if( SUCCEEDED( hr ) )
514 hr = l.p_dvbs_locator->put_WestPosition( b_west );
515 if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
516 hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
519 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
520 "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
524 hr = p_tune_request->put_Locator( l.p_dvbs_locator );
527 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
528 "Cannot put the locator: hr=0x%8lx", hr );
532 /* Build and Run the Graph. If a Tuner device is in use the graph will
533 * fail to run. Repeated calls to build will check successive tuner
540 msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
541 "Cannot Build the Graph: hr=0x%8lx", hr );
551 /*****************************************************************************
552 * Load the Tuning Space from System Tuning Spaces according to the
553 * Network Type requested
554 ******************************************************************************/
555 HRESULT BDAGraph::CreateTuneRequest()
558 GUID guid_this_network_type;
562 ITuningSpaceContainer* p_tuning_space_container;
563 IEnumTuningSpaces* p_tuning_space_enum;
564 ITuningSpace* p_this_tuning_space;
565 localComPtr(): p_tuning_space_container(NULL),
566 p_tuning_space_enum(NULL), p_this_tuning_space(NULL) {};
569 if( p_tuning_space_container )
570 p_tuning_space_container->Release();
571 if( p_tuning_space_enum )
572 p_tuning_space_enum->Release();
573 if( p_this_tuning_space )
574 p_this_tuning_space->Release();
578 /* A Tuning Space may already have been set up. If it is for the same
579 * network type then all is well. Otherwise, reset the Tuning Space and get
583 hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
584 if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
585 if( guid_this_network_type == guid_network_type )
591 p_tuning_space->Release();
592 p_tuning_space = NULL;
596 /* Force use of the first available Tuner Device during Build */
599 /* Get the SystemTuningSpaces container to enumerate through all the
600 * defined tuning spaces */
601 hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
602 IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
605 msg_Warn( p_access, "CreateTuneRequest: "\
606 "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
610 hr = l.p_tuning_space_container->get_EnumTuningSpaces(
611 &l.p_tuning_space_enum );
614 msg_Warn( p_access, "CreateTuneRequest: "\
615 "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
619 while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
622 hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
624 /* GUID_NULL means a non-BDA network was found e.g analog
625 * Ignore failures and non-BDA networks and keep looking */
626 if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
628 if( guid_this_network_type == guid_network_type )
630 hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
631 (void**)&p_tuning_space );
634 msg_Warn( p_access, "CreateTuneRequest: "\
635 "Cannot QI Tuning Space: hr=0x%8lx", hr );
638 hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
641 msg_Warn( p_access, "CreateTuneRequest: "\
642 "Cannot Create Tune Request: hr=0x%8lx", hr );
651 msg_Warn( p_access, "CreateTuneRequest: "\
652 "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
658 /******************************************************************************
660 * Step 4: Build the Filter Graph
661 * Build sets up devices, adds and connects filters
662 ******************************************************************************/
663 HRESULT BDAGraph::Build()
666 long l_capture_used, l_tif_used;
667 AM_MEDIA_TYPE grabber_media_type;
669 /* If we have already have a filter graph, rebuild it*/
672 hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
673 IID_IGraphBuilder, (void**)&p_filter_graph );
676 msg_Warn( p_access, "Build: "\
677 "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
681 /* First filter in the graph is the Network Provider and
682 * its Scanning Tuner which takes the Tune Request*/
683 hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
684 IID_IBaseFilter, (void**)&p_network_provider);
687 msg_Warn( p_access, "Build: "\
688 "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
691 hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
694 msg_Warn( p_access, "Build: "\
695 "Cannot load network provider: hr=0x%8lx", hr );
699 hr = p_network_provider->QueryInterface( IID_IScanningTuner,
700 (void**)&p_scanning_tuner );
703 msg_Warn( p_access, "Build: "\
704 "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
708 hr = p_scanning_tuner->Validate( p_tune_request );
711 msg_Warn( p_access, "Build: "\
712 "Tune Request is invalid: hr=0x%8lx", hr );
715 hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
718 msg_Warn( p_access, "Build: "\
719 "Cannot submit the tune request: hr=0x%8lx", hr );
723 /* Add the Network Tuner to the Network Provider. On subsequent calls,
724 * l_tuner_used will cause a different tuner to be selected */
725 hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
726 p_network_provider, &p_tuner_device );
729 msg_Warn( p_access, "Build: "\
730 "Cannot load tuner device and connect network provider: "\
735 /* Always look for all capture devices to match the Network Tuner */
737 hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
738 p_tuner_device, &p_capture_device );
741 /* Some BDA drivers do not provide a Capture Device Filter so force
742 * the Sample Grabber to connect directly to the Tuner Device */
743 p_capture_device = p_tuner_device;
744 p_tuner_device = NULL;
745 msg_Warn( p_access, "Build: "\
746 "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
749 /* Insert the Sample Grabber to tap into the Transport Stream. */
750 hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
751 IID_IBaseFilter, (void**)&p_sample_grabber );
754 msg_Warn( p_access, "Build: "\
755 "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
758 hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
761 msg_Warn( p_access, "Build: "\
762 "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
766 hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
767 (void**)&p_grabber );
770 msg_Warn( p_access, "Build: "\
771 "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
775 ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
776 grabber_media_type.majortype == MEDIATYPE_Stream;
777 grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
778 hr = p_grabber->SetMediaType( &grabber_media_type );
781 msg_Warn( p_access, "Build: "\
782 "Cannot set media type on grabber filter: hr=0x%8lx", hr );
785 hr = Connect( p_capture_device, p_sample_grabber );
788 msg_Warn( p_access, "Build: "\
789 "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
793 /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
794 * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
795 * the Network Provider filter to set up the stream */
796 hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
797 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
800 msg_Warn( p_access, "Build: "\
801 "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
804 hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
807 msg_Warn( p_access, "Build: "\
808 "Cannot add demux filter to graph: hr=0x%8lx", hr );
812 hr = Connect( p_sample_grabber, p_mpeg_demux );
815 msg_Warn( p_access, "Build: "\
816 "Cannot connect demux to grabber: hr=0x%8lx", hr );
820 /* Always look for the Transform Information Filter from the start
821 * of the collection*/
823 hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
824 p_mpeg_demux, &p_transport_info );
827 msg_Warn( p_access, "Build: "\
828 "Cannot load TIF onto demux: hr=0x%8lx", hr );
832 /* Configure the Sample Grabber to buffer the samples continuously */
833 hr = p_grabber->SetBufferSamples( TRUE );
836 msg_Warn( p_access, "Build: "\
837 "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
840 hr = p_grabber->SetOneShot( FALSE );
843 msg_Warn( p_access, "Build: "\
844 "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
847 hr = p_grabber->SetCallback( this, 0 );
850 msg_Warn( p_access, "Build: "\
851 "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
858 d_graph_register = 0;
861 /* The Media Control is used to Run and Stop the Graph */
862 hr = p_filter_graph->QueryInterface( IID_IMediaControl,
863 (void**)&p_media_control );
866 msg_Warn( p_access, "Build: "\
867 "Cannot QI Media Control: hr=0x%8lx", hr );
873 /******************************************************************************
875 * Looks up all filters in a category and connects to the upstream filter until
876 * a successful match is found. The index of the connected filter is returned.
877 * On subsequent calls, this can be used to start from that point to find
879 * This is used when the graph does not run because a tuner device is in use so
880 * another one needs to be slected.
881 ******************************************************************************/
882 HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
883 IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
886 int i_moniker_index = -1;
891 IEnumMoniker* p_moniker_enum;
892 IBaseFilter* p_filter;
893 IPropertyBag* p_property_bag;
897 p_moniker_enum(NULL),
900 { ::VariantInit(&var_bstr); };
904 p_moniker->Release();
906 p_moniker_enum->Release();
910 p_property_bag->Release();
911 ::VariantClear(&var_bstr);
915 if( !p_system_dev_enum )
917 hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
918 IID_ICreateDevEnum, (void**)&p_system_dev_enum );
921 msg_Warn( p_access, "FindFilter: "\
922 "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
927 hr = p_system_dev_enum->CreateClassEnumerator( clsid,
928 &l.p_moniker_enum, 0 );
931 msg_Warn( p_access, "FindFilter: "\
932 "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
935 while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
939 /* Skip over devices already found on previous calls */
940 if( i_moniker_index <= *i_moniker_used ) continue;
941 *i_moniker_used = i_moniker_index;
943 hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
944 (void**)&l.p_filter );
948 l.p_moniker->Release();
951 l.p_filter->Release();
956 hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
957 (void**)&l.p_property_bag );
960 msg_Warn( p_access, "FindFilter: "\
961 "Cannot Bind to Property Bag: hr=0x%8lx", hr );
965 hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
968 msg_Warn( p_access, "FindFilter: "\
969 "Cannot read filter friendly name: hr=0x%8lx", hr );
973 hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
976 msg_Warn( p_access, "FindFilter: "\
977 "Cannot add filter: hr=0x%8lx", hr );
981 hr = Connect( p_upstream, l.p_filter );
982 if( SUCCEEDED( hr ) )
984 msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
985 l.p_filter->QueryInterface( IID_IBaseFilter,
986 (void**)p_p_downstream );
989 /* Not the filter we want so unload and try the next one */
990 hr = p_filter_graph->RemoveFilter( l.p_filter );
993 msg_Warn( p_access, "FindFilter: "\
994 "Failed unloading Filter: hr=0x%8lx", hr );
999 l.p_moniker->Release();
1002 l.p_filter->Release();
1007 msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
1011 /*****************************************************************************
1012 * Connect is called from Build to enumerate and connect pins
1013 *****************************************************************************/
1014 HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
1016 HRESULT hr = E_FAIL;
1020 IPin* p_pin_upstream;
1021 IPin* p_pin_downstream;
1022 IEnumPins* p_pin_upstream_enum;
1023 IEnumPins* p_pin_downstream_enum;
1025 localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
1026 p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
1027 p_pin_temp(NULL) { };
1030 if( p_pin_upstream )
1031 p_pin_upstream->Release();
1032 if( p_pin_downstream )
1033 p_pin_downstream->Release();
1034 if( p_pin_upstream_enum )
1035 p_pin_upstream_enum->Release();
1036 if( p_pin_downstream_enum )
1037 p_pin_downstream_enum->Release();
1039 p_pin_temp->Release();
1043 PIN_INFO pin_info_upstream;
1044 PIN_INFO pin_info_downstream;
1046 hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
1049 msg_Warn( p_access, "Connect: "\
1050 "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
1053 while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
1055 hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
1058 msg_Warn( p_access, "Connect: "\
1059 "Cannot get upstream filter pin information: hr=0x%8lx", hr );
1062 hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
1064 l.p_pin_downstream->Release();
1065 if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
1067 msg_Warn( p_access, "Connect: "\
1068 "Cannot check upstream filter connection: hr=0x%8lx", hr );
1071 if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
1072 ( hr == VFW_E_NOT_CONNECTED ) )
1074 /* The upstream pin is not yet connected so check each pin on the
1075 * downstream filter */
1076 hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
1079 msg_Warn( p_access, "Connect: Cannot get "\
1080 "downstream filter enumerator: hr=0x%8lx", hr );
1083 while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
1086 hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
1089 msg_Warn( p_access, "Connect: Cannot get "\
1090 "downstream filter pin information: hr=0x%8lx", hr );
1094 hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
1095 if( hr == S_OK ) l.p_pin_temp->Release();
1096 if( hr != VFW_E_NOT_CONNECTED )
1100 msg_Warn( p_access, "Connect: Cannot check "\
1101 "downstream filter connection: hr=0x%8lx", hr );
1105 if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
1106 ( hr == VFW_E_NOT_CONNECTED ) )
1108 hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
1109 l.p_pin_downstream, NULL );
1110 if( SUCCEEDED( hr ) )
1112 pin_info_downstream.pFilter->Release();
1113 pin_info_upstream.pFilter->Release();
1117 /* If we fall out here it means this downstream pin was not
1118 * suitable so try the next downstream pin */
1119 l.p_pin_downstream = NULL;
1120 pin_info_downstream.pFilter->Release();
1124 /* If we fall out here it means we did not find any suitable downstream
1125 * pin so try the next upstream pin */
1126 l.p_pin_upstream = NULL;
1127 pin_info_upstream.pFilter->Release();
1130 /* If we fall out here it means we did not find any pair of suitable pins */
1134 /*****************************************************************************
1135 * Start uses MediaControl to start the graph
1136 *****************************************************************************/
1137 HRESULT BDAGraph::Start()
1140 OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
1142 if( !p_media_control )
1144 msg_Dbg( p_access, "Start: Media Control has not been created" );
1147 hr = p_media_control->Run();
1151 /* Query the state of the graph - timeout after 100 milliseconds */
1152 while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
1157 "Start: Cannot get Graph state: hr=0x%8lx", hr );
1161 if( i_state == State_Running )
1164 /* The Graph is not running so stop it and return an error */
1165 hr = p_media_control->Stop();
1169 "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
1175 /*****************************************************************************
1176 * Read the stream of data - query the buffer size required
1177 *****************************************************************************/
1178 long BDAGraph::GetBufferSize()
1180 long l_buffer_size = 0;
1185 for( int i_timer = 0; queue_sample.empty() && i_timer < 200; i_timer++ )
1188 l_queue_size = queue_sample.size();
1189 if( l_queue_size <= 0 )
1191 msg_Warn( p_access, "BDA GetBufferSize: Timed Out waiting for sample" );
1195 /* Establish the length of the queue as it grows quickly. If the queue
1196 * size is checked dynamically there is a risk of not exiting the loop */
1197 for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
1199 l_buffer_size += queue_sample.front()->GetActualDataLength();
1200 queue_buffer.push( queue_sample.front() );
1203 return l_buffer_size;
1206 /*****************************************************************************
1207 * Read the stream of data - Retrieve from the buffer queue
1208 ******************************************************************************/
1209 long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
1216 while( !queue_buffer.empty() )
1218 queue_buffer.front()->GetPointer( &p_buff_temp );
1219 hr = queue_buffer.front()->IsDiscontinuity();
1222 "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
1223 memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
1224 queue_buffer.front()->GetActualDataLength() );
1225 *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
1226 queue_buffer.front()->Release();
1230 return *pl_buffer_len;
1233 /******************************************************************************
1234 * SampleCB - Callback when the Sample Grabber has a sample
1235 ******************************************************************************/
1236 STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
1241 queue_sample.push( p_sample );
1245 msg_Warn( p_access, "BDA SampleCB: Not ready - dropped sample" );
1250 STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
1256 /******************************************************************************
1257 * removes each filter from the graph
1258 ******************************************************************************/
1259 HRESULT BDAGraph::Destroy()
1263 if( p_media_control )
1264 hr = p_media_control->Stop();
1266 if( p_transport_info )
1268 p_filter_graph->RemoveFilter( p_transport_info );
1269 p_transport_info->Release();
1270 p_transport_info = NULL;
1274 p_filter_graph->RemoveFilter( p_mpeg_demux );
1275 p_mpeg_demux->Release();
1276 p_mpeg_demux = NULL;
1278 if( p_sample_grabber )
1280 p_filter_graph->RemoveFilter( p_sample_grabber );
1281 p_sample_grabber->Release();
1282 p_sample_grabber = NULL;
1284 if( p_capture_device )
1286 p_filter_graph->RemoveFilter( p_capture_device );
1287 p_capture_device->Release();
1288 p_capture_device = NULL;
1290 if( p_tuner_device )
1292 p_filter_graph->RemoveFilter( p_tuner_device );
1293 p_tuner_device->Release();
1294 p_tuner_device = NULL;
1296 if( p_network_provider )
1298 p_filter_graph->RemoveFilter( p_network_provider );
1299 p_network_provider->Release();
1300 p_network_provider = NULL;
1303 if( p_scanning_tuner )
1305 p_scanning_tuner->Release();
1306 p_scanning_tuner = NULL;
1308 if( p_media_control )
1310 p_media_control->Release();
1311 p_media_control = NULL;
1313 if( p_scanning_tuner )
1315 p_filter_graph->Release();
1316 p_filter_graph = NULL;
1319 if( d_graph_register )
1327 /*****************************************************************************
1328 * Add/Remove a DirectShow filter graph to/from the Running Object Table.
1329 * Allows GraphEdit to "spy" on a remote filter graph.
1330 ******************************************************************************/
1331 HRESULT BDAGraph::Register()
1336 IMoniker* p_moniker;
1337 IRunningObjectTable* p_ro_table;
1338 localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
1342 p_moniker->Release();
1344 p_ro_table->Release();
1347 WCHAR psz_w_graph_name[128];
1350 hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
1353 msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
1357 wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
1358 (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
1359 hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
1362 msg_Warn( p_access, "Register: Cannot Create Moniker: hr=0x%8lx", hr );
1365 hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
1366 p_filter_graph, l.p_moniker, &d_graph_register );
1369 msg_Warn( p_access, "Register: Cannot Register Graph: hr=0x%8lx", hr );
1372 msg_Dbg( p_access, "Register: registered Graph: %S", psz_w_graph_name );
1376 void BDAGraph::Deregister()
1379 IRunningObjectTable* p_ro_table;
1380 hr = ::GetRunningObjectTable( 0, &p_ro_table );
1381 if( SUCCEEDED( hr ) )
1382 p_ro_table->Revoke( d_graph_register );
1383 d_graph_register = 0;
1384 p_ro_table->Release();