]> git.sesse.net Git - vlc/blobdiff - modules/access/dvb/scan.c
Replaced a %d with PRId64 in dvb access.
[vlc] / modules / access / dvb / scan.c
index 1e4d39b058d2fb230f9a11e3fbe5d8155ccb6dfd..626dbf2823e840b35f80bc1efde9a4820f6d77fd 100644 (file)
@@ -1,9 +1,10 @@
 /*****************************************************************************
  * scan.c: DVB scanner helpers
  *****************************************************************************
- * Copyright (C) 2008 the VideoLAN team
+ * Copyright (C) 2008,2010 the VideoLAN team
  *
  * Authors: Laurent Aimar <fenrir@videolan.org>
+ *          David Kaplan <david@2of1.org>
  *
  * 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 <vlc_plugin.h>
 #include <vlc_access.h>
 #include <vlc_dialog.h>
+#include <vlc_fs.h>
 
 #ifdef HAVE_UNISTD_H
 #   include <unistd.h>
 #endif
 
-#include <fcntl.h>
 #include <sys/types.h>
-#include <sys/poll.h>
-
-#include <errno.h>
+#include <poll.h>
 
 /* Include dvbpsi headers */
 #ifdef HAVE_DVBPSI_DR_H
@@ -119,10 +118,17 @@ int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_pa
                  p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
         msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
     }
+    else if( p_parameter->type == SCAN_DVB_S )
+    {
+        msg_Dbg( p_obj, "DVB-S scanning:" );
+        msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
+    }
     else
     {
         return VLC_EGENERIC;
     }
+    msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
+    msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
 
     p_scan->p_obj = VLC_OBJECT(p_obj);
     p_scan->i_index = 0;
@@ -133,6 +139,7 @@ int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_pa
 
     return VLC_SUCCESS;
 }
+
 void scan_Clean( scan_t *p_scan )
 {
     if( p_scan->p_dialog != NULL )
@@ -143,35 +150,195 @@ void scan_Clean( scan_t *p_scan )
     TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
 }
 
-static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
+static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
 {
     msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
-    if( p_scan->i_index <= ( 10 ) )
-    {
-        p_cfg->i_frequency = 100500000 + ( ( p_scan->i_index ) * 700000);
-    } 
-    else if ( p_scan->i_index <= (10 + 9  ) )
+
+    int *pi_count = &p_scan->parameter.sat_info.i_count;
+
+    if( !p_scan->parameter.sat_info.psz_name )
     {
-        p_cfg->i_frequency = 97000000 + ( ( p_scan->i_index - 20 ) * 800000);
+        msg_Err( p_scan->p_obj, "no satellite selected" );
+        return VLC_EGENERIC;
     }
-    else if ( p_scan->i_index <= (38 + 17 ) )
+
+    /* if there are no transponders in mem, laod from config file */
+    if( !*pi_count )
     {
-        p_cfg->i_frequency = 14250000 + ( ( p_scan->i_index - 33 ) * 700000);
+        scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
+
+        DIR *p_dir;
+
+        char *psz_dir = NULL;
+        char *data_dir = config_GetDataDir( p_scan->p_obj );
+
+        if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
+            psz_dir = NULL;
+        free( data_dir );
+
+        if( !psz_dir )
+        {
+            free( p_scan->parameter.sat_info.psz_name );
+            return VLC_EGENERIC;
+        }
+
+        /* open config directory */
+        if( !( p_dir = vlc_opendir( psz_dir ) ) )
+        {
+            msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
+            free( p_scan->parameter.sat_info.psz_name );
+            return VLC_EGENERIC;
+        }
+
+        /* find the requested file in the directory */
+        for( ; ; ) {
+            char *psz_filename;
+
+            if( ! (psz_filename = vlc_readdir( p_dir ) ) )
+                break;
+
+            if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
+            {
+                if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
+                    p_scan->parameter.sat_info.psz_path = NULL;
+
+                free( psz_filename );
+                break;
+            }
+        }
+
+        closedir( p_dir );
+
+        if( !p_scan->parameter.sat_info.psz_path )
+        {
+            msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
+            free( p_scan->parameter.sat_info.psz_name );
+            return VLC_EGENERIC;
+        }
+
+        msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
+
+        FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
+
+        /* parse file */
+        if( f )
+        {
+            char type;
+            char psz_fec[3];
+
+            int res;
+            do
+            {
+                if ( ( res = fscanf( f, "%c %d %c %d %s\n",
+                            &type,
+                            &p_transponders[*pi_count].i_frequency,
+                            &p_transponders[*pi_count].c_polarization,
+                            &p_transponders[*pi_count].i_symbol_rate,
+                            psz_fec ) ) != 5 )
+                {
+                    msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
+                    continue;
+                }
+
+                /* decode fec */
+                char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
+                char *p_fec = strstr( psz_fec_list, psz_fec );
+                if ( !p_fec )
+                    p_transponders[*pi_count].i_fec = 9;    /* FEC_AUTO */
+                else
+                    p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
+
+                (*pi_count)++;
+
+                p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
+            } while (res != EOF);
+
+            msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
+
+            fclose( f );
+        }
+        else
+        {
+            msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
+            free( p_scan->parameter.sat_info.psz_name );
+            free( p_scan->parameter.sat_info.psz_path );
+            return VLC_EGENERIC;
+        }
+        free( p_scan->parameter.sat_info.psz_name );
+        free( p_scan->parameter.sat_info.psz_path );
+
+        p_scan->parameter.sat_info.p_transponders = p_transponders;
     }
-    else if ( p_scan->i_index <= (72 + (90-21) ) )
+
+    if( p_scan->i_index < *pi_count )
     {
-        p_cfg->i_frequency = 13800000 + ( ( p_scan->i_index - (72 + 21 ) )  * 800000);
+        /* setup params for scan */
+        p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
+        p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
+        p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
+        p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
+
+        msg_Dbg( p_scan->p_obj,
+                 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
+                 p_scan->i_index + 1,
+                 *pi_count,
+                 p_cfg->i_frequency,
+                 p_cfg->i_symbol_rate,
+                 p_cfg->i_fec,
+                 p_cfg->c_polarization );
+
+        *pf_pos = (double)p_scan->i_index / *pi_count;
+
+        return VLC_SUCCESS;
     }
-    else
+
+    if( p_scan->parameter.sat_info.p_transponders )
     {
-        return VLC_EGENERIC;
+        free( p_scan->parameter.sat_info.p_transponders );
+        p_scan->parameter.sat_info.p_transponders = NULL;
     }
-    *pf_pos = (double)p_scan->i_index / ( (90-21+22-5+10+9));
-    return VLC_SUCCESS;
 
+    return VLC_EGENERIC;
 }
 
-static int ScanDvbTNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
+static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
+{
+    msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
+    /* Values taken from dvb-scan utils frequency-files, sorted by how
+     * often they appear. This hopefully speeds up finding services. */
+    static const unsigned short frequencies[] = {
+     410, 426, 418, 394, 402, 362,
+     370, 354, 346, 442, 434, 386,
+     378, 450, 306, 162, 154, 474,
+     466, 458, 338, 754, 714, 586,
+     562, 546, 514, 490, 314, 170,
+     113, 770, 762, 746, 738, 730,
+     722, 706, 690, 682, 674, 666,
+     650, 642, 634, 554, 538, 530,
+     506, 498, 330, 322, 283, 850,
+     842, 834, 818, 810, 802, 794,
+     786, 778, 748, 732, 728, 724,
+     720, 698, 660, 658, 656, 610,
+     594, 578, 570, 522, 482, 377,
+     372, 347, 339, 323, 315, 299,
+     298, 291, 275, 267, 259, 255,
+     251, 243, 235, 232, 227, 219,
+     211, 203, 195, 187, 179, 171,
+     163, 155, 147, 146, 143, 139,
+     131, 123, 121
+    };
+    enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
+
+    if( p_scan->i_index < num_frequencies )
+    {
+        p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
+        *pf_pos = (double)p_scan->i_index / num_frequencies;
+        return VLC_SUCCESS;
+    }
+    return VLC_EGENERIC;
+}
+
+static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
 {
     if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
         return VLC_EGENERIC;
@@ -261,7 +428,7 @@ static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double
 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
 {
     if( p_scan->parameter.b_exhaustive )
-        return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
+        return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
     else
         return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
 }
@@ -269,11 +436,19 @@ static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf
 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
 {
     if( p_scan->parameter.b_exhaustive )
-        return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
+        return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
     else
         return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
 }
 
+static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
+{
+    if( p_scan->parameter.b_exhaustive )
+        msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
+
+    return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
+}
+
 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
 {
     double f_position;
@@ -291,6 +466,9 @@ int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
     case SCAN_DVB_C:
         i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
         break;
+    case SCAN_DVB_S:
+        i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
+        break;
     default:
         i_ret = VLC_EGENERIC;
         break;
@@ -308,17 +486,17 @@ int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
             i_service++;
     }
 
-    if( asprintf( &psz_text, _("%.1f MHz (%d services)"), 
-                  (double)p_cfg->i_frequency / 1000000, i_service ) >= 0 )
-    {
-        const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
-        char psz_eta[MSTRTIME_MAX_SIZE];
+    const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
+    char psz_eta[MSTRTIME_MAX_SIZE];
 
+    if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
+                  (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
+    {
         if( i_eta >= 0 )
             msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
 
         if( p_scan->p_dialog == NULL )
-            p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB-T"), psz_text, _("Cancel") );
+            p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
         if( p_scan->p_dialog != NULL )
             dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
         free( psz_text );
@@ -783,14 +961,20 @@ block_t *scan_GetM3U( scan_t *p_scan )
                   s->i_network_id, s->i_nit_version, s->i_sdt_version,
                   s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
 
+        if( !s->cfg.i_fec )
+            s->cfg.i_fec = 9;   /* FEC_AUTO */
+
         char *psz;
         if( asprintf( &psz, "#EXTINF:,,%s\n"
                         "#EXTVLCOPT:program=%d\n"
-                        "dvb://frequency=%d:bandwidth=%d\n"
+                        "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
                         "\n",
                       s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
                       s->i_program,
-                      s->cfg.i_frequency, s->cfg.i_bandwidth ) < 0 )
+                      s->cfg.i_frequency,
+                      s->cfg.i_bandwidth,
+                      s->cfg.c_polarization == 'H' ? 18 : 13,
+                      s->cfg.i_fec ) < 0 )
             psz = NULL;
         if( psz )
         {