]> git.sesse.net Git - vlc/commitdiff
- the long awaited Windows BDA driver support for DVB/ATSC capture cards, courtesy...
authorDamien Fouilleul <damienf@videolan.org>
Mon, 23 Apr 2007 12:37:13 +0000 (12:37 +0000)
committerDamien Fouilleul <damienf@videolan.org>
Mon, 23 Apr 2007 12:37:13 +0000 (12:37 +0000)
configure.ac
modules/access/bda/Modules.am [new file with mode: 0644]
modules/access/bda/bda.c [new file with mode: 0644]
modules/access/bda/bda.h [new file with mode: 0644]
modules/access/bda/bdadefs.h [new file with mode: 0644]
modules/access/bda/bdagraph.cpp [new file with mode: 0644]
modules/access/bda/bdagraph.h [new file with mode: 0644]

index cb26b1981213cba010943fa01f7fe2cd466ef34b..ebb870a6f20a0c459ca529f62e5e2a8669162791 100644 (file)
@@ -1970,6 +1970,22 @@ then
   fi
 fi
 
+dnl
+dnl  Windows DirectShow BDA access module
+dnl
+AC_ARG_ENABLE(bda,
+  [  --enable-bda          Win32 DirectShow BDA support (default enabled on Win32)])
+if test "${enable_bda}" != "no"
+then
+  if test "${SYS}" = "mingw32" -o "${SYS}" = "cygwin"
+  then
+      AC_CHECK_HEADERS(dshow.h,
+      [ VLC_ADD_PLUGINS([bda])
+        VLC_ADD_CXXFLAGS([bda],[])
+        VLC_ADD_LDFLAGS([bda],[-lole32 -loleaut32 -luuid]) ])
+  fi
+fi
+
 
 dnl
 dnl  OpenCV wrapper and example filters
@@ -5794,6 +5810,7 @@ AC_CONFIG_FILES([
 
 AC_CONFIG_FILES([
   modules/access/Makefile
+  modules/access/bda/Makefile
   modules/access/dshow/Makefile
   modules/access/dvb/Makefile
   modules/access/mms/Makefile
diff --git a/modules/access/bda/Modules.am b/modules/access/bda/Modules.am
new file mode 100644 (file)
index 0000000..df038ce
--- /dev/null
@@ -0,0 +1 @@
+SOURCES_bda = bda.c bda.h bdagraph.h bdagraph.cpp bdadefs.h
diff --git a/modules/access/bda/bda.c b/modules/access/bda/bda.c
new file mode 100644 (file)
index 0000000..c1e753e
--- /dev/null
@@ -0,0 +1,514 @@
+/*****************************************************************************
+ * 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;
+}
diff --git a/modules/access/bda/bda.h b/modules/access/bda/bda.h
new file mode 100644 (file)
index 0000000..dc5d7d6
--- /dev/null
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * bda.h : DirectShow BDA access header 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
+ *****************************************************************************/
+#ifndef _MSC_VER
+#   include <wtypes.h>
+#   include <unknwn.h>
+#   include <ole2.h>
+#   include <limits.h>
+#   ifdef _WINGDI_
+#      undef _WINGDI_
+#   endif
+#   define _WINGDI_ 1
+#   define AM_NOVTABLE
+#   define _OBJBASE_H_
+#   undef _X86_
+#   define _I64_MAX LONG_LONG_MAX
+#   define LONGLONG long long
+#endif
+
+#ifdef __cplusplus
+class BDAGraph;
+extern "C" {
+#else
+typedef struct BDAGraph BDAGraph;
+#endif
+
+void dvb_newBDAGraph( access_t* p_access );
+void dvb_deleteBDAGraph( access_t* p_access );
+int dvb_SubmitATSCTuneRequest( access_t* p_access );
+int dvb_SubmitDVBTTuneRequest( access_t* p_access );
+int dvb_SubmitDVBCTuneRequest( access_t* p_access );
+int dvb_SubmitDVBSTuneRequest( access_t* p_access );
+long dvb_GetBufferSize( access_t* p_access );
+long dvb_ReadBuffer( access_t* p_access, long* l_buffer_len, BYTE* p_buff );
+
+#ifdef __cplusplus
+}
+#endif
+
+/****************************************************************************
+ * Access descriptor declaration
+ ****************************************************************************/
+struct access_sys_t
+{
+    /* These 2 must be left at the beginning */
+    vlc_mutex_t lock;
+    vlc_cond_t  wait;
+    BDAGraph *p_bda_module;
+};
+
diff --git a/modules/access/bda/bdadefs.h b/modules/access/bda/bdadefs.h
new file mode 100644 (file)
index 0000000..3f09543
--- /dev/null
@@ -0,0 +1,491 @@
+/*****************************************************************************
+ * 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;
+};
diff --git a/modules/access/bda/bdagraph.cpp b/modules/access/bda/bdagraph.cpp
new file mode 100644 (file)
index 0000000..f536923
--- /dev/null
@@ -0,0 +1,1443 @@
+/*****************************************************************************
+ * 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();
+}
diff --git a/modules/access/bda/bdagraph.h b/modules/access/bda/bdagraph.h
new file mode 100644 (file)
index 0000000..89f914a
--- /dev/null
@@ -0,0 +1,108 @@
+/*****************************************************************************
+ * bdagraph.h : DirectShow BDA graph builder header 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 <queue>
+
+using namespace std;
+#ifndef _MSC_VER
+#   include <wtypes.h>
+#   include <unknwn.h>
+#   include <ole2.h>
+#   include <limits.h>
+#   ifdef _WINGDI_
+#      undef _WINGDI_
+#   endif
+#   define _WINGDI_ 1
+#   define AM_NOVTABLE
+#   define _OBJBASE_H_
+#   undef _X86_
+#   define _I64_MAX LONG_LONG_MAX
+#   define LONGLONG long long
+#endif
+
+#include <dshow.h>
+#include <comcat.h>
+#include "bdadefs.h"
+#include "bda.h"
+
+/* The main class for building the filter graph */
+class BDAGraph : public ISampleGrabberCB
+{
+public:
+    BDAGraph( access_t* p_access );
+    virtual ~BDAGraph();
+
+    int SubmitATSCTuneRequest();
+    int SubmitDVBTTuneRequest();
+    int SubmitDVBCTuneRequest();
+    int SubmitDVBSTuneRequest();
+    long GetBufferSize();
+    long ReadBuffer( long* l_buffer_len, BYTE* p_buff );
+
+private:
+    /* ISampleGrabberCB methods */
+    STDMETHODIMP_( ULONG ) AddRef( ) { return 1; }
+    STDMETHODIMP_( ULONG ) Release( ) { return 2; }
+    STDMETHODIMP QueryInterface( REFIID riid, void** p_p_object )
+        {return E_NOTIMPL;  }
+    STDMETHODIMP SampleCB( double d_time, IMediaSample* p_sample );
+    STDMETHODIMP BufferCB( double d_time, BYTE* p_buffer, long l_buffer_len );
+
+    access_t* p_access;
+    CLSID     guid_network_type;
+    long      l_tuner_used;        /* Index of the Tuning Device */
+    /* registration number for the RunningObjectTable */
+    DWORD     d_graph_register;
+
+    queue<IMediaSample*> queue_sample;
+    queue<IMediaSample*> queue_buffer;
+
+    IMediaControl*  p_media_control;
+    IGraphBuilder*  p_filter_graph;
+    ITuningSpace*   p_tuning_space;
+    ITuneRequest*   p_tune_request;
+
+    ICreateDevEnum* p_system_dev_enum;
+    IBaseFilter*    p_network_provider;
+    IScanningTuner* p_scanning_tuner;
+    IBaseFilter*    p_tuner_device;
+    IBaseFilter*    p_capture_device;
+    IBaseFilter*    p_sample_grabber;
+    IBaseFilter*    p_mpeg_demux;
+    IBaseFilter*    p_transport_info;
+    ISampleGrabber* p_grabber;
+
+    HRESULT CreateTuneRequest( );
+    HRESULT Build( );
+    HRESULT FindFilter( REFCLSID clsid, long* i_moniker_used,
+        IBaseFilter* p_upstream, IBaseFilter** p_p_downstream );
+    HRESULT Connect( IBaseFilter* p_filter_upstream,
+        IBaseFilter* p_filter_downstream );
+    HRESULT Start( );
+    HRESULT Destroy( );
+    HRESULT Register( );
+    void Deregister( );
+};
+