--- /dev/null
+/*****************************************************************************
+ * bda.c : BDA access module for vlc
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ *
+ * Author: Ken Self <kens@campoz.fslife.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc_input.h>
+#include <vlc_access.h>
+
+#include "bda.h"
+
+/*****************************************************************************
+ * Access: local prototypes
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this );
+static int ParsePath( access_t *p_access, const char* psz_module,
+ const int i_param_count, const char** psz_param, const int* i_type );
+static void Close( vlc_object_t *p_this );
+static block_t *Block( access_t * );
+static int Control( access_t *, int, va_list );
+
+
+#define CACHING_TEXT N_("Caching value in ms")
+#define CACHING_LONGTEXT N_( \
+ "Caching value for DVB streams. This " \
+ "value should be set in milliseconds." )
+
+#define ADAPTER_TEXT N_("Adapter card to tune")
+#define ADAPTER_LONGTEXT N_("Adapter cards have a device file in directory " \
+ "named /dev/dvb/adapter[n] with n>=0.")
+
+#define DEVICE_TEXT N_("Device number to use on adapter")
+#define DEVICE_LONGTEXT ""
+
+#define FREQ_TEXT N_("Transponder/multiplex frequency")
+#define FREQ_LONGTEXT N_("In kHz for DVB-S or Hz for DVB-C/T")
+
+#define INVERSION_TEXT N_("Inversion mode")
+#define INVERSION_LONGTEXT N_("Inversion mode [0=off, 1=on, 2=auto]")
+
+#define PROBE_TEXT N_("Probe DVB card for capabilities")
+#define PROBE_LONGTEXT N_("Some DVB cards do not like to be probed for their " \
+ "capabilities, you can disable this feature if you experience some " \
+ "trouble.")
+
+#define BUDGET_TEXT N_("Budget mode")
+#define BUDGET_LONGTEXT N_("This allows you to stream an entire transponder " \
+ "with a \"budget\" card.")
+
+/* Satellite */
+#define SATNO_TEXT N_("Satellite number in the Diseqc system")
+#define SATNO_LONGTEXT N_("[0=no diseqc, 1-4=satellite number].")
+
+#define VOLTAGE_TEXT N_("LNB voltage")
+#define VOLTAGE_LONGTEXT N_("In Volts [0, 13=vertical, 18=horizontal].")
+
+#define HIGH_VOLTAGE_TEXT N_("High LNB voltage")
+#define HIGH_VOLTAGE_LONGTEXT N_("Enable high voltage if your cables are " \
+ "particularly long. This is not supported by all frontends.")
+
+#define TONE_TEXT N_("22 kHz tone")
+#define TONE_LONGTEXT N_("[0=off, 1=on, -1=auto].")
+
+#define FEC_TEXT N_("Transponder FEC")
+#define FEC_LONGTEXT N_("FEC=Forward Error Correction mode [9=auto].")
+
+#define SRATE_TEXT N_("Transponder symbol rate in kHz")
+#define SRATE_LONGTEXT ""
+
+#define LNB_LOF1_TEXT N_("Antenna lnb_lof1 (kHz)")
+#define LNB_LOF1_LONGTEXT ""
+
+#define LNB_LOF2_TEXT N_("Antenna lnb_lof2 (kHz)")
+#define LNB_LOF2_LONGTEXT ""
+
+#define LNB_SLOF_TEXT N_("Antenna lnb_slof (kHz)")
+#define LNB_SLOF_LONGTEXT ""
+
+/* Cable */
+#define MODULATION_TEXT N_("Modulation type")
+#define MODULATION_LONGTEXT N_("QAM constellation points " \
+ "[16, 32, 64, 128, 256]")
+static const int i_qam_list[] = { -1, 16, 32, 64, 128, 256 };
+static const char *ppsz_qam_text[] = { N_("Undefined"), N_("16"), N_("32"),
+ N_("64"), N_("128"), N_("256") };
+
+/* Terrestrial */
+#define CODE_RATE_HP_TEXT N_("Terrestrial high priority stream code rate (FEC)")
+#define CODE_RATE_HP_LONGTEXT ""
+
+#define CODE_RATE_LP_TEXT N_("Terrestrial low priority stream code rate (FEC)")
+#define CODE_RATE_LP_LONGTEXT ""
+
+#define BANDWIDTH_TEXT N_("Terrestrial bandwidth")
+#define BANDWIDTH_LONGTEXT N_("Terrestrial bandwidth [0=auto,6,7,8 in MHz]")
+static const int i_band_list[] = { -1, 6, 7, 8 };
+static const char *ppsz_band_text[] = { N_("Undefined"), N_("6"), N_("7"),
+ N_("8") };
+
+#define GUARD_TEXT N_("Terrestrial guard interval")
+#define GUARD_LONGTEXT ""
+
+#define TRANSMISSION_TEXT N_("Terrestrial transmission mode")
+#define TRANSMISSION_LONGTEXT ""
+
+#define HIERARCHY_TEXT N_("Terrestrial hierarchy mode")
+#define HIERARCHY_LONGTEXT ""
+
+/* BDA module additional DVB-S Parameters */
+#define AZIMUTH_TEXT N_("Satellite Azimuth")
+#define AZIMUTH_LONGTEXT N_("Satellite Azimuth in tenths of degree")
+#define ELEVATION_TEXT N_("Satellite Elevation")
+#define ELEVATION_LONGTEXT N_("Satellite Elevation in tenths of degree")
+#define LONGITUDE_TEXT N_("Satellite Longitude")
+#define LONGITUDE_LONGTEXT N_( \
+ "Satellite Longitude in 10ths of degree, -ve=West")
+#define POLARISATION_TEXT N_("Satellite Polarisation")
+#define POLARISATION_LONGTEXT N_("Satellite Polarisation [H/V/L/R]")
+static const char *ppsz_polar_list[] = { "H", "V", "L", "R" };
+static const char *ppsz_polar_text[] = { N_("Horizontal"), N_("Vertical"),
+ N_("Circular Left"), N_("Circular Right") };
+
+vlc_module_begin();
+ set_shortname( _("DVB") );
+ set_description( _("DirectShow DVB input") );
+ set_category( CAT_INPUT );
+ set_subcategory( SUBCAT_INPUT_ACCESS );
+
+ add_integer( "dvb-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
+ CACHING_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-frequency", 11954000, NULL, FREQ_TEXT, FREQ_LONGTEXT,
+ VLC_FALSE );
+# if defined(WIN32) || defined(WINCE)
+# else
+ add_integer( "dvb-adapter", 0, NULL, ADAPTER_TEXT, ADAPTER_LONGTEXT,
+ VLC_FALSE );
+ add_integer( "dvb-device", 0, NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
+ VLC_TRUE );
+ add_integer( "dvb-inversion", 2, NULL, INVERSION_TEXT,
+ INVERSION_LONGTEXT, VLC_TRUE );
+ add_bool( "dvb-probe", 1, NULL, PROBE_TEXT, PROBE_LONGTEXT, VLC_TRUE );
+ add_bool( "dvb-budget-mode", 0, NULL, BUDGET_TEXT, BUDGET_LONGTEXT,
+ VLC_TRUE );
+# endif
+
+ /* DVB-S (satellite) */
+# if defined(WIN32) || defined(WINCE)
+ add_integer( "dvb-azimuth", 0, NULL, AZIMUTH_TEXT, AZIMUTH_LONGTEXT,
+ VLC_FALSE );
+ add_integer( "dvb-elevation", 0, NULL, ELEVATION_TEXT,
+ ELEVATION_LONGTEXT, VLC_FALSE );
+ add_integer( "dvb-longitude", 0, NULL, LONGITUDE_TEXT,
+ LONGITUDE_LONGTEXT, VLC_FALSE );
+ add_string( "dvb-polarisation", NULL, NULL, POLARISATION_TEXT,
+ POLARISATION_LONGTEXT, VLC_FALSE );
+ change_string_list( ppsz_polar_list, ppsz_polar_text, 0 );
+ /* Note: Polaristion H = voltage 18; V = voltage 13; */
+# else
+ add_integer( "dvb-satno", 0, NULL, SATNO_TEXT, SATNO_LONGTEXT,
+ VLC_TRUE );
+ add_integer( "dvb-voltage", 13, NULL, VOLTAGE_TEXT, VOLTAGE_LONGTEXT,
+ VLC_TRUE );
+ add_bool( "dvb-high-voltage", 0, NULL, HIGH_VOLTAGE_TEXT,
+ HIGH_VOLTAGE_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-tone", -1, NULL, TONE_TEXT, TONE_LONGTEXT,
+ VLC_TRUE );
+ add_integer( "dvb-lnb-lof1", 0, NULL, LNB_LOF1_TEXT,
+ LNB_LOF1_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-lnb-lof2", 0, NULL, LNB_LOF2_TEXT,
+ LNB_LOF2_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-lnb-slof", 0, NULL, LNB_SLOF_TEXT,
+ LNB_SLOF_LONGTEXT, VLC_TRUE );
+# endif
+ add_integer( "dvb-fec", 9, NULL, FEC_TEXT, FEC_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-srate", 27500000, NULL, SRATE_TEXT, SRATE_LONGTEXT,
+ VLC_FALSE );
+
+ /* DVB-C (cable) */
+ add_integer( "dvb-modulation", 0, NULL, MODULATION_TEXT,
+ MODULATION_LONGTEXT, VLC_TRUE );
+ change_integer_list( i_qam_list, ppsz_qam_text, 0 );
+
+ /* DVB-T (terrestrial) */
+ add_integer( "dvb-code-rate-hp", 9, NULL, CODE_RATE_HP_TEXT,
+ CODE_RATE_HP_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-code-rate-lp", 9, NULL, CODE_RATE_LP_TEXT,
+ CODE_RATE_LP_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-bandwidth", 0, NULL, BANDWIDTH_TEXT, BANDWIDTH_LONGTEXT,
+ VLC_TRUE );
+ change_integer_list( i_band_list, ppsz_band_text, 0 );
+ add_integer( "dvb-guard", 0, NULL, GUARD_TEXT, GUARD_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-transmission", 0, NULL, TRANSMISSION_TEXT,
+ TRANSMISSION_LONGTEXT, VLC_TRUE );
+ add_integer( "dvb-hierarchy", 0, NULL, HIERARCHY_TEXT, HIERARCHY_LONGTEXT,
+ VLC_TRUE );
+
+ set_capability( "access2", 0 );
+ add_shortcut( "dvb" ); /* Generic name */
+
+ add_shortcut( "dvb-s" ); /* Satellite */
+ add_shortcut( "qpsk" );
+ add_shortcut( "satellite" );
+
+ add_shortcut( "dvb-c" ); /* Cable */
+ add_shortcut( "cable" );
+
+ add_shortcut( "dvb-t" ); /* Terrestrial */
+ add_shortcut( "terrestrial" );
+
+ add_shortcut( "atsc" ); /* Atsc */
+ add_shortcut( "usdigital" );
+
+ set_callbacks( Open, Close );
+vlc_module_end();
+
+
+/*****************************************************************************
+ * Open: open direct show device as an access module
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+ access_t *p_access = (access_t*)p_this;
+ access_sys_t *p_sys;
+ const char* psz_module = "dvb";
+ const int i_param_count = 8;
+ const char* psz_param[] = { "frequency", "bandwidth",
+ "srate", "azimuth", "elevation", "longitude", "polarisation",
+ "modulation" };
+
+ const int i_type[] = { VLC_VAR_INTEGER, VLC_VAR_INTEGER,
+ VLC_VAR_INTEGER, VLC_VAR_INTEGER, VLC_VAR_INTEGER, VLC_VAR_INTEGER,
+ VLC_VAR_STRING, VLC_VAR_INTEGER };
+
+ char psz_full_name[128];
+ int i_ret;
+
+ /* Only if selected */
+ if( *p_access->psz_access == '\0' )
+ return VLC_EGENERIC;
+
+ /* Setup Access */
+ p_access->pf_read = NULL;
+ p_access->pf_block = Block; /* Function to read compressed data */
+ p_access->pf_control = Control; /* Function to control the module */
+ p_access->pf_seek = NULL;
+ p_access->info.i_update = 0;
+ p_access->info.i_size = 0;
+ p_access->info.i_pos = 0;
+ p_access->info.b_eof = VLC_FALSE;
+ p_access->info.i_title = 0;
+ p_access->info.i_seekpoint = 0;
+ p_access->p_sys = p_sys = (access_sys_t *)malloc( sizeof( access_sys_t ) );
+ if( !p_sys )
+ return VLC_ENOMEM;
+
+ memset( p_sys, 0, sizeof( access_sys_t ) );
+
+ for( int i = 0; i < i_param_count; i++ )
+ {
+ snprintf( psz_full_name, 128, "%s-%s\0", psz_module,
+ psz_param[i] );
+ var_Create( p_access, psz_full_name, i_type[i] | VLC_VAR_DOINHERIT );
+ }
+
+ /* Parse the command line */
+ if( ParsePath( p_access, psz_module, i_param_count, psz_param, i_type ) )
+ {
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
+
+ /* Build directshow graph */
+ dvb_newBDAGraph( p_access );
+
+ i_ret = VLC_EGENERIC;
+
+ if( strncmp( p_access->psz_access, "qpsk", 4 ) == 0 ||
+ strncmp( p_access->psz_access, "dvb-s", 5 ) == 0 ||
+ strncmp( p_access->psz_access, "satellite", 9 ) == 0 )
+ {
+ i_ret = dvb_SubmitDVBSTuneRequest( p_access );
+ }
+ if( strncmp( p_access->psz_access, "cable", 5 ) == 0 ||
+ strncmp( p_access->psz_access, "dvb-c", 5 ) == 0 )
+ {
+ i_ret = dvb_SubmitDVBCTuneRequest( p_access );
+ }
+ if( strncmp( p_access->psz_access, "terrestrial", 11 ) == 0 ||
+ strncmp( p_access->psz_access, "dvb-t", 5 ) == 0 )
+ {
+ i_ret = dvb_SubmitDVBTTuneRequest( p_access );
+ }
+ if( strncmp( p_access->psz_access, "usdigital", 9 ) == 0 ||
+ strncmp( p_access->psz_access, "atsc", 4 ) == 0 )
+ {
+ i_ret = dvb_SubmitATSCTuneRequest( p_access );
+ }
+
+ if( i_ret != VLC_SUCCESS )
+ msg_Warn( p_access, "DVB_Open: Unsupported Network %s",
+ p_access->psz_access);
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ParsePath:
+ * Parses the path passed to VLC treating it as a MRL which
+ * is organized as a sequence of <key>=<value> pairs separated by a colon
+ * e.g. :key1=value1:key2=value2:key3=value3.
+ * Each <key> is matched to one of the parameters passed in psz_param using
+ * whatever characters are provided. e.g. fr = fre = frequency
+ *****************************************************************************/
+static int ParsePath( access_t *p_access, const char* psz_module,
+ const int i_param_count, const char** psz_param, const int* i_type )
+{
+ const int MAXPARAM = 20;
+ BOOL b_used[MAXPARAM];
+ char* psz_parser;
+ char* psz_token;
+ char* psz_value;
+ vlc_value_t v_value;
+ int i_token_len, i_param_len, i_this_param;
+ char psz_full_name[128];
+
+ if( i_param_count > MAXPARAM )
+ {
+ msg_Warn( p_access, "ParsePath: Too many parameters: %d > %d",
+ i_param_count, MAXPARAM );
+ return VLC_EGENERIC;
+ }
+ for( int i = 0; i < i_param_count; i++ )
+ b_used[i] = FALSE;
+ psz_parser = p_access->psz_path;
+ if( strlen( psz_parser ) <= 0 )
+ return VLC_SUCCESS;
+
+ i_token_len = strcspn( psz_parser, ":" );
+ if( i_token_len <= 0 )
+ i_token_len = strcspn( ++psz_parser, ":" );
+
+ do
+ {
+ psz_token = strndup( psz_parser, i_token_len );
+ i_param_len = strcspn( psz_token, "=" );
+ if( i_param_len <= 0 )
+ {
+ msg_Warn( p_access, "ParsePath: Unspecified parameter %s",
+ psz_token );
+ if( psz_token )
+ free( psz_token );
+ return VLC_EGENERIC;
+ }
+ i_this_param = -1;
+ for( int i = 0; i < i_param_count; i++ )
+ {
+ if( strncmp( psz_token, psz_param[i], i_param_len ) == 0 )
+ {
+ i_this_param = i;
+ break;
+ }
+ }
+ if( i_this_param < 0 )
+ {
+ msg_Warn( p_access, "ParsePath: Unknown parameter %s", psz_token );
+ if( psz_token )
+ free( psz_token );
+ return VLC_EGENERIC;
+ }
+ if( b_used[i_this_param] )
+ {
+ msg_Warn( p_access, "ParsePath: Duplicate parameter %s",
+ psz_token );
+ if( psz_token )
+ free( psz_token );
+ return VLC_EGENERIC;
+ }
+ b_used[i_this_param] = TRUE;
+
+ /* if "=" was found in token then value starts at
+ * psz_token + i_paramlen + 1
+ * else there is no value specified so we use an empty string */
+ psz_value = psz_token + i_param_len + 1;
+ if( i_param_len >= i_token_len )
+ psz_value--;
+ if( i_type[i_this_param] == VLC_VAR_STRING )
+ v_value.psz_string = strdup( psz_value );
+ if( i_type[i_this_param] == VLC_VAR_INTEGER )
+ v_value.i_int = atol( psz_value );
+ snprintf( psz_full_name, 128, "%s-%s\0", psz_module,
+ psz_param[i_this_param] );
+ var_Set( p_access, psz_full_name, v_value );
+
+ if( psz_token )
+ free( psz_token );
+ if( i_token_len >= strlen( psz_parser ) )
+ break;
+ psz_parser += i_token_len + 1;
+ i_token_len = strcspn( psz_parser, ":" );
+ }
+ while( TRUE );
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * AccessClose: close device
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+ access_t *p_access = (access_t *)p_this;
+ access_sys_t *p_sys = p_access->p_sys;
+
+ dvb_deleteBDAGraph( p_access );
+
+ vlc_mutex_destroy( &p_sys->lock );
+ vlc_cond_destroy( &p_sys->wait );
+
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * Control:
+ *****************************************************************************/
+static int Control( access_t *p_access, int i_query, va_list args )
+{
+ vlc_bool_t *pb_bool, b_bool;
+ int *pi_int, i_int;
+ int64_t *pi_64;
+
+ switch( i_query )
+ {
+ case ACCESS_CAN_SEEK: /* 0 */
+ case ACCESS_CAN_FASTSEEK: /* 1 */
+ case ACCESS_CAN_PAUSE: /* 2 */
+ case ACCESS_CAN_CONTROL_PACE: /* 3 */
+ pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
+ *pb_bool = VLC_FALSE;
+ break;
+ case ACCESS_GET_MTU: /* 4 */
+ pi_int = (int*)va_arg( args, int * );
+ *pi_int = 0;
+ break;
+ case ACCESS_GET_PTS_DELAY: /* 5 */
+ pi_64 = (int64_t*)va_arg( args, int64_t * );
+ *pi_64 = var_GetInteger( p_access, "dvb-caching" ) * 1000;
+ break;
+ /* */
+ case ACCESS_GET_TITLE_INFO: /* 6 */
+ case ACCESS_GET_META: /* 7 */
+ case ACCESS_SET_PAUSE_STATE: /* 8 */
+ case ACCESS_SET_TITLE: /* 9 */
+ case ACCESS_SET_SEEKPOINT: /* 10 */
+ return VLC_EGENERIC;
+
+ case ACCESS_SET_PRIVATE_ID_STATE: /* 11 */
+ i_int = (int)va_arg( args, int );
+ b_bool = (vlc_bool_t)va_arg( args, vlc_bool_t );
+ break;
+ case ACCESS_SET_PRIVATE_ID_CA: /* 12 -From Demux */
+ break;
+ default:
+ msg_Warn( p_access,
+ "DVB_Control: Unimplemented query in control %d", i_query );
+ return VLC_EGENERIC;
+ }
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Block:
+ *****************************************************************************/
+static block_t *Block( access_t *p_access )
+{
+ block_t *p_block;
+ long l_buffer_len;
+
+ if( p_access->b_die )
+ return NULL;
+
+ l_buffer_len = dvb_GetBufferSize( p_access );
+ if( l_buffer_len < 0 )
+ return NULL;
+
+ p_block = block_New( p_access, l_buffer_len );
+ if( dvb_ReadBuffer( p_access, &l_buffer_len, p_block->p_buffer )
+ < 0 )
+ return NULL;
+
+ return p_block;
+}
--- /dev/null
+/*****************************************************************************
+ * bdadefs.h : DirectShow BDA headers for vlc
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ *
+ * Author: Ken Self <kens@campoz.fslife.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+class IATSCChannelTuneRequest;
+class IATSCLocator;
+class IChannelTuneRequest;
+class IComponent;
+class IComponents;
+class IComponentType;
+class IComponentTypes;
+class IDVBCLocator;
+class IDVBSLocator;
+class IDVBTLocator;
+class IDVBTuneRequest;
+class IEnumComponents;
+class IEnumComponentTypes;
+class IEnumTuningSpaces;
+class ILocator;
+class ISampleGrabber;
+class ISampleGrabberCB;
+class IScanningTuner;
+class ITuner;
+class ITuneRequest;
+class ITuningSpace;
+class ITuningSpaceContainer;
+class ITuningSpaces;
+
+typedef enum BinaryConvolutionCodeRate
+{
+ BDA_BCC_RATE_NOT_SET = -1,
+ BDA_BCC_RATE_NOT_DEFINED=0,
+ BDA_BCC_RATE_1_2 = 1,
+ BDA_BCC_RATE_2_3,
+ BDA_BCC_RATE_3_4,
+ BDA_BCC_RATE_3_5,
+ BDA_BCC_RATE_4_5,
+ BDA_BCC_RATE_5_6,
+ BDA_BCC_RATE_5_11,
+ BDA_BCC_RATE_7_8,
+ BDA_BCC_RATE_MAX,
+} BinaryConvolutionCodeRate;
+
+typedef enum ComponentCategory
+{
+ CategoryNotSet = -1,
+ CategoryOther=0,
+ CategoryVideo,
+ CategoryAudio,
+ CategoryText,
+ CategoryData,
+} ComponentCategory;
+
+typedef enum ComponentStatus
+{
+ StatusActive,
+ StatusInactive,
+ StatusUnavailable,
+} ComponentStatus;
+
+typedef enum FECMethod
+{
+ BDA_FEC_METHOD_NOT_SET = -1,
+ BDA_FEC_METHOD_NOT_DEFINED=0,
+ BDA_FEC_VITERBI = 1,
+ BDA_FEC_RS_204_188,
+ BDA_FEC_MAX,
+} FECMethod;
+
+typedef enum GuardInterval
+{
+ BDA_GUARD_NOT_SET = -1,
+ BDA_GUARD_NOT_DEFINED=0,
+ BDA_GUARD_1_32 = 1,
+ BDA_GUARD_1_16,
+ BDA_GUARD_1_8,
+ BDA_GUARD_1_4,
+ BDA_GUARD_MAX,
+} GuardInterval;
+
+typedef enum HierarchyAlpha
+{
+ BDA_HALPHA_NOT_SET = -1,
+ BDA_HALPHA_NOT_DEFINED=0,
+ BDA_HALPHA_1 = 1,
+ BDA_HALPHA_2,
+ BDA_HALPHA_4,
+ BDA_HALPHA_MAX,
+} HierarchyAlpha;
+
+typedef enum ModulationType
+{
+ BDA_MOD_NOT_SET = -1,
+ BDA_MOD_NOT_DEFINED=0,
+ BDA_MOD_16QAM = 1,
+ BDA_MOD_32QAM,
+ BDA_MOD_64QAM,
+ BDA_MOD_80QAM,
+ BDA_MOD_96QAM,
+ BDA_MOD_112QAM,
+ BDA_MOD_128QAM,
+ BDA_MOD_160QAM,
+ BDA_MOD_192QAM,
+ BDA_MOD_224QAM,
+ BDA_MOD_256QAM,
+ BDA_MOD_320QAM,
+ BDA_MOD_384QAM,
+ BDA_MOD_448QAM,
+ BDA_MOD_512QAM,
+ BDA_MOD_640QAM,
+ BDA_MOD_768QAM,
+ BDA_MOD_896QAM,
+ BDA_MOD_1024QAM,
+ BDA_MOD_QPSK,
+ BDA_MOD_BPSK,
+ BDA_MOD_OQPSK,
+ BDA_MOD_8VSB,
+ BDA_MOD_16VSB,
+ BDA_MOD_ANALOG_AMPLITUDE,
+ BDA_MOD_ANALOG_FREQUENCY,
+ BDA_MOD_MAX,
+} ModulationType;
+
+typedef enum Polarisation
+{
+ BDA_POLARISATION_NOT_SET = -1,
+ BDA_POLARISATION_NOT_DEFINED = 0,
+ BDA_POLARISATION_LINEAR_H = 1,
+ BDA_POLARISATION_LINEAR_V = 2,
+ BDA_POLARISATION_CIRCULAR_L = 3,
+ BDA_POLARISATION_CIRCULAR_R = 4,
+ BDA_POLARISATION_MAX = 5
+} Polarisation;
+
+typedef enum TransmissionMode
+{
+ BDA_XMIT_MODE_NOT_SET = -1,
+ BDA_XMIT_MODE_NOT_DEFINED=0,
+ BDA_XMIT_MODE_2K = 1,
+ BDA_XMIT_MODE_8K,
+ BDA_XMIT_MODE_MAX,
+} TransmissionMode;
+
+class IComponent : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_Type( IComponentType** p_p_cpt_type )=0;
+ virtual HRESULT __stdcall put_Type( IComponentType* p_cpt_type )=0;
+ virtual HRESULT __stdcall get_DescLangID( long* p_l_language )=0;
+ virtual HRESULT __stdcall put_DescLangID( long l_language )=0;
+ virtual HRESULT __stdcall get_Status( ComponentStatus* p_status )=0;
+ virtual HRESULT __stdcall put_Status( ComponentStatus status )=0;
+ virtual HRESULT __stdcall get_Description( BSTR* p_bstr_desc )=0;
+ virtual HRESULT __stdcall put_Description( BSTR bstr_desc )=0;
+ virtual HRESULT __stdcall Clone( IComponent** p_p_component )=0;
+};
+
+class IComponents : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_Count( long* pl_count )=0;
+ virtual HRESULT __stdcall get__NewEnum( IEnumVARIANT** p_p_enum )=0;
+ virtual HRESULT __stdcall EnumComponents( IEnumComponents** p_p_enum )=0;
+ virtual HRESULT __stdcall get_Item( VARIANT Index,
+ IComponent** p_p_component )=0;
+ virtual HRESULT __stdcall Add( IComponent* p_component,
+ VARIANT* v_index )=0;
+ virtual HRESULT __stdcall Remove( VARIANT v_index )=0;
+ virtual HRESULT __stdcall Clone( IComponents** p_p_cpts )=0;
+};
+
+class IComponentType : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_Category( ComponentCategory* p_category )=0;
+ virtual HRESULT __stdcall put_Category( ComponentCategory category )=0;
+ virtual HRESULT __stdcall get_MediaMajorType( BSTR* p_bstr_major_type )=0;
+ virtual HRESULT __stdcall put_MediaMajorType( BSTR bstr_major_type )=0;
+ virtual HRESULT __stdcall get__MediaMajorType( GUID* p_guid_major_type )=0;
+ virtual HRESULT __stdcall put__MediaMajorType( REFCLSID guid_major_type )=0;
+ virtual HRESULT __stdcall get_MediaSubType( BSTR* p_bstr_sub_type )=0;
+ virtual HRESULT __stdcall put_MediaSubType( BSTR bstr_sub_type )=0;
+ virtual HRESULT __stdcall get__MediaSubType( GUID* p_guid_sub_type )=0;
+ virtual HRESULT __stdcall put__MediaSubType( REFCLSID guid_sub_type )=0;
+ virtual HRESULT __stdcall get_MediaFormatType( BSTR* p_bstr_format_type )=0;
+ virtual HRESULT __stdcall put_MediaFormatType( BSTR bstr_format_type )=0;
+ virtual HRESULT __stdcall get__MediaFormatType(
+ GUID* p_guid_format_type )=0;
+ virtual HRESULT __stdcall put__MediaFormatType(
+ REFCLSID guid_format_type )=0;
+ virtual HRESULT __stdcall get_MediaType( AM_MEDIA_TYPE* p_media_type )=0;
+ virtual HRESULT __stdcall put_MediaType( AM_MEDIA_TYPE* p_media_type )=0;
+ virtual HRESULT __stdcall Clone( IComponentType** p_p_cpt_type )=0;
+};
+
+class IComponentTypes : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_Count( long* l_count )=0;
+ virtual HRESULT __stdcall get__NewEnum( IEnumVARIANT** p_p_enum )=0;
+ virtual HRESULT __stdcall EnumComponentTypes(
+ IEnumComponentTypes** p_p_enum )=0;
+ virtual HRESULT __stdcall get_Item( VARIANT v_index,
+ IComponentType** p_p_cpt_type )=0;
+ virtual HRESULT __stdcall put_Item( VARIANT v_index,
+ IComponentType* p_cpt_type )=0;
+ virtual HRESULT __stdcall Add( IComponentType* p_cpt_type,
+ VARIANT* v_index )=0;
+ virtual HRESULT __stdcall Remove( VARIANT v_index )=0;
+ virtual HRESULT __stdcall Clone( IComponentTypes** p_p_cpt_types )=0;
+};
+
+class IEnumComponents : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall Next( ULONG num_elem, IComponent** p_p_elem,
+ ULONG* p_num_elem_fetch )=0;
+ virtual HRESULT __stdcall Skip( ULONG num_elem )=0;
+ virtual HRESULT __stdcall Reset( void )=0;
+ virtual HRESULT __stdcall Clone( IEnumComponents** p_p_enum )=0;
+};
+
+class IEnumComponentTypes : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall Next( ULONG num_elem, IComponentType** p_p_elem,
+ ULONG* p_num_elem_fetch )=0;
+ virtual HRESULT __stdcall Skip( ULONG num_elem )=0;
+ virtual HRESULT __stdcall Reset( void )=0;
+ virtual HRESULT __stdcall Clone( IEnumComponentTypes** p_p_enum )=0;
+};
+
+class IEnumTuningSpaces : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall Next( ULONG l_num_elem,
+ ITuningSpace** p_p_tuning_space, ULONG* pl_num_elem_fetched )=0;
+ virtual HRESULT __stdcall Skip( ULONG l_num_elem )=0;
+ virtual HRESULT __stdcall Reset( void )=0;
+ virtual HRESULT __stdcall Clone( IEnumTuningSpaces** p_p_enum )=0;
+};
+
+class ITuner : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall get_TuningSpace(
+ ITuningSpace** p_p_tuning_space )=0;
+ virtual HRESULT __stdcall put_TuningSpace( ITuningSpace* p_tuning_space )=0;
+ virtual HRESULT __stdcall EnumTuningSpaces( IEnumTuningSpaces** p_p_enum )=0;
+ virtual HRESULT __stdcall get_TuneRequest(
+ ITuneRequest** p_p_tune_request )=0;
+ virtual HRESULT __stdcall put_TuneRequest( ITuneRequest* p_tune_request )=0;
+ virtual HRESULT __stdcall Validate( ITuneRequest* p_tune_request )=0;
+ virtual HRESULT __stdcall get_PreferredComponentTypes(
+ IComponentTypes** p_p_cpt_types )=0;
+ virtual HRESULT __stdcall put_PreferredComponentTypes(
+ IComponentTypes* p_cpt_types )=0;
+ virtual HRESULT __stdcall get_SignalStrength( long* l_sig_strength )=0;
+ virtual HRESULT __stdcall TriggerSignalEvents( long l_interval )=0;
+};
+
+class ISampleGrabber : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall SetOneShot( BOOL b_one_shot )=0;
+ virtual HRESULT __stdcall SetMediaType(
+ const AM_MEDIA_TYPE* p_media_type )=0;
+ virtual HRESULT __stdcall GetConnectedMediaType(
+ AM_MEDIA_TYPE* p_media_type )=0;
+ virtual HRESULT __stdcall SetBufferSamples( BOOL b_buffer_samples )=0;
+ virtual HRESULT __stdcall GetCurrentBuffer( long* p_buff_size,
+ long* p_buffer )=0;
+ virtual HRESULT __stdcall GetCurrentSample( IMediaSample** p_p_sample )=0;
+ virtual HRESULT __stdcall SetCallback( ISampleGrabberCB* pf_callback,
+ long l_callback_type )=0;
+};
+
+class ISampleGrabberCB : public IUnknown
+{
+public:
+ virtual HRESULT __stdcall SampleCB( double d_sample_time,
+ IMediaSample* p_sample )=0;
+ virtual HRESULT __stdcall BufferCB( double d_sample_time, BYTE *p_buffer,
+ long l_bufferLen )=0;
+};
+
+class IScanningTuner : public ITuner
+{
+public:
+ virtual HRESULT __stdcall SeekUp( void )=0;
+ virtual HRESULT __stdcall SeekDown( void )=0;
+ virtual HRESULT __stdcall ScanDown( long l_pause )=0;
+ virtual HRESULT __stdcall ScanUp( long l_pause )=0;
+ virtual HRESULT __stdcall AutoProgram( void )=0;
+};
+
+class ITuneRequest : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_TuningSpace(
+ ITuningSpace** p_p_tuning_space )=0;
+ virtual HRESULT __stdcall get_Components( IComponents** p_p_components )=0;
+ virtual HRESULT __stdcall Clone( ITuneRequest** p_p_tune_request )=0;
+ virtual HRESULT __stdcall get_Locator( ILocator** p_p_locator )=0;
+ virtual HRESULT __stdcall put_Locator( ILocator* p_locator )=0;
+};
+
+class IChannelTuneRequest : public ITuneRequest
+{
+public:
+ virtual HRESULT __stdcall get_Channel( long* pl_channel )=0;
+ virtual HRESULT __stdcall put_Channel( long l_channel )=0;
+};
+
+class IATSCChannelTuneRequest : public IChannelTuneRequest
+{
+public:
+ virtual HRESULT __stdcall get_MinorChannel( long* pl_minor_channel )=0;
+ virtual HRESULT __stdcall put_MinorChannel( long l_minor_channel )=0;
+};
+
+class IDVBTuneRequest : public ITuneRequest
+{
+public:
+ virtual HRESULT __stdcall get_ONID( long* pl_onid )=0;
+ virtual HRESULT __stdcall put_ONID( long l_onid )=0;
+ virtual HRESULT __stdcall get_TSID( long* pl_tsid )=0;
+ virtual HRESULT __stdcall put_TSID( long l_tsid )=0;
+ virtual HRESULT __stdcall get_SID( long* pl_sid )=0;
+ virtual HRESULT __stdcall put_SID( long l_sid )=0;
+};
+
+class ILocator : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_CarrierFrequency( long* pl_frequency )=0;
+ virtual HRESULT __stdcall put_CarrierFrequency( long l_frequency )=0;
+ virtual HRESULT __stdcall get_InnerFEC( FECMethod* FEC )=0;
+ virtual HRESULT __stdcall put_InnerFEC( FECMethod FEC )=0;
+ virtual HRESULT __stdcall get_InnerFECRate(
+ BinaryConvolutionCodeRate* FEC )=0;
+ virtual HRESULT __stdcall put_InnerFECRate(
+ BinaryConvolutionCodeRate FEC )=0;
+ virtual HRESULT __stdcall get_OuterFEC( FECMethod* FEC )=0;
+ virtual HRESULT __stdcall put_OuterFEC( FECMethod FEC )=0;
+ virtual HRESULT __stdcall get_OuterFECRate(
+ BinaryConvolutionCodeRate* FEC )=0;
+ virtual HRESULT __stdcall put_OuterFECRate(
+ BinaryConvolutionCodeRate FEC )=0;
+ virtual HRESULT __stdcall get_Modulation( ModulationType* p_modulation )=0;
+ virtual HRESULT __stdcall put_Modulation( ModulationType modulation )=0;
+ virtual HRESULT __stdcall get_SymbolRate( long* pl_rate )=0;
+ virtual HRESULT __stdcall put_SymbolRate( long l_rate )=0;
+ virtual HRESULT __stdcall Clone( ILocator** p_p_locator )=0;
+};
+
+class IATSCLocator : public ILocator
+{
+public:
+ virtual HRESULT __stdcall get_PhysicalChannel( long* pl_phys_channel )=0;
+ virtual HRESULT __stdcall put_PhysicalChannel( long l_phys_channel )=0;
+ virtual HRESULT __stdcall get_TSID( long* pl_tsid )=0;
+ virtual HRESULT __stdcall put_TSID( long l_tsid )=0;
+};
+
+class IDVBCLocator : public ILocator
+{
+public:
+};
+
+class IDVBSLocator : public ILocator
+{
+public:
+ virtual HRESULT __stdcall get_SignalPolarisation(
+ Polarisation* p_polarisation )=0;
+ virtual HRESULT __stdcall put_SignalPolarisation(
+ Polarisation polarisation )=0;
+ virtual HRESULT __stdcall get_WestPosition( VARIANT_BOOL* pb_west )=0;
+ virtual HRESULT __stdcall put_WestPosition( VARIANT_BOOL b_west )=0;
+ virtual HRESULT __stdcall get_OrbitalPosition( long* pl_longitude )=0;
+ virtual HRESULT __stdcall put_OrbitalPosition( long l_longitude )=0;
+ virtual HRESULT __stdcall get_Azimuth( long* pl_azimuth )=0;
+ virtual HRESULT __stdcall put_Azimuth( long l_azimuth )=0;
+ virtual HRESULT __stdcall get_Elevation( long* pl_elevation )=0;
+ virtual HRESULT __stdcall put_Elevation( long l_elevation )=0;
+};
+
+class IDVBTLocator : public ILocator
+{
+public:
+ virtual HRESULT __stdcall get_Bandwidth( long* pl_bandwidth )=0;
+ virtual HRESULT __stdcall put_Bandwidth( long l_bandwidth )=0;
+ virtual HRESULT __stdcall get_LPInnerFEC( FECMethod* FEC )=0;
+ virtual HRESULT __stdcall put_LPInnerFEC( FECMethod FEC )=0;
+ virtual HRESULT __stdcall get_LPInnerFECRate(
+ BinaryConvolutionCodeRate* FEC )=0;
+ virtual HRESULT __stdcall put_LPInnerFECRate(
+ BinaryConvolutionCodeRate FEC )=0;
+ virtual HRESULT __stdcall get_HAlpha( HierarchyAlpha* Alpha )=0;
+ virtual HRESULT __stdcall put_HAlpha( HierarchyAlpha Alpha )=0;
+ virtual HRESULT __stdcall get_Guard( GuardInterval* GI )=0;
+ virtual HRESULT __stdcall put_Guard( GuardInterval GI )=0;
+ virtual HRESULT __stdcall get_Mode( TransmissionMode* mode )=0;
+ virtual HRESULT __stdcall put_Mode( TransmissionMode mode )=0;
+ virtual HRESULT __stdcall get_OtherFrequencyInUse(
+ VARIANT_BOOL* OtherFrequencyInUseVal )=0;
+ virtual HRESULT __stdcall put_OtherFrequencyInUse(
+ VARIANT_BOOL OtherFrequencyInUseVal )=0;
+};
+
+class ITuningSpace : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_UniqueName( BSTR* p_bstr_name )=0;
+ virtual HRESULT __stdcall put_UniqueName( BSTR Name )=0;
+ virtual HRESULT __stdcall get_FriendlyName( BSTR* p_bstr_name )=0;
+ virtual HRESULT __stdcall put_FriendlyName( BSTR bstr_name )=0;
+ virtual HRESULT __stdcall get_CLSID( BSTR* bstr_clsid )=0;
+ virtual HRESULT __stdcall get_NetworkType( BSTR* p_bstr_network_guid )=0;
+ virtual HRESULT __stdcall put_NetworkType( BSTR bstr_network_guid )=0;
+ virtual HRESULT __stdcall get__NetworkType( GUID* p_guid_network_guid )=0;
+ virtual HRESULT __stdcall put__NetworkType( REFCLSID clsid_network_guid )=0;
+ virtual HRESULT __stdcall CreateTuneRequest(
+ ITuneRequest** p_p_tune_request )=0;
+ virtual HRESULT __stdcall EnumCategoryGUIDs( IEnumGUID** p_p_enum )=0;
+ virtual HRESULT __stdcall EnumDeviceMonikers( IEnumMoniker** p_p_enum )=0;
+ virtual HRESULT __stdcall get_DefaultPreferredComponentTypes(
+ IComponentTypes** p_p_cpt_types )=0;
+ virtual HRESULT __stdcall put_DefaultPreferredComponentTypes(
+ IComponentTypes* p_cpt_types )=0;
+ virtual HRESULT __stdcall get_FrequencyMapping( BSTR* p_bstr_mapping )=0;
+ virtual HRESULT __stdcall put_FrequencyMapping( BSTR bstr_mapping )=0;
+ virtual HRESULT __stdcall get_DefaultLocator( ILocator** p_p_locator )=0;
+ virtual HRESULT __stdcall put_DefaultLocator( ILocator* p_locator )=0;
+ virtual HRESULT __stdcall Clone( ITuningSpace** p_p_tuning_space )=0;
+};
+
+class ITuningSpaceContainer : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_Count( long* l_count )=0;
+ virtual HRESULT __stdcall get__NewEnum( IEnumVARIANT** p_p_enum )=0;
+ virtual HRESULT __stdcall get_Item( VARIANT v_index,
+ ITuningSpace** p_p_tuning_space )=0;
+ virtual HRESULT __stdcall put_Item( VARIANT v_index,
+ ITuningSpace* p_tuning_space )=0;
+ virtual HRESULT __stdcall TuningSpacesForCLSID( BSTR bstr_clsid,
+ ITuningSpaces** p_p_tuning_spaces )=0;
+ virtual HRESULT __stdcall _TuningSpacesForCLSID( REFCLSID clsid,
+ ITuningSpaces** p_p_tuning_spaces )=0;
+ virtual HRESULT __stdcall TuningSpacesForName( BSTR bstr_name,
+ ITuningSpaces** p_p_tuning_spaces )=0;
+ virtual HRESULT __stdcall FindID( ITuningSpace* p_tuning_space,
+ long* l_id )=0;
+ virtual HRESULT __stdcall Add( ITuningSpace* p_tuning_space,
+ VARIANT* v_index )=0;
+ virtual HRESULT __stdcall get_EnumTuningSpaces(
+ IEnumTuningSpaces** p_p_enum )=0;
+ virtual HRESULT __stdcall Remove( VARIANT v_index )=0;
+ virtual HRESULT __stdcall get_MaxCount( long* l_maxcount )=0;
+ virtual HRESULT __stdcall put_MaxCount( long l_maxcount )=0;
+};
+
+class ITuningSpaces : public IDispatch
+{
+public:
+ virtual HRESULT __stdcall get_Count( long* l_count )=0;
+ virtual HRESULT __stdcall get__NewEnum( IEnumVARIANT** p_p_enum )=0;
+ virtual HRESULT __stdcall get_Item( VARIANT v_index,
+ ITuningSpace** p_p_tuning_space )=0;
+ virtual HRESULT __stdcall get_EnumTuningSpaces(
+ IEnumTuningSpaces** p_p_enum )=0;
+};
--- /dev/null
+/*****************************************************************************
+ * bdagraph.cpp : DirectShow BDA graph for vlc
+ *****************************************************************************
+ * Copyright( C ) 2007 the VideoLAN team
+ *
+ * Author: Ken Self <kens@campoz.fslife.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ *( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc_input.h>
+#include <vlc_access.h>
+
+/* Needed to call CoInitializeEx */
+#define _WIN32_DCOM
+
+/* Work-around a bug in w32api-2.5 */
+/*#ifndef _MSC_VER
+# define QACONTAINERFLAGS QACONTAINERFLAGS_SOMETHINGELSE
+#endif */
+
+#include "bdagraph.h"
+
+const GUID CLSID_ATSCLocator =
+ {0x8872FF1B,0x98FA,0x4D7A,{0x8D,0x93,0xC9,0xF1,0x05,0x5F,0x85,0xBB}};
+const GUID CLSID_ATSCNetworkProvider =
+ {0x0dad2fdd,0x5fd7,0x11d3,{0x8f,0x50,0x00,0xc0,0x4f,0x79,0x71,0xe2}};
+const GUID CLSID_DVBCLocator =
+ {0xc531d9fd,0x9685,0x4028,{0x8b,0x68,0x6e,0x12,0x32,0x07,0x9f,0x1e}};
+const GUID CLSID_DVBCNetworkProvider =
+ {0xdc0c0fe7,0x0485,0x4266,{0xb9,0x3f,0x68,0xfb,0xf8,0xe,0xd8,0x34}};
+const GUID CLSID_DVBSLocator =
+ {0x1df7d126,0x4050,0x47f0,{0xa7,0xcf,0x4c,0x4c,0xa9,0x24,0x13,0x33}};
+const GUID CLSID_DVBSNetworkProvider =
+ {0xfa4b375a,0x45b4,0x4d45,{0x84,0x40,0x26,0x39,0x57,0xb1,0x16,0x23}};
+const GUID CLSID_DVBSTuningSpace =
+ {0xb64016f3,0xc9a2,0x4066,{0x96,0xf0,0xbd,0x95,0x63,0x31,0x47,0x26}};
+const GUID CLSID_DVBTLocator =
+ {0x9cd64701,0xbdf3,0x4d14,{0x8e,0x03,0xf1,0x29,0x83,0xd8,0x66,0x64}};
+const GUID CLSID_DVBTNetworkProvider =
+ {0x216c62df,0x6d7f,0x4e9a,{0x85,0x71,0x05,0xf1,0x4e,0xdb,0x76,0x6a}};
+const GUID CLSID_FilterGraph =
+ {0xe436ebb3,0x524f,0x11ce,{0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
+const GUID CLSID_InfTee =
+ {0xf8388a40,0xd5bb,0x11d0,{0xbe,0x5a,0x00,0x80,0xc7,0x06,0x56,0x8e}};
+const GUID CLSID_MPEG2Demultiplexer =
+ {0xafb6c280,0x2c41,0x11d3,{0x8a,0x60,0x00,0x00,0xf8,0x1e,0x0e,0x4a}};
+const GUID CLSID_NullRenderer =
+ {0xc1f400a4,0x3f08,0x11d3,{0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37}};
+const GUID CLSID_SampleGrabber =
+ {0xc1f400a0,0x3f08,0x11d3,{0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37}};
+const GUID CLSID_SystemDeviceEnum =
+ {0x62be5d10,0x60eb,0x11d0,{0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86}};
+const GUID CLSID_SystemTuningSpaces =
+ {0xd02aac50,0x027e,0x11d3,{0x9d,0x8e,0x00,0xc0,0x4f,0x72,0xd9,0x80}};
+
+const GUID IID_IATSCChannelTuneRequest =
+ {0x0369B4E1,0x45B6,0x11d3,{0xB6,0x50,0x00,0xC0,0x4F,0x79,0x49,0x8E}};
+const GUID IID_IATSCLocator =
+ {0xbf8d986f,0x8c2b,0x4131,{0x94,0xd7,0x4d,0x3d,0x9f,0xcc,0x21,0xef}};
+const GUID IID_IBaseFilter =
+ {0x56a86895,0x0ad4,0x11ce,{0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
+const GUID IID_ICreateDevEnum =
+ {0x29840822,0x5b84,0x11d0,{0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86}};
+const GUID IID_IDVBTLocator =
+ {0x8664da16,0xdda2,0x42ac,{0x92,0x6a,0xc1,0x8f,0x91,0x27,0xc3,0x02}};
+const GUID IID_IDVBCLocator =
+ {0x6e42f36e,0x1dd2,0x43c4,{0x9f,0x78,0x69,0xd2,0x5a,0xe3,0x90,0x34}};
+const GUID IID_IDVBSLocator =
+ {0x3d7c353c,0x0d04,0x45f1,{0xa7,0x42,0xf9,0x7c,0xc1,0x18,0x8d,0xc8}};
+const GUID IID_IDVBSTuningSpace =
+ {0xcdf7be60,0xd954,0x42fd,{0xa9,0x72,0x78,0x97,0x19,0x58,0xe4,0x70}};
+const GUID IID_IDVBTuneRequest =
+ {0x0D6F567E,0xA636,0x42bb,{0x83,0xBA,0xCE,0x4C,0x17,0x04,0xAF,0xA2}};
+const GUID IID_IGraphBuilder =
+ {0x56a868a9,0x0ad4,0x11ce,{0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
+const GUID IID_IMediaControl =
+ {0x56a868b1,0x0ad4,0x11ce,{0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
+const GUID IID_IMpeg2Demultiplexer =
+ {0x436eee9c,0x264f,0x4242,{0x90,0xe1,0x4e,0x33,0x0c,0x10,0x75,0x12}};
+const GUID IID_ISampleGrabber =
+ {0x6b652fff,0x11fe,0x4fce,{0x92,0xad,0x02,0x66,0xb5,0xd7,0xc7,0x8f}};
+const GUID IID_IScanningTuner =
+ {0x1dfd0a5c,0x0284,0x11d3,{0x9d,0x8e,0x00,0xc0,0x4f,0x72,0xd9,0x80}};
+const GUID IID_ITuner =
+ {0x28C52640,0x018A,0x11d3,{0x9D,0x8E,0x00,0xC0,0x4F,0x72,0xD9,0x80}};
+const GUID IID_ITuningSpace =
+ {0x061c6e30,0xe622,0x11d2,{0x94,0x93,0x00,0xc0,0x4f,0x72,0xd9,0x80}};
+const GUID IID_ITuningSpaceContainer =
+ {0x5B692E84,0xE2F1,0x11d2,{0x94,0x93,0x00,0xC0,0x4F,0x72,0xD9,0x80}};
+
+const GUID KSCATEGORY_BDA_TRANSPORT_INFORMATION =
+ {0xa2e3074f,0x6c3d,0x11d3,{0xb6,0x53,0x00,0xc0,0x4f,0x79,0x49,0x8e}};
+const GUID KSCATEGORY_BDA_RECEIVER_COMPONENT =
+ {0xFD0A5AF4,0xB41D,0x11d2,{0x9c,0x95,0x00,0xc0,0x4f,0x79,0x71,0xe0}};
+const GUID KSCATEGORY_BDA_NETWORK_TUNER =
+ {0x71985f48,0x1ca1,0x11d3,{0x9c,0xc8,0x00,0xc0,0x4f,0x79,0x71,0xe0}};
+const GUID MEDIATYPE_MPEG2_SECTIONS =
+ {0x455f176c,0x4b06,0x47ce,{0x9a,0xef,0x8c,0xae,0xf7,0x3d,0xf7,0xb5}};
+const GUID MEDIASUBTYPE_None =
+ {0xe436eb8e,0x524f,0x11ce,{0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70}};
+const GUID FORMAT_None =
+ {0x0f6417d6,0xc318,0x11d0,{0xa4,0x3f,0x00,0xa0,0xc9,0x22,0x31,0x96}};
+
+/****************************************************************************
+ * Interfaces for calls from C
+ ****************************************************************************/
+extern "C" {
+
+ void dvb_newBDAGraph( access_t* p_access )
+ {
+ p_access->p_sys->p_bda_module = new BDAGraph( p_access );
+ };
+
+ void dvb_deleteBDAGraph( access_t* p_access )
+ {
+ delete p_access->p_sys->p_bda_module;
+ };
+
+ int dvb_SubmitATSCTuneRequest( access_t* p_access )
+ {
+ return p_access->p_sys->p_bda_module->SubmitATSCTuneRequest();
+ };
+
+ int dvb_SubmitDVBTTuneRequest( access_t* p_access )
+ {
+ return p_access->p_sys->p_bda_module->SubmitDVBTTuneRequest();
+ };
+
+ int dvb_SubmitDVBCTuneRequest( access_t* p_access )
+ {
+ return p_access->p_sys->p_bda_module->SubmitDVBCTuneRequest();
+ };
+
+ int dvb_SubmitDVBSTuneRequest( access_t* p_access )
+ {
+ return p_access->p_sys->p_bda_module->SubmitDVBSTuneRequest();
+ };
+
+ long dvb_GetBufferSize( access_t* p_access )
+ {
+ return p_access->p_sys->p_bda_module->GetBufferSize();
+ };
+
+ long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff )
+ {
+ return p_access->p_sys->p_bda_module->ReadBuffer( l_buffer_len,
+ p_buff );
+ };
+
+};
+
+/*****************************************************************************
+* Constructor
+*****************************************************************************/
+BDAGraph::BDAGraph( access_t* p_this ):
+ p_access( p_this ),
+ guid_network_type(GUID_NULL),
+ l_tuner_used(-1),
+ d_graph_register( 0 )
+{
+ p_tuning_space = NULL;
+ p_tune_request = NULL;
+ p_media_control = NULL;
+ p_filter_graph = NULL;
+ p_system_dev_enum = NULL;
+ p_network_provider = p_tuner_device = p_capture_device = NULL;
+ p_sample_grabber = p_mpeg_demux = p_transport_info = NULL;
+ p_scanning_tuner = NULL;
+ p_grabber = NULL;
+
+ /* Initialize COM - MS says to use CoInitializeEx in preference to
+ * CoInitialize */
+ CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
+}
+
+/*****************************************************************************
+* Destructor
+*****************************************************************************/
+BDAGraph::~BDAGraph()
+{
+ Destroy();
+ CoUninitialize();
+}
+
+/*****************************************************************************
+* Submit an ATSC Tune Request
+*****************************************************************************/
+int BDAGraph::SubmitATSCTuneRequest()
+{
+ HRESULT hr = S_OK;
+ class localComPtr
+ {
+ public:
+ IATSCChannelTuneRequest* p_atsc_tune_request;
+ IATSCLocator* p_atsc_locator;
+ localComPtr(): p_atsc_tune_request(NULL), p_atsc_locator(NULL) {};
+ ~localComPtr()
+ {
+ if( p_atsc_tune_request )
+ p_atsc_tune_request->Release();
+ if( p_atsc_locator )
+ p_atsc_locator->Release();
+ }
+ } l;
+ long l_major_channel, l_minor_channel, l_physical_channel;
+
+ l_major_channel = l_minor_channel = l_physical_channel = -1;
+/*
+ l_major_channel = var_GetInteger( p_access, "dvb-major-channel" );
+ l_minor_channel = var_GetInteger( p_access, "dvb-minor-channel" );
+ l_physical_channel = var_GetInteger( p_access, "dvb-physical-channel" );
+*/
+
+ guid_network_type = CLSID_ATSCNetworkProvider;
+ hr = CreateTuneRequest();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitATSCTuneRequest: "\
+ "Cannot create Tuning Space: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->QueryInterface( IID_IATSCChannelTuneRequest,
+ (void**)&l.p_atsc_tune_request );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitATSCTuneRequest: "\
+ "Cannot QI for IATSCChannelTuneRequest: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ hr = ::CoCreateInstance( CLSID_ATSCLocator, 0, CLSCTX_INPROC,
+ IID_IATSCLocator, (void**)&l.p_atsc_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitATSCTuneRequest: "\
+ "Cannot create the ATSC locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = S_OK;
+ if( l_major_channel > 0 )
+ hr = l.p_atsc_tune_request->put_Channel( l_major_channel );
+ if( SUCCEEDED( hr ) && l_minor_channel > 0 )
+ hr = l.p_atsc_tune_request->put_MinorChannel( l_minor_channel );
+ if( SUCCEEDED( hr ) && l_physical_channel > 0 )
+ hr = l.p_atsc_locator->put_PhysicalChannel( l_physical_channel );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitATSCTuneRequest: "\
+ "Cannot set tuning parameters: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->put_Locator( l.p_atsc_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitATSCTuneRequest: "\
+ "Cannot put the locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ /* Build and Run the Graph. If a Tuner device is in use the graph will
+ * fail to run. Repeated calls to build will check successive tuner
+ * devices */
+ do
+ {
+ hr = Build();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitATSCTuneRequest: "\
+ "Cannot Build the Graph: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ hr = Start();
+ }
+ while( hr != S_OK );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+* Submit a DVB-T Tune Request
+******************************************************************************/
+int BDAGraph::SubmitDVBTTuneRequest()
+{
+ HRESULT hr = S_OK;
+ class localComPtr
+ {
+ public:
+ IDVBTuneRequest* p_dvbt_tune_request;
+ IDVBTLocator* p_dvbt_locator;
+ localComPtr(): p_dvbt_tune_request(NULL), p_dvbt_locator(NULL) {};
+ ~localComPtr()
+ {
+ if( p_dvbt_tune_request )
+ p_dvbt_tune_request->Release();
+ if( p_dvbt_locator )
+ p_dvbt_locator->Release();
+ }
+ } l;
+ long l_frequency, l_bandwidth;
+
+ l_frequency = l_bandwidth = -1;
+ l_frequency = var_GetInteger( p_access, "dvb-frequency" );
+ l_bandwidth = var_GetInteger( p_access, "dvb-bandwidth" );
+
+ guid_network_type = CLSID_DVBTNetworkProvider;
+ hr = CreateTuneRequest();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
+ "Cannot create Tune Request: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
+ (void**)&l.p_dvbt_tune_request );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
+ "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ l.p_dvbt_tune_request->put_ONID( -1 );
+ l.p_dvbt_tune_request->put_SID( -1 );
+ l.p_dvbt_tune_request->put_TSID( -1 );
+
+ hr = ::CoCreateInstance( CLSID_DVBTLocator, 0, CLSCTX_INPROC,
+ IID_IDVBTLocator, (void**)&l.p_dvbt_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
+ "Cannot create the DVBT Locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = S_OK;
+ if( l_frequency > 0 )
+ hr = l.p_dvbt_locator->put_CarrierFrequency( l_frequency );
+ if( SUCCEEDED( hr ) && l_bandwidth > 0 )
+ hr = l.p_dvbt_locator->put_Bandwidth( l_bandwidth );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
+ "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->put_Locator( l.p_dvbt_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
+ "Cannot put the locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ /* Build and Run the Graph. If a Tuner device is in use the graph will
+ * fail to run. Repeated calls to build will check successive tuner
+ * devices */
+ do
+ {
+ hr = Build();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBTTuneRequest: "\
+ "Cannot Build the Graph: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ hr = Start();
+ }
+ while( hr != S_OK );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+* Submit a DVB-C Tune Request
+******************************************************************************/
+int BDAGraph::SubmitDVBCTuneRequest()
+{
+ HRESULT hr = S_OK;
+
+ class localComPtr
+ {
+ public:
+ IDVBTuneRequest* p_dvbc_tune_request;
+ IDVBCLocator* p_dvbc_locator;
+ localComPtr(): p_dvbc_tune_request(NULL), p_dvbc_locator(NULL) {};
+ ~localComPtr()
+ {
+ if( p_dvbc_tune_request )
+ p_dvbc_tune_request->Release();
+ if( p_dvbc_locator )
+ p_dvbc_locator->Release();
+ }
+ } l;
+
+ long l_frequency, l_symbolrate;
+ int i_qam;
+ ModulationType i_qam_mod;
+
+ l_frequency = l_symbolrate = i_qam = -1;
+ l_frequency = var_GetInteger( p_access, "dvb-frequency" );
+ l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
+ i_qam = var_GetInteger( p_access, "dvb-modulation" );
+ i_qam_mod = BDA_MOD_NOT_SET;
+ if( i_qam == 16 )
+ i_qam_mod = BDA_MOD_16QAM;
+ if( i_qam == 32 )
+ i_qam_mod = BDA_MOD_32QAM;
+ if( i_qam == 64 )
+ i_qam_mod = BDA_MOD_64QAM;
+ if( i_qam == 128 )
+ i_qam_mod = BDA_MOD_128QAM;
+ if( i_qam == 256 )
+ i_qam_mod = BDA_MOD_256QAM;
+
+ guid_network_type = CLSID_DVBCNetworkProvider;
+ hr = CreateTuneRequest();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot create Tune Request: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
+ (void**)&l.p_dvbc_tune_request );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ l.p_dvbc_tune_request->put_ONID( -1 );
+ l.p_dvbc_tune_request->put_SID( -1 );
+ l.p_dvbc_tune_request->put_TSID( -1 );
+
+ hr = ::CoCreateInstance( CLSID_DVBCLocator, 0, CLSCTX_INPROC,
+ IID_IDVBCLocator, (void**)&l.p_dvbc_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot create the DVB-C Locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = S_OK;
+ if( l_frequency > 0 )
+ hr = l.p_dvbc_locator->put_CarrierFrequency( l_frequency );
+ if( SUCCEEDED( hr ) && l_symbolrate > 0 )
+ hr = l.p_dvbc_locator->put_SymbolRate( l_symbolrate );
+ if( SUCCEEDED( hr ) && i_qam_mod != BDA_MOD_NOT_SET )
+ hr = l.p_dvbc_locator->put_Modulation( i_qam_mod );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->put_Locator( l.p_dvbc_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot put the locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ /* Build and Run the Graph. If a Tuner device is in use the graph will
+ * fail to run. Repeated calls to build will check successive tuner
+ * devices */
+ do
+ {
+ hr = Build();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot Build the Graph: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ hr = Start();
+ }
+ while( hr != S_OK );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+* Submit a DVB-S Tune Request
+******************************************************************************/
+int BDAGraph::SubmitDVBSTuneRequest()
+{
+ HRESULT hr = S_OK;
+
+ class localComPtr
+ {
+ public:
+ IDVBTuneRequest* p_dvbs_tune_request;
+ IDVBSLocator* p_dvbs_locator;
+ localComPtr(): p_dvbs_tune_request(NULL), p_dvbs_locator(NULL) {};
+ ~localComPtr()
+ {
+ if( p_dvbs_tune_request )
+ p_dvbs_tune_request->Release();
+ if( p_dvbs_locator )
+ p_dvbs_locator->Release();
+ }
+ } l;
+ long l_frequency, l_symbolrate, l_azimuth, l_elevation, l_longitude;
+ char* psz_polarisation;
+ Polarisation i_polar;
+ VARIANT_BOOL b_west;
+
+ l_frequency = l_symbolrate = l_azimuth = l_elevation = l_longitude = -1;
+ l_frequency = var_GetInteger( p_access, "dvb-frequency" );
+ l_symbolrate = var_GetInteger( p_access, "dvb-srate" );
+ l_azimuth = var_GetInteger( p_access, "dvb-azimuth" );
+ l_elevation = var_GetInteger( p_access, "dvb-elevation" );
+ l_longitude = var_GetInteger( p_access, "dvb-longitude" );
+ psz_polarisation = var_GetString( p_access, "dvb-polarisation" );
+
+ b_west = ( l_longitude < 0 ) ? TRUE : FALSE;
+
+ i_polar = BDA_POLARISATION_NOT_SET;
+ if( *psz_polarisation == 'H' || *psz_polarisation == 'h' )
+ i_polar = BDA_POLARISATION_LINEAR_H;
+ if( *psz_polarisation == 'V' || *psz_polarisation == 'v' )
+ i_polar = BDA_POLARISATION_LINEAR_V;
+ if( *psz_polarisation == 'L' || *psz_polarisation == 'l' )
+ i_polar = BDA_POLARISATION_CIRCULAR_L;
+ if( *psz_polarisation == 'R' || *psz_polarisation == 'r' )
+ i_polar = BDA_POLARISATION_CIRCULAR_R;
+
+ guid_network_type = CLSID_DVBSNetworkProvider;
+ hr = CreateTuneRequest();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot create Tune Request: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->QueryInterface( IID_IDVBTuneRequest,
+ (void**)&l.p_dvbs_tune_request );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot QI for IDVBTuneRequest: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ l.p_dvbs_tune_request->put_ONID( -1 );
+ l.p_dvbs_tune_request->put_SID( -1 );
+ l.p_dvbs_tune_request->put_TSID( -1 );
+
+ hr = ::CoCreateInstance( CLSID_DVBSLocator, 0, CLSCTX_INPROC,
+ IID_IDVBSLocator, (void**)&l.p_dvbs_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot create the DVBS Locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = S_OK;
+ if( l_frequency > 0 )
+ hr = l.p_dvbs_locator->put_CarrierFrequency( l_frequency );
+ if( SUCCEEDED( hr ) && l_symbolrate > 0 )
+ hr = l.p_dvbs_locator->put_SymbolRate( l_symbolrate );
+ if( SUCCEEDED( hr ) && l_azimuth > 0 )
+ hr = l.p_dvbs_locator->put_Azimuth( l_azimuth );
+ if( SUCCEEDED( hr ) && l_elevation > 0 )
+ hr = l.p_dvbs_locator->put_Elevation( l_elevation );
+ if( SUCCEEDED( hr ) )
+ hr = l.p_dvbs_locator->put_OrbitalPosition( labs( l_longitude ) );
+ if( SUCCEEDED( hr ) )
+ hr = l.p_dvbs_locator->put_WestPosition( b_west );
+ if( SUCCEEDED( hr ) && i_polar != BDA_POLARISATION_NOT_SET )
+ hr = l.p_dvbs_locator->put_SignalPolarisation( i_polar );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot set tuning parameters on Locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ hr = p_tune_request->put_Locator( l.p_dvbs_locator );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBCTuneRequest: "\
+ "Cannot put the locator: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+
+ /* Build and Run the Graph. If a Tuner device is in use the graph will
+ * fail to run. Repeated calls to build will check successive tuner
+ * devices */
+ do
+ {
+ hr = Build();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "SubmitDVBSTuneRequest: "\
+ "Cannot Build the Graph: hr=0x%8lx", hr );
+ return VLC_EGENERIC;
+ }
+ hr = Start();
+ }
+ while( hr != S_OK );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+* Load the Tuning Space from System Tuning Spaces according to the
+* Network Type requested
+******************************************************************************/
+HRESULT BDAGraph::CreateTuneRequest()
+{
+ HRESULT hr = S_OK;
+ GUID guid_this_network_type;
+ class localComPtr
+ {
+ public:
+ ITuningSpaceContainer* p_tuning_space_container;
+ IEnumTuningSpaces* p_tuning_space_enum;
+ ITuningSpace* p_this_tuning_space;
+ localComPtr(): p_tuning_space_container(NULL),
+ p_tuning_space_enum(NULL), p_this_tuning_space(NULL) {};
+ ~localComPtr()
+ {
+ if( p_tuning_space_container )
+ p_tuning_space_container->Release();
+ if( p_tuning_space_enum )
+ p_tuning_space_enum->Release();
+ if( p_this_tuning_space )
+ p_this_tuning_space->Release();
+ }
+ } l;
+
+ /* A Tuning Space may already have been set up. If it is for the same
+ * network type then all is well. Otherwise, reset the Tuning Space and get
+ * a new one */
+ if( p_tuning_space )
+ {
+ hr = p_tuning_space->get__NetworkType( &guid_this_network_type );
+ if( FAILED( hr ) ) guid_this_network_type = GUID_NULL;
+ if( guid_this_network_type == guid_network_type )
+ {
+ return S_OK;
+ }
+ else
+ {
+ p_tuning_space->Release();
+ p_tuning_space = NULL;
+ }
+ }
+
+ /* Force use of the first available Tuner Device during Build */
+ l_tuner_used = -1;
+
+ /* Get the SystemTuningSpaces container to enumerate through all the
+ * defined tuning spaces */
+ hr = ::CoCreateInstance( CLSID_SystemTuningSpaces, 0, CLSCTX_INPROC,
+ IID_ITuningSpaceContainer, (void**)&l.p_tuning_space_container );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "CreateTuneRequest: "\
+ "Cannot CoCreate SystemTuningSpaces: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = l.p_tuning_space_container->get_EnumTuningSpaces(
+ &l.p_tuning_space_enum );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "CreateTuneRequest: "\
+ "Cannot create SystemTuningSpaces Enumerator: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ while( l.p_tuning_space_enum->Next( 1, &l.p_this_tuning_space, NULL ) ==
+ S_OK )
+ {
+ hr = l.p_this_tuning_space->get__NetworkType( &guid_this_network_type );
+
+ /* GUID_NULL means a non-BDA network was found e.g analog
+ * Ignore failures and non-BDA networks and keep looking */
+ if( FAILED( hr ) ) guid_this_network_type == GUID_NULL;
+
+ if( guid_this_network_type == guid_network_type )
+ {
+ hr = l.p_this_tuning_space->QueryInterface( IID_ITuningSpace,
+ (void**)&p_tuning_space );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "CreateTuneRequest: "\
+ "Cannot QI Tuning Space: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = p_tuning_space->CreateTuneRequest( &p_tune_request );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "CreateTuneRequest: "\
+ "Cannot Create Tune Request: hr=0x%8lx", hr );
+ return hr;
+ }
+ return hr;
+ }
+ }
+ hr = E_FAIL;
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "CreateTuneRequest: "\
+ "Cannot find a suitable System Tuning Space: hr=0x%8lx", hr );
+ return hr;
+ }
+ return hr;
+}
+
+/******************************************************************************
+* Build
+* Step 4: Build the Filter Graph
+* Build sets up devices, adds and connects filters
+******************************************************************************/
+HRESULT BDAGraph::Build()
+{
+ HRESULT hr = S_OK;
+ long l_capture_used, l_tif_used;
+ AM_MEDIA_TYPE grabber_media_type;
+
+ /* If we have already have a filter graph, rebuild it*/
+ Destroy();
+
+ hr = ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
+ IID_IGraphBuilder, (void**)&p_filter_graph );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot CoCreate IFilterGraph: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ /* First filter in the graph is the Network Provider and
+ * its Scanning Tuner which takes the Tune Request*/
+ hr = ::CoCreateInstance( guid_network_type, NULL, CLSCTX_INPROC_SERVER,
+ IID_IBaseFilter, (void**)&p_network_provider);
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot CoCreate Network Provider: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = p_filter_graph->AddFilter( p_network_provider, L"Network Provider" );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot load network provider: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = p_network_provider->QueryInterface( IID_IScanningTuner,
+ (void**)&p_scanning_tuner );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot QI Network Provider for Scanning Tuner: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = p_scanning_tuner->Validate( p_tune_request );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Tune Request is invalid: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = p_scanning_tuner->put_TuneRequest( p_tune_request );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot submit the tune request: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ /* Add the Network Tuner to the Network Provider. On subsequent calls,
+ * l_tuner_used will cause a different tuner to be selected */
+ hr = FindFilter( KSCATEGORY_BDA_NETWORK_TUNER, &l_tuner_used,
+ p_network_provider, &p_tuner_device );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot load tuner device and connect network provider: "\
+ "hr=0x%8lx", hr );
+ return hr;
+ }
+
+ /* Always look for all capture devices to match the Network Tuner */
+ l_capture_used = -1;
+ hr = FindFilter( KSCATEGORY_BDA_RECEIVER_COMPONENT, &l_capture_used,
+ p_tuner_device, &p_capture_device );
+ if( FAILED( hr ) )
+ {
+ /* Some BDA drivers do not provide a Capture Device Filter so force
+ * the Sample Grabber to connect directly to the Tuner Device */
+ p_capture_device = p_tuner_device;
+ p_tuner_device = NULL;
+ msg_Warn( p_access, "Build: "\
+ "Cannot find Capture device. Connecting to tuner: hr=0x%8lx", hr );
+ }
+
+ /* Insert the Sample Grabber to tap into the Transport Stream. */
+ hr = ::CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
+ IID_IBaseFilter, (void**)&p_sample_grabber );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot load Sample Grabber Filter: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = p_filter_graph->AddFilter( p_sample_grabber, L"Sample Grabber" );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot add Sample Grabber Filter to graph: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = p_sample_grabber->QueryInterface( IID_ISampleGrabber,
+ (void**)&p_grabber );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot QI Sample Grabber Filter: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ ZeroMemory( &grabber_media_type, sizeof( AM_MEDIA_TYPE ) );
+ grabber_media_type.majortype == MEDIATYPE_Stream;
+ grabber_media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT;
+ hr = p_grabber->SetMediaType( &grabber_media_type );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot set media type on grabber filter: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = Connect( p_capture_device, p_sample_grabber );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot connect Sample Grabber to Capture device: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ /* We need the MPEG2 Demultiplexer even though we are going to use the VLC
+ * TS demuxer. The TIF filter connects to the MPEG2 demux and works with
+ * the Network Provider filter to set up the stream */
+ hr = ::CoCreateInstance( CLSID_MPEG2Demultiplexer, NULL,
+ CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&p_mpeg_demux );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot CoCreateInstance MPEG2 Demultiplexer: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = p_filter_graph->AddFilter( p_mpeg_demux, L"Demux" );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot add demux filter to graph: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = Connect( p_sample_grabber, p_mpeg_demux );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot connect demux to grabber: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ /* Always look for the Transform Information Filter from the start
+ * of the collection*/
+ l_tif_used = -1;
+ hr = FindFilter( KSCATEGORY_BDA_TRANSPORT_INFORMATION, &l_tif_used,
+ p_mpeg_demux, &p_transport_info );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot load TIF onto demux: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ /* Configure the Sample Grabber to buffer the samples continuously */
+ hr = p_grabber->SetBufferSamples( TRUE );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot set Sample Grabber to buffering: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = p_grabber->SetOneShot( FALSE );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot set Sample Grabber to multi shot: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = p_grabber->SetCallback( this, 0 );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot set SampleGrabber Callback: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = Register();
+ if( FAILED( hr ) )
+ {
+ d_graph_register = 0;
+ }
+
+ /* The Media Control is used to Run and Stop the Graph */
+ hr = p_filter_graph->QueryInterface( IID_IMediaControl,
+ (void**)&p_media_control );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Build: "\
+ "Cannot QI Media Control: hr=0x%8lx", hr );
+ return hr;
+ }
+ return hr;
+}
+
+/******************************************************************************
+* FindFilter
+* Looks up all filters in a category and connects to the upstream filter until
+* a successful match is found. The index of the connected filter is returned.
+* On subsequent calls, this can be used to start from that point to find
+* another match.
+* This is used when the graph does not run because a tuner device is in use so
+* another one needs to be slected.
+******************************************************************************/
+HRESULT BDAGraph::FindFilter( REFCLSID clsid, long* i_moniker_used,
+ IBaseFilter* p_upstream, IBaseFilter** p_p_downstream )
+{
+ HRESULT hr = S_OK;
+ int i_moniker_index = -1;
+ class localComPtr
+ {
+ public:
+ IMoniker* p_moniker;
+ IEnumMoniker* p_moniker_enum;
+ IBaseFilter* p_filter;
+ IPropertyBag* p_property_bag;
+ VARIANT var_bstr;
+ localComPtr():
+ p_moniker(NULL),
+ p_moniker_enum(NULL),
+ p_filter(NULL),
+ p_property_bag(NULL)
+ { ::VariantInit(&var_bstr); };
+ ~localComPtr()
+ {
+ if( p_moniker )
+ p_moniker->Release();
+ if( p_moniker_enum )
+ p_moniker_enum->Release();
+ if( p_filter )
+ p_filter->Release();
+ if( p_property_bag )
+ p_property_bag->Release();
+ ::VariantClear(&var_bstr);
+ }
+ } l;
+
+ if( !p_system_dev_enum )
+ {
+ hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC,
+ IID_ICreateDevEnum, (void**)&p_system_dev_enum );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "FindFilter: "\
+ "Cannot CoCreate SystemDeviceEnum: hr=0x%8lx", hr );
+ return hr;
+ }
+ }
+
+ hr = p_system_dev_enum->CreateClassEnumerator( clsid,
+ &l.p_moniker_enum, 0 );
+ if( hr != S_OK )
+ {
+ msg_Warn( p_access, "FindFilter: "\
+ "Cannot CreateClassEnumerator: hr=0x%8lx", hr );
+ return E_FAIL;
+ }
+ while( l.p_moniker_enum->Next( 1, &l.p_moniker, 0 ) == S_OK )
+ {
+ i_moniker_index++;
+
+ /* Skip over devices already found on previous calls */
+ if( i_moniker_index <= *i_moniker_used ) continue;
+ *i_moniker_used = i_moniker_index;
+
+ hr = l.p_moniker->BindToObject( NULL, NULL, IID_IBaseFilter,
+ (void**)&l.p_filter );
+ if( FAILED( hr ) )
+ {
+ if( l.p_moniker )
+ l.p_moniker->Release();
+ l.p_moniker = NULL;
+ if( l.p_filter)
+ l.p_filter->Release();
+ l.p_filter = NULL;
+ continue;
+ }
+
+ hr = l.p_moniker->BindToStorage( NULL, NULL, IID_IPropertyBag,
+ (void**)&l.p_property_bag );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "FindFilter: "\
+ "Cannot Bind to Property Bag: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = l.p_property_bag->Read( L"FriendlyName", &l.var_bstr, NULL );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "FindFilter: "\
+ "Cannot read filter friendly name: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = p_filter_graph->AddFilter( l.p_filter, l.var_bstr.bstrVal );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "FindFilter: "\
+ "Cannot add filter: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = Connect( p_upstream, l.p_filter );
+ if( SUCCEEDED( hr ) )
+ {
+ msg_Dbg( p_access, "FindFilter: Connected %S", l.var_bstr.bstrVal );
+ l.p_filter->QueryInterface( IID_IBaseFilter,
+ (void**)p_p_downstream );
+ return S_OK;
+ }
+ /* Not the filter we want so unload and try the next one */
+ hr = p_filter_graph->RemoveFilter( l.p_filter );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "FindFilter: "\
+ "Failed unloading Filter: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ if( l.p_moniker )
+ l.p_moniker->Release();
+ l.p_moniker = NULL;
+ if( l.p_filter)
+ l.p_filter->Release();
+ l.p_filter = NULL;
+ }
+
+ hr = E_FAIL;
+ msg_Warn( p_access, "FindFilter: No filter connected: hr=0x%8lx", hr );
+ return hr;
+}
+
+/*****************************************************************************
+* Connect is called from Build to enumerate and connect pins
+*****************************************************************************/
+HRESULT BDAGraph::Connect( IBaseFilter* p_upstream, IBaseFilter* p_downstream )
+{
+ HRESULT hr = E_FAIL;
+ class localComPtr
+ {
+ public:
+ IPin* p_pin_upstream;
+ IPin* p_pin_downstream;
+ IEnumPins* p_pin_upstream_enum;
+ IEnumPins* p_pin_downstream_enum;
+ IPin* p_pin_temp;
+ localComPtr(): p_pin_upstream(NULL), p_pin_downstream(NULL),
+ p_pin_upstream_enum(NULL), p_pin_downstream_enum(NULL),
+ p_pin_temp(NULL) { };
+ ~localComPtr()
+ {
+ if( p_pin_upstream )
+ p_pin_upstream->Release();
+ if( p_pin_downstream )
+ p_pin_downstream->Release();
+ if( p_pin_upstream_enum )
+ p_pin_upstream_enum->Release();
+ if( p_pin_downstream_enum )
+ p_pin_downstream_enum->Release();
+ if( p_pin_temp )
+ p_pin_temp->Release();
+ }
+ } l;
+
+ PIN_INFO pin_info_upstream;
+ PIN_INFO pin_info_downstream;
+
+ hr = p_upstream->EnumPins( &l.p_pin_upstream_enum );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Connect: "\
+ "Cannot get upstream filter enumerator: hr=0x%8lx", hr );
+ return hr;
+ }
+ while( l.p_pin_upstream_enum->Next( 1, &l.p_pin_upstream, 0 ) == S_OK )
+ {
+ hr = l.p_pin_upstream->QueryPinInfo( &pin_info_upstream );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Connect: "\
+ "Cannot get upstream filter pin information: hr=0x%8lx", hr );
+ return hr;
+ }
+ hr = l.p_pin_upstream->ConnectedTo( &l.p_pin_downstream );
+ if( hr == S_OK )
+ l.p_pin_downstream->Release();
+ if(FAILED( hr ) && hr != VFW_E_NOT_CONNECTED )
+ {
+ msg_Warn( p_access, "Connect: "\
+ "Cannot check upstream filter connection: hr=0x%8lx", hr );
+ return hr;
+ }
+ if(( pin_info_upstream.dir == PINDIR_OUTPUT ) &&
+ ( hr == VFW_E_NOT_CONNECTED ) )
+ {
+ /* The upstream pin is not yet connected so check each pin on the
+ * downstream filter */
+ hr = p_downstream->EnumPins( &l.p_pin_downstream_enum );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Connect: Cannot get "\
+ "downstream filter enumerator: hr=0x%8lx", hr );
+ return hr;
+ }
+ while( l.p_pin_downstream_enum->Next( 1, &l.p_pin_downstream, 0 )
+ == S_OK )
+ {
+ hr = l.p_pin_downstream->QueryPinInfo( &pin_info_downstream );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Connect: Cannot get "\
+ "downstream filter pin information: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ hr = l.p_pin_downstream->ConnectedTo( &l.p_pin_temp );
+ if( hr == S_OK ) l.p_pin_temp->Release();
+ if( hr != VFW_E_NOT_CONNECTED )
+ {
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Connect: Cannot check "\
+ "downstream filter connection: hr=0x%8lx", hr );
+ return hr;
+ }
+ }
+ if(( pin_info_downstream.dir == PINDIR_INPUT ) &&
+ ( hr == VFW_E_NOT_CONNECTED ) )
+ {
+ hr = p_filter_graph->ConnectDirect( l.p_pin_upstream,
+ l.p_pin_downstream, NULL );
+ if( SUCCEEDED( hr ) )
+ {
+ pin_info_downstream.pFilter->Release();
+ pin_info_upstream.pFilter->Release();
+ return S_OK;
+ }
+ }
+ /* If we fall out here it means this downstream pin was not
+ * suitable so try the next downstream pin */
+ l.p_pin_downstream = NULL;
+ pin_info_downstream.pFilter->Release();
+ }
+ }
+
+ /* If we fall out here it means we did not find any suitable downstream
+ * pin so try the next upstream pin */
+ l.p_pin_upstream = NULL;
+ pin_info_upstream.pFilter->Release();
+ }
+
+ /* If we fall out here it means we did not find any pair of suitable pins */
+ return E_FAIL;
+}
+
+/*****************************************************************************
+* Start uses MediaControl to start the graph
+*****************************************************************************/
+HRESULT BDAGraph::Start()
+{
+ HRESULT hr = S_OK;
+ OAFilterState i_state; /* State_Stopped, State_Paused, State_Running */
+
+ if( !p_media_control )
+ {
+ msg_Dbg( p_access, "Start: Media Control has not been created" );
+ return E_FAIL;
+ }
+ hr = p_media_control->Run();
+ if( hr == S_OK )
+ return hr;
+
+ /* Query the state of the graph - timeout after 100 milliseconds */
+ while( hr = p_media_control->GetState( 100, &i_state ) != S_OK )
+ {
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access,
+ "Start: Cannot get Graph state: hr=0x%8lx", hr );
+ return hr;
+ }
+ }
+ if( i_state == State_Running )
+ return hr;
+
+ /* The Graph is not running so stop it and return an error */
+ hr = p_media_control->Stop();
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access,
+ "Start: Cannot stop Graph after Run failed: hr=0x%8lx", hr );
+ return hr;
+ }
+ return E_FAIL;
+}
+
+/*****************************************************************************
+* Read the stream of data - query the buffer size required
+*****************************************************************************/
+long BDAGraph::GetBufferSize()
+{
+ while( queue_sample.empty() )
+ Sleep( 50 );
+
+ long l_buffer_size = 0;
+ long l_queue_size;
+
+ /* Establish the length of the queue as it grows quickly. If the queue
+ * size is checked dynamically there is a risk of not exiting the loop */
+ l_queue_size = queue_sample.size();
+ for( long l_queue_count=0; l_queue_count < l_queue_size; l_queue_count++ )
+ {
+ l_buffer_size += queue_sample.front()->GetActualDataLength();
+ queue_buffer.push( queue_sample.front() );
+ queue_sample.pop();
+ }
+ return l_buffer_size;
+}
+
+/*****************************************************************************
+* Read the stream of data - Retrieve from the buffer queue
+******************************************************************************/
+long BDAGraph::ReadBuffer( long* pl_buffer_len, BYTE* p_buffer )
+{
+ HRESULT hr = S_OK;
+
+ *pl_buffer_len = 0;
+ BYTE *p_buff_temp;
+
+ while( !queue_buffer.empty() )
+ {
+ queue_buffer.front()->GetPointer( &p_buff_temp );
+ hr = queue_buffer.front()->IsDiscontinuity();
+ if( hr == S_OK )
+ msg_Warn( p_access,
+ "BDA ReadBuffer: Sample Discontinuity. 0x%8lx", hr );
+ memcpy( p_buffer + *pl_buffer_len, p_buff_temp,
+ queue_buffer.front()->GetActualDataLength() );
+ *pl_buffer_len += queue_buffer.front()->GetActualDataLength();
+ queue_buffer.front()->Release();
+ queue_buffer.pop();
+ }
+
+ return *pl_buffer_len;
+}
+
+/******************************************************************************
+* SampleCB - Callback when the Sample Grabber has a sample
+******************************************************************************/
+STDMETHODIMP BDAGraph::SampleCB( double d_time, IMediaSample *p_sample )
+{
+ p_sample->AddRef();
+ queue_sample.push( p_sample );
+ return S_OK;
+}
+
+STDMETHODIMP BDAGraph::BufferCB( double d_time, BYTE* p_buffer,
+ long l_buffer_len )
+{
+ return E_FAIL;
+}
+
+/******************************************************************************
+* removes each filter from the graph
+******************************************************************************/
+HRESULT BDAGraph::Destroy()
+{
+ HRESULT hr = S_OK;
+
+ if( p_media_control )
+ hr = p_media_control->Stop();
+
+ if( p_transport_info )
+ {
+ p_filter_graph->RemoveFilter( p_transport_info );
+ p_transport_info->Release();
+ p_transport_info = NULL;
+ }
+ if( p_mpeg_demux )
+ {
+ p_filter_graph->RemoveFilter( p_mpeg_demux );
+ p_mpeg_demux->Release();
+ p_mpeg_demux = NULL;
+ }
+ if( p_sample_grabber )
+ {
+ p_filter_graph->RemoveFilter( p_sample_grabber );
+ p_sample_grabber->Release();
+ p_sample_grabber = NULL;
+ }
+ if( p_capture_device )
+ {
+ p_filter_graph->RemoveFilter( p_capture_device );
+ p_capture_device->Release();
+ p_capture_device = NULL;
+ }
+ if( p_tuner_device )
+ {
+ p_filter_graph->RemoveFilter( p_tuner_device );
+ p_tuner_device->Release();
+ p_tuner_device = NULL;
+ }
+ if( p_network_provider )
+ {
+ p_filter_graph->RemoveFilter( p_network_provider );
+ p_network_provider->Release();
+ p_network_provider = NULL;
+ }
+
+ if( p_scanning_tuner )
+ {
+ p_scanning_tuner->Release();
+ p_scanning_tuner = NULL;
+ }
+ if( p_media_control )
+ {
+ p_media_control->Release();
+ p_media_control = NULL;
+ }
+ if( p_scanning_tuner )
+ {
+ p_filter_graph->Release();
+ p_filter_graph = NULL;
+ }
+
+ if( d_graph_register )
+ {
+ Deregister();
+ }
+
+ return S_OK;
+}
+
+/*****************************************************************************
+* Add/Remove a DirectShow filter graph to/from the Running Object Table.
+* Allows GraphEdit to "spy" on a remote filter graph.
+******************************************************************************/
+HRESULT BDAGraph::Register()
+{
+ class localComPtr
+ {
+ public:
+ IMoniker* p_moniker;
+ IRunningObjectTable* p_ro_table;
+ localComPtr(): p_moniker(NULL), p_ro_table(NULL) {};
+ ~localComPtr()
+ {
+ if( p_moniker )
+ p_moniker->Release();
+ if( p_ro_table )
+ p_ro_table->Release();
+ }
+ } l;
+ WCHAR psz_w_graph_name[128];
+ HRESULT hr;
+
+ hr = ::GetRunningObjectTable( 0, &l.p_ro_table );
+ if( FAILED( hr ) )
+ {
+ msg_Warn( p_access, "Register: Cannot get ROT: hr=0x%8lx", hr );
+ return hr;
+ }
+
+ wsprintfW( psz_w_graph_name, L"VLC BDA Graph %08x Pid %08x",
+ (DWORD_PTR) p_filter_graph, ::GetCurrentProcessId() );
+ hr = CreateItemMoniker( L"!", psz_w_graph_name, &l.p_moniker );
+ if( SUCCEEDED( hr ) )
+ hr = l.p_ro_table->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE,
+ p_filter_graph, l.p_moniker, &d_graph_register );
+
+ return hr;
+}
+
+void BDAGraph::Deregister()
+{
+ IRunningObjectTable* p_ro_table;
+ if( SUCCEEDED( ::GetRunningObjectTable( 0, &p_ro_table ) ) )
+ p_ro_table->Revoke( d_graph_register );
+ d_graph_register = 0;
+ p_ro_table->Release();
+}