]> git.sesse.net Git - vlc/blobdiff - modules/access/satellite/access.c
* Spelling fixes.
[vlc] / modules / access / satellite / access.c
index fc32d9399b80a6b7e48d23b0cdaa998093fb4bff..23819a02e78f6b11a259bccf103c31fb8ab8b821 100644 (file)
@@ -1,9 +1,10 @@
 /*****************************************************************************
  * access.c: Satellite card input
  *****************************************************************************
- * Copyright (C) 1998-2002 VideoLAN
+ * Copyright (C) 1998-2003 VideoLAN
  *
  * Authors: Johan Bilien <jobi@via.ecp.fr>
+ *          Christophe Massiot <massiot@via.ecp.fr>
  *
  * 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
 
 #include "dvb.h"
 
-#define SATELLITE_READ_ONCE 3
+/* These are for the Dreambox port. I have no idea whether they're correct
+ * for other DVB adapters. --Meuuh */
+#define SATELLITE_READ_ONCE (64 * 1024)
+#define DMX_BUFFER_SIZE (1024 * 1024)
 
 /*****************************************************************************
  * Local prototypes
@@ -58,16 +62,74 @@ static int     SatelliteSetArea    ( input_thread_t *, input_area_t * );
 static int     SatelliteSetProgram ( input_thread_t *, pgrm_descriptor_t * );
 static void    SatelliteSeek       ( input_thread_t *, off_t );
 
+typedef struct demux_handle_t
+{
+    int i_pid;
+    int i_handle;
+    int i_type;
+} demux_handle_t;
+
+#define PAT_TYPE 1
+#define PMT_TYPE 2
+#define ES_TYPE 3
+
+#define MAX_DEMUX 8 
+
+typedef struct thread_sat_data_t
+{
+    int i_handle;
+    demux_handle_t p_demux_handles[MAX_DEMUX];
+} thread_sat_data_t;
+
+static void AllocateDemux( input_thread_t * p_input, int i_pid,
+                           int i_type )
+{
+    thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
+    int                 i_demux;
+    int                 i;
+    i_demux = config_GetInt( p_input, "dvb-dmx" );
+
+    /* Find first free slot */
+    for ( i = 0; i < MAX_DEMUX; i++ )
+    {
+        if ( !p_satellite->p_demux_handles[i].i_type )
+        {
+            if (ioctl_SetDMXFilter( i_demux, i_pid, &p_satellite->p_demux_handles[i].i_handle, 3) < 0)
+            {
+                msg_Warn(p_input, "ioctl_SetDMXFilter failed (%d)", i_pid);
+                break;
+            }
+            p_satellite->p_demux_handles[i].i_type = i_type;
+            p_satellite->p_demux_handles[i].i_pid = i_pid;
+            break;
+        }
+    }
+}
+
+static void CloseProgram( input_thread_t * p_input )
+{
+    thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
+    int i;
+
+    for ( i = 1; i < MAX_DEMUX; i++ )
+    {
+        if ( p_satellite->p_demux_handles[i].i_type )
+        {
+            ioctl_UnsetDMXFilter( p_satellite->p_demux_handles[i].i_handle );
+            p_satellite->p_demux_handles[i].i_type = 0;
+        }
+    }
+}
+
 /*****************************************************************************
  * Open: open the dvr device
  *****************************************************************************/
 int E_(Open) ( vlc_object_t *p_this )
 {
     input_thread_t *    p_input = (input_thread_t *)p_this;
-    input_socket_t *    p_satellite;
+    thread_sat_data_t * p_satellite;
     char *              psz_parser;
     char *              psz_next;
-    int                 i_fd = 0;
     int                 i_freq = 0;
     int                 i_srate = 0;
     vlc_bool_t          b_pol = 0;
@@ -77,6 +139,10 @@ int E_(Open) ( vlc_object_t *p_this )
     int                 i_lnb_lof1;
     int                 i_lnb_lof2;
     int                 i_lnb_slof;
+    int                 i_demux;
+    char                psz_dvr[255];
+    i_demux = config_GetInt( p_input, "dvb-dmx" );
+    snprintf(psz_dvr, sizeof(psz_dvr), DVR "%d", i_demux);
 
     /* parse the options passed in command line : */
 
@@ -111,29 +177,29 @@ int E_(Open) ( vlc_object_t *p_this )
 
     }
 
-    if( i_freq > 12999 || i_freq < 10000 )
+    if( i_freq > (12999*1000) || i_freq < (10000*1000) )
     {
         msg_Warn( p_input, "invalid frequency, using default one" );
         i_freq = config_GetInt( p_input, "frequency" );
-        if( i_freq > 12999 || i_freq < 10000 )
+        if( i_freq && (i_freq > (12999*1000) || i_freq < (10000*1000)) )
         {
             msg_Err( p_input, "invalid default frequency" );
             return -1;
         }
     }
 
-    if( i_srate > 30000 || i_srate < 1000 )
+    if( i_freq && (i_srate > (30000*1000) || i_srate < (1000*1000)) )
     {
         msg_Warn( p_input, "invalid symbol rate, using default one" );
         i_srate = config_GetInt( p_input, "symbol-rate" );
-        if( i_srate > 30000 || i_srate < 1000 )
+        if( i_srate > (30000*1000) || i_srate < (1000*1000) )
         {
             msg_Err( p_input, "invalid default symbol rate" );
             return -1;
         }
     }
 
-    if( b_pol && b_pol != 1 )
+    if( i_freq && b_pol && b_pol != 1 )
     {
         msg_Warn( p_input, "invalid polarization, using default one" );
         b_pol = config_GetInt( p_input, "polarization" );
@@ -144,7 +210,7 @@ int E_(Open) ( vlc_object_t *p_this )
         }
     }
 
-    if( i_fec > 7 || i_fec < 1 )
+    if( i_freq && (i_fec > 7 || i_fec < 1) )
     {
         msg_Warn( p_input, "invalid FEC, using default one" );
         i_fec = config_GetInt( p_input, "fec" );
@@ -155,57 +221,65 @@ int E_(Open) ( vlc_object_t *p_this )
         }
     }
 
-    switch( i_fec )
+    if ( i_freq )
     {
-        case 1:
-            f_fec = 1./2;
-            break;
-        case 2:
-            f_fec = 2./3;
-            break;
-        case 3:
-            f_fec = 3./4;
-            break;
-        case 4:
-            f_fec = 4./5;
-            break;
-        case 5:
-            f_fec = 5./6;
-            break;
-        case 6:
-            f_fec = 6./7;
-            break;
-        case 7:
-            f_fec = 7./8;
-            break;
-        default:
-            /* cannot happen */
-            break;
+        switch( i_fec )
+        {
+            case 1:
+                f_fec = 1./2;
+                break;
+            case 2:
+                f_fec = 2./3;
+                break;
+            case 3:
+                f_fec = 3./4;
+                break;
+            case 4:
+                f_fec = 4./5;
+                break;
+            case 5:
+                f_fec = 5./6;
+                break;
+            case 6:
+                f_fec = 6./7;
+                break;
+            case 7:
+                f_fec = 7./8;
+                break;
+            default:
+                /* cannot happen */
+                break;
+        }
     }
 
 
     /* Initialise structure */
-    p_satellite = malloc( sizeof( input_socket_t ) );
+    p_satellite = malloc( sizeof( thread_sat_data_t ) );
 
     if( p_satellite == NULL )
     {
         msg_Err( p_input, "out of memory" );
         return -1;
     }
+    memset( p_satellite, 0, sizeof( thread_sat_data_t ) );
 
     p_input->p_access_data = (void *)p_satellite;
 
     /* Open the DVR device */
-    msg_Dbg( p_input, "opening DVR device `%s'", DVR );
+    msg_Dbg( p_input, "opening DVR device `%s'", psz_dvr );
 
-    if( (p_satellite->i_handle = open( DVR,
+    if( (p_satellite->i_handle = open( psz_dvr,
                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
     {
-        msg_Warn( p_input, "cannot open `%s' (%s)", DVR, strerror(errno) );
+        msg_Warn( p_input, "cannot open `%s' (%s)", psz_dvr, strerror(errno) );
         free( p_satellite );
         return -1;
     }
 
+    /* FIXME : this is from the Dreambox port. I have no idea whether it
+     * hurts or helps other DVB interfaces, so I just leave it here.
+     * Feel free to remove it if it breaks. --Meuuh */
+    ioctl_SetBufferSize( p_satellite->i_handle, DMX_BUFFER_SIZE );
 
     /* Get antenna configuration options */
     b_diseqc = config_GetInt( p_input, "diseqc" );
@@ -215,65 +289,62 @@ int E_(Open) ( vlc_object_t *p_this )
 
     /* Initialize the Satellite Card */
 
-    msg_Dbg( p_input, "initializing Sat Card with Freq: %d, Pol: %d, "
-                      "FEC: %03f, Srate: %d", i_freq, b_pol, f_fec, i_srate );
-
-    if ( ioctl_SECControl( i_freq * 1000, b_pol, i_lnb_slof * 1000,
-                b_diseqc ) < 0 )
+    if ( i_freq )
     {
-        msg_Err( p_input, "an error occured when controling SEC" );
-        close( p_satellite->i_handle );
-        free( p_satellite );
-        return -1;
-    }
+        int i_tuner = config_GetInt( p_input, "dvb-tuner" );
 
-    msg_Dbg( p_input, "initializing frontend device" );
-    switch (ioctl_SetQPSKFrontend ( i_freq * 1000, i_srate* 1000, f_fec,
-                i_lnb_lof1 * 1000, i_lnb_lof2 * 1000, i_lnb_slof * 1000))
-    {
-        case -2:
-            msg_Err( p_input, "frontend returned an unexpected event" );
-            close( p_satellite->i_handle );
-            free( p_satellite );
-            return -1;
-            break;
-        case -3:
-            msg_Err( p_input, "frontend returned no event" );
-            close( p_satellite->i_handle );
-            free( p_satellite );
-            return -1;
-            break;
-        case -4:
-            msg_Err( p_input, "frontend: timeout when polling for event" );
-            close( p_satellite->i_handle );
-            free( p_satellite );
-            return -1;
-            break;
-        case -5:
-            msg_Err( p_input, "an error occured when polling frontend device" );
-            close( p_satellite->i_handle );
-            free( p_satellite );
-            return -1;
-            break;
-        case -1:
-            msg_Err( p_input, "frontend returned a failure event" );
+        msg_Dbg( p_input, "initializing Sat Card with Freq: %d, Pol: %d, "
+                          "FEC: %03f, Srate: %d", i_freq, b_pol, f_fec, i_srate );
+
+        if ( ioctl_SECControl( i_tuner, i_freq, b_pol, i_lnb_slof, b_diseqc ) < 0 )
+        {
+            msg_Err( p_input, "an error occurred when controling SEC" );
             close( p_satellite->i_handle );
             free( p_satellite );
             return -1;
-            break;
-        default:
-            break;
-    }
+        }
 
-    msg_Dbg( p_input, "setting filter on PAT" );
+        msg_Dbg( p_input, "initializing frontend device" );
+        switch (ioctl_SetQPSKFrontend ( i_tuner, i_freq, i_srate, f_fec,
+                    i_lnb_lof1, i_lnb_lof2, i_lnb_slof))
+        {
+            case -2:
+                msg_Err( p_input, "frontend returned an unexpected event" );
+                close( p_satellite->i_handle );
+                free( p_satellite );
+                return -1;
+                break;
+            case -3:
+                msg_Err( p_input, "frontend returned no event" );
+                close( p_satellite->i_handle );
+                free( p_satellite );
+                return -1;
+                break;
+            case -4:
+                msg_Err( p_input, "frontend: timeout when polling for event" );
+                close( p_satellite->i_handle );
+                free( p_satellite );
+                return -1;
+                break;
+            case -5:
+                msg_Err( p_input, "an error occured when polling frontend device" );
+                close( p_satellite->i_handle );
+                free( p_satellite );
+                return -1;
+                break;
+            case -1:
+                msg_Err( p_input, "frontend returned a failure event" );
+                close( p_satellite->i_handle );
+                free( p_satellite );
+                return -1;
+                break;
+            default:
+                break;
+        }
+    } /* i_freq */
 
-    if ( ioctl_SetDMXFilter( 0, &i_fd, 3 ) < 0 )
-    {
-        msg_Err( p_input, "an error occured when setting filter on PAT" );
-        close( p_satellite->i_handle );
-        free( p_satellite );
-        return -1;
-    }
+    msg_Dbg( p_input, "setting filter on PAT" );
+    AllocateDemux( p_input, 0, PAT_TYPE );
 
     if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
     {
@@ -291,7 +362,7 @@ int E_(Open) ( vlc_object_t *p_this )
 
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    p_input->i_mtu = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
+    p_input->i_mtu = SATELLITE_READ_ONCE;
     p_input->stream.i_method = INPUT_METHOD_SATELLITE;
 
     return 0;
@@ -303,57 +374,62 @@ int E_(Open) ( vlc_object_t *p_this )
 void E_(Close) ( vlc_object_t *p_this )
 {
     input_thread_t *    p_input = (input_thread_t *)p_this;
-    input_socket_t *    p_satellite;
-    int                 i_es_index;
+    thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
 
-    if ( p_input->stream.p_selected_program )
-    {
-        for ( i_es_index = 1 ;
-                i_es_index < p_input->stream.p_selected_program->
-                    i_es_number ;
-                i_es_index ++ )
-        {
-#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
-            if ( p_es->p_decoder_fifo )
-            {
-                ioctl_UnsetDMXFilter( p_es->i_demux_fd );
-            }
-#undef p_es
-        }
-    }
+    msg_Dbg( p_input, "unsetting filters on all pids" );
+    CloseProgram( p_input );
+    close( p_satellite->p_demux_handles[0].i_handle );
 
-    p_satellite = (input_socket_t *)p_input;
     close( p_satellite->i_handle );
 }
 
-
 /*****************************************************************************
  * SatelliteRead: reads data from the satellite card
  *****************************************************************************/
 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
-                size_t i_len )
+                              size_t i_len )
 {
-    int i;
+    thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
+    ssize_t i_ret;
+
+    unsigned int i;
 
     /* if not set, set filters to the PMTs */
-    for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
+    /* This is kludgy and consumes way too much CPU power - the access
+     * module should have a callback from the demux when a new program
+     * is encountered. --Meuuh */
+    if ( !p_satellite->p_demux_handles[1].i_type )
     {
-        if ( p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd == 0 )
+        int i_program = config_GetInt( p_input, "program" );
+
+        for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
         {
-            msg_Dbg( p_input, "setting filter on pmt pid %d",
-                     p_input->stream.pp_programs[i]->pp_es[0]->i_id );
-            ioctl_SetDMXFilter( p_input->stream.pp_programs[i]->pp_es[0]->i_id,
-                       &p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd,
-                       3 );
+            /* Only set a filter on the selected program : some boards
+             * (read: Dreambox) only have 8 filters, so you don't want to
+             * spend them on unwanted PMTs. --Meuuh */
+            if ( (!i_program || p_input->stream.pp_programs[i]->i_number == i_program) )
+            {
+                msg_Dbg( p_input, "setting filter on PMT pid %d",
+                         p_input->stream.pp_programs[i]->pp_es[0]->i_id );
+                AllocateDemux( p_input, p_input->stream.pp_programs[i]->pp_es[0]->i_id, PMT_TYPE );
+            }
         }
     }
 
-    return input_FDRead( p_input, p_buffer, i_len );
+    i_ret = read( p_satellite->i_handle, p_buffer, i_len );
+    if( i_ret < 0 )
+    {
+#   ifdef HAVE_ERRNO_H
+        msg_Err( p_input, "read failed (%s)", strerror(errno) );
+#   else
+        msg_Err( p_input, "read failed" );
+#   endif
+    }
+    return i_ret;
 }
 
-
-
-
 /*****************************************************************************
  * SatelliteSetArea : Does nothing
  *****************************************************************************/
@@ -370,53 +446,70 @@ static int SatelliteSetArea( input_thread_t * p_input, input_area_t * p_area )
 int SatelliteSetProgram( input_thread_t    * p_input,
                          pgrm_descriptor_t * p_new_prg )
 {
-    int                 i_es_index;
+    unsigned int i_es_index;
+    vlc_value_t val;
 
     if ( p_input->stream.p_selected_program )
     {
-        for ( i_es_index = 1 ; /* 0 should be the PMT */
+        for ( i_es_index = 0 ; /* 0 should be the PMT */
                 i_es_index < p_input->stream.p_selected_program->
                     i_es_number ;
                 i_es_index ++ )
         {
 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
-            if ( p_es->p_decoder_fifo )
+            if ( p_es->p_dec )
             {
                 input_UnselectES( p_input , p_es );
             }
-            if ( p_es->i_demux_fd )
-            {
-                ioctl_UnsetDMXFilter( p_es->i_demux_fd );
-                p_es->i_demux_fd = 0;
-            }
 #undef p_es
         }
     }
 
-    for (i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
+    msg_Dbg( p_input, "unsetting filters on all pids" );
+    CloseProgram( p_input );
+    msg_Dbg( p_input, "setting filter on PMT pid %d",
+             p_new_prg->pp_es[0]->i_id );
+    AllocateDemux( p_input, p_new_prg->pp_es[0]->i_id, PMT_TYPE );
+
+    for ( i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
     {
 #define p_es p_new_prg->pp_es[i_es_index]
         switch( p_es->i_cat )
         {
-            case MPEG1_VIDEO_ES:
-            case MPEG2_VIDEO_ES:
-                if ( config_GetInt( p_input, "video" ) )
-                {
-                    ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 1);
-                    input_SelectES( p_input , p_es );
-                }
+            case VIDEO_ES:
+                msg_Dbg(p_input, "setting filter on video ES 0x%x",
+                        p_es->i_id);
+                /* Always set the filter. This may seem a little odd, but
+                 * it allows you to stream the video with demuxstream
+                 * without having a decoder or a stream output behind.
+                 * The result is you'll sometimes filter a PID which you
+                 * don't really want, but in the most common cases it
+                 * should be OK. --Meuuh */
+                AllocateDemux( p_input, p_es->i_id, ES_TYPE );
+                input_SelectES( p_input , p_es );
                 break;
-            case MPEG1_AUDIO_ES:
-            case MPEG2_AUDIO_ES:
-                if ( config_GetInt( p_input, "audio" ) )
-                {
-                    ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 2);
-                    input_SelectES( p_input , p_es );
-                }
+
+            case AUDIO_ES:
+                msg_Dbg(p_input, "setting filter on audio ES 0x%x",
+                        p_es->i_id);
+                AllocateDemux( p_input, p_es->i_id, ES_TYPE );
+                input_SelectES( p_input , p_es );
                 break;
+
             default:
-                ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 3);
+                /* Do not select private streams. This is to avoid the
+                 * limit of 8 filters on the Dreambox and possibly on
+                 * other boards. We should probably change that to
+                 * have the DVB subtitles, but filtering all private
+                 * streams including DVB tables and padding seems
+                 * nonsense to me. --Meuuh */
+#if 0
+                msg_Dbg(p_input, "setting filter on misc (0x%x) ES 0x%x",
+                        p_es->i_cat,
+                        p_es->i_id);
+                AllocateDemux( p_input, p_es->i_id, ES_TYPE );
                 input_SelectES( p_input , p_es );
+#endif
                 break;
 #undef p_es
         }
@@ -424,7 +517,11 @@ int SatelliteSetProgram( input_thread_t    * p_input,
 
     p_input->stream.p_selected_program = p_new_prg;
 
-    return( 0 );
+    /* Update the navigation variables without triggering a callback */
+    val.i_int = p_new_prg->i_number;
+    var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
+
+    return 0;
 }
 
 /*****************************************************************************
@@ -432,5 +529,6 @@ int SatelliteSetProgram( input_thread_t    * p_input,
  *****************************************************************************/
 static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
 {
-    return;
+    ;
 }
+