]> git.sesse.net Git - vlc/blob - modules/access/dvb/scan.c
626dbf2823e840b35f80bc1efde9a4820f6d77fd
[vlc] / modules / access / dvb / scan.c
1 /*****************************************************************************
2  * scan.c: DVB scanner helpers
3  *****************************************************************************
4  * Copyright (C) 2008,2010 the VideoLAN team
5  *
6  * Authors: Laurent Aimar <fenrir@videolan.org>
7  *          David Kaplan <david@2of1.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_access.h>
34 #include <vlc_dialog.h>
35 #include <vlc_fs.h>
36
37 #ifdef HAVE_UNISTD_H
38 #   include <unistd.h>
39 #endif
40
41 #include <sys/types.h>
42 #include <poll.h>
43
44 /* Include dvbpsi headers */
45 #ifdef HAVE_DVBPSI_DR_H
46 #   include <dvbpsi/dvbpsi.h>
47 #   include <dvbpsi/descriptor.h>
48 #   include <dvbpsi/pat.h>
49 #   include <dvbpsi/pmt.h>
50 #   include <dvbpsi/dr.h>
51 #   include <dvbpsi/psi.h>
52 #   include <dvbpsi/demux.h>
53 #   include <dvbpsi/sdt.h>
54 #else
55 #   include "dvbpsi.h"
56 #   include "descriptor.h"
57 #   include "tables/pat.h"
58 #   include "tables/pmt.h"
59 #   include "descriptors/dr.h"
60 #   include "psi.h"
61 #   include "demux.h"
62 #   include "tables/sdt.h"
63 #endif
64
65 #ifdef ENABLE_HTTPD
66 #   include <vlc_httpd.h>
67 #endif
68
69 #include "dvb.h"
70
71 /* */
72 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg  )
73 {
74     scan_service_t *p_srv = malloc( sizeof(*p_srv) );
75     if( !p_srv )
76         return NULL;
77
78     p_srv->i_program = i_program;
79     p_srv->cfg = *p_cfg;
80     p_srv->i_snr = -1;
81
82     p_srv->type = SERVICE_UNKNOWN;
83     p_srv->psz_name = NULL;
84     p_srv->i_channel = -1;
85     p_srv->b_crypted = false;
86
87     p_srv->i_network_id = -1;
88     p_srv->i_nit_version = -1;
89     p_srv->i_sdt_version = -1;
90
91     return p_srv;
92 }
93
94 void scan_service_Delete( scan_service_t *p_srv )
95 {
96     free( p_srv->psz_name );
97     free( p_srv );
98 }
99
100 /* */
101 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
102 {
103     if( p_parameter->type == SCAN_DVB_T )
104     {
105         msg_Dbg( p_obj, "DVB-T scanning:" );
106         msg_Dbg( p_obj, " - frequency [%d, %d]",
107                  p_parameter->frequency.i_min, p_parameter->frequency.i_max );
108         msg_Dbg( p_obj, " - bandwidth [%d,%d]",
109                  p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
110         msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
111     }
112     else if( p_parameter->type == SCAN_DVB_C )
113     {
114         msg_Dbg( p_obj, "DVB-C scanning:" );
115         msg_Dbg( p_obj, " - frequency [%d, %d]",
116                  p_parameter->frequency.i_min, p_parameter->frequency.i_max );
117         msg_Dbg( p_obj, " - bandwidth [%d,%d]",
118                  p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
119         msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
120     }
121     else if( p_parameter->type == SCAN_DVB_S )
122     {
123         msg_Dbg( p_obj, "DVB-S scanning:" );
124         msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
125     }
126     else
127     {
128         return VLC_EGENERIC;
129     }
130     msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
131     msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
132
133     p_scan->p_obj = VLC_OBJECT(p_obj);
134     p_scan->i_index = 0;
135     p_scan->p_dialog = NULL;
136     TAB_INIT( p_scan->i_service, p_scan->pp_service );
137     p_scan->parameter = *p_parameter;
138     p_scan->i_time_start = mdate();
139
140     return VLC_SUCCESS;
141 }
142
143 void scan_Clean( scan_t *p_scan )
144 {
145     if( p_scan->p_dialog != NULL )
146         dialog_ProgressDestroy( p_scan->p_dialog );
147
148     for( int i = 0; i < p_scan->i_service; i++ )
149         scan_service_Delete( p_scan->pp_service[i] );
150     TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
151 }
152
153 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
154 {
155     msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
156
157     int *pi_count = &p_scan->parameter.sat_info.i_count;
158
159     if( !p_scan->parameter.sat_info.psz_name )
160     {
161         msg_Err( p_scan->p_obj, "no satellite selected" );
162         return VLC_EGENERIC;
163     }
164
165     /* if there are no transponders in mem, laod from config file */
166     if( !*pi_count )
167     {
168         scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
169
170         DIR *p_dir;
171
172         char *psz_dir = NULL;
173         char *data_dir = config_GetDataDir( p_scan->p_obj );
174
175         if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
176             psz_dir = NULL;
177         free( data_dir );
178
179         if( !psz_dir )
180         {
181             free( p_scan->parameter.sat_info.psz_name );
182             return VLC_EGENERIC;
183         }
184
185         /* open config directory */
186         if( !( p_dir = vlc_opendir( psz_dir ) ) )
187         {
188             msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
189             free( p_scan->parameter.sat_info.psz_name );
190             return VLC_EGENERIC;
191         }
192
193         /* find the requested file in the directory */
194         for( ; ; ) {
195             char *psz_filename;
196
197             if( ! (psz_filename = vlc_readdir( p_dir ) ) )
198                 break;
199
200             if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
201             {
202                 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
203                     p_scan->parameter.sat_info.psz_path = NULL;
204
205                 free( psz_filename );
206                 break;
207             }
208         }
209
210         closedir( p_dir );
211
212         if( !p_scan->parameter.sat_info.psz_path )
213         {
214             msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
215             free( p_scan->parameter.sat_info.psz_name );
216             return VLC_EGENERIC;
217         }
218
219         msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
220
221         FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
222
223         /* parse file */
224         if( f )
225         {
226             char type;
227             char psz_fec[3];
228
229             int res;
230             do
231             {
232                 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
233                             &type,
234                             &p_transponders[*pi_count].i_frequency,
235                             &p_transponders[*pi_count].c_polarization,
236                             &p_transponders[*pi_count].i_symbol_rate,
237                             psz_fec ) ) != 5 )
238                 {
239                     msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
240                     continue;
241                 }
242
243                 /* decode fec */
244                 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
245                 char *p_fec = strstr( psz_fec_list, psz_fec );
246                 if ( !p_fec )
247                     p_transponders[*pi_count].i_fec = 9;    /* FEC_AUTO */
248                 else
249                     p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
250
251                 (*pi_count)++;
252
253                 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
254             } while (res != EOF);
255
256             msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
257
258             fclose( f );
259         }
260         else
261         {
262             msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
263             free( p_scan->parameter.sat_info.psz_name );
264             free( p_scan->parameter.sat_info.psz_path );
265             return VLC_EGENERIC;
266         }
267         free( p_scan->parameter.sat_info.psz_name );
268         free( p_scan->parameter.sat_info.psz_path );
269
270         p_scan->parameter.sat_info.p_transponders = p_transponders;
271     }
272
273     if( p_scan->i_index < *pi_count )
274     {
275         /* setup params for scan */
276         p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
277         p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
278         p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
279         p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
280
281         msg_Dbg( p_scan->p_obj,
282                  "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
283                  p_scan->i_index + 1,
284                  *pi_count,
285                  p_cfg->i_frequency,
286                  p_cfg->i_symbol_rate,
287                  p_cfg->i_fec,
288                  p_cfg->c_polarization );
289
290         *pf_pos = (double)p_scan->i_index / *pi_count;
291
292         return VLC_SUCCESS;
293     }
294
295     if( p_scan->parameter.sat_info.p_transponders )
296     {
297         free( p_scan->parameter.sat_info.p_transponders );
298         p_scan->parameter.sat_info.p_transponders = NULL;
299     }
300
301     return VLC_EGENERIC;
302 }
303
304 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
305 {
306     msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
307     /* Values taken from dvb-scan utils frequency-files, sorted by how
308      * often they appear. This hopefully speeds up finding services. */
309     static const unsigned short frequencies[] = {
310      410, 426, 418, 394, 402, 362,
311      370, 354, 346, 442, 434, 386,
312      378, 450, 306, 162, 154, 474,
313      466, 458, 338, 754, 714, 586,
314      562, 546, 514, 490, 314, 170,
315      113, 770, 762, 746, 738, 730,
316      722, 706, 690, 682, 674, 666,
317      650, 642, 634, 554, 538, 530,
318      506, 498, 330, 322, 283, 850,
319      842, 834, 818, 810, 802, 794,
320      786, 778, 748, 732, 728, 724,
321      720, 698, 660, 658, 656, 610,
322      594, 578, 570, 522, 482, 377,
323      372, 347, 339, 323, 315, 299,
324      298, 291, 275, 267, 259, 255,
325      251, 243, 235, 232, 227, 219,
326      211, 203, 195, 187, 179, 171,
327      163, 155, 147, 146, 143, 139,
328      131, 123, 121
329     };
330     enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
331
332     if( p_scan->i_index < num_frequencies )
333     {
334         p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
335         *pf_pos = (double)p_scan->i_index / num_frequencies;
336         return VLC_SUCCESS;
337     }
338     return VLC_EGENERIC;
339 }
340
341 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
342 {
343     if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
344         return VLC_EGENERIC;
345
346     const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
347     const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
348
349     p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
350     p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
351
352     *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
353     return VLC_SUCCESS;
354 }
355
356 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
357 {
358     static const int i_band_count = 2;
359     static const struct
360     {
361         const char *psz_name;
362         int i_min;
363         int i_max;
364     }
365     band[2] =
366     {
367         { "VHF", 174, 230 },
368         { "UHF", 470, 862 },
369     };
370     const int i_offset_count = 5;
371     const int i_mhz = 1000000;
372
373     /* We will probe the whole band divided in all bandwidth possibility trying 
374      * i_offset_count offset around the position
375      */
376     for( ;; p_scan->i_index++ )
377     {
378
379         const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
380         const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
381         const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
382
383         const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
384         int i;
385
386         for( i = 0; i < i_band_count; i++ )
387         {
388             if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
389                 break;
390         }
391         if( i >=i_band_count )
392         {
393             if( i_fi > band[i_band_count-1].i_max )
394                 return VLC_EGENERIC;
395             continue;
396         }
397
398         const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
399         const int i_frequency_base = i_fi*i_mhz;
400
401         if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
402         {
403             const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
404
405             if( i_frequency < p_scan->parameter.frequency.i_min ||
406                 i_frequency > p_scan->parameter.frequency.i_max )
407                 continue;
408
409             p_cfg->i_frequency = i_frequency;
410             p_cfg->i_bandwidth = i_bandwidth;
411
412             int i_current = 0, i_total = 0;
413             for( int i = 0; i < i_band_count; i++ )
414             {
415                 const int i_frag = band[i].i_max-band[i].i_min;
416
417                 if( i_fi >= band[i].i_min )
418                     i_current += __MIN( i_fi - band[i].i_min, i_frag );
419                 i_total += i_frag;
420             }
421
422             *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
423             return VLC_SUCCESS;
424         }
425     }
426 }
427
428 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
429 {
430     if( p_scan->parameter.b_exhaustive )
431         return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
432     else
433         return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
434 }
435
436 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
437 {
438     if( p_scan->parameter.b_exhaustive )
439         return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
440     else
441         return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
442 }
443
444 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
445 {
446     if( p_scan->parameter.b_exhaustive )
447         msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
448
449     return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
450 }
451
452 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
453 {
454     double f_position;
455     int i_ret;
456
457     if( scan_IsCancelled( p_scan ) )
458         return VLC_EGENERIC;
459
460     memset( p_cfg, 0, sizeof(*p_cfg) );
461     switch( p_scan->parameter.type )
462     {
463     case SCAN_DVB_T:
464         i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
465         break;
466     case SCAN_DVB_C:
467         i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
468         break;
469     case SCAN_DVB_S:
470         i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
471         break;
472     default:
473         i_ret = VLC_EGENERIC;
474         break;
475     }
476
477     if( i_ret )
478         return i_ret;
479
480     char *psz_text;
481     int i_service = 0;
482
483     for( int i = 0; i < p_scan->i_service; i++ )
484     {
485         if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
486             i_service++;
487     }
488
489     const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
490     char psz_eta[MSTRTIME_MAX_SIZE];
491
492     if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
493                   (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
494     {
495         if( i_eta >= 0 )
496             msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
497
498         if( p_scan->p_dialog == NULL )
499             p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
500         if( p_scan->p_dialog != NULL )
501             dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
502         free( psz_text );
503     }
504
505     p_scan->i_index++;
506     return VLC_SUCCESS;
507 }
508
509 bool scan_IsCancelled( scan_t *p_scan )
510 {
511     return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
512 }
513
514 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
515 {
516     for( int i = i_service_start; i < p_scan->i_service; i++ )
517     {
518         if( p_scan->pp_service[i]->i_program == i_program )
519             return p_scan->pp_service[i];
520     }
521     return NULL;
522 }
523
524 /* FIXME handle properly string (convert to utf8) */
525 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
526 {
527     vlc_object_t *p_obj = p_session->p_obj;
528
529     msg_Dbg( p_obj, "PATCallBack" );
530
531     /* */
532     if( p_session->p_pat && p_session->p_pat->b_current_next )
533     {
534         dvbpsi_DeletePAT( p_session->p_pat );
535         p_session->p_pat = NULL;
536     }
537     if( p_session->p_pat )
538     {
539         dvbpsi_DeletePAT( p_pat );
540         return;
541     }
542
543     dvbpsi_pat_program_t *p_program;
544
545     /* */
546     p_session->p_pat = p_pat;
547
548     /* */
549     msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
550              p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
551     for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
552     {
553         msg_Dbg( p_obj, "  * number=%d pid=%d", p_program->i_number, p_program->i_pid );
554         if( p_program->i_number == 0 )
555             p_session->i_nit_pid = p_program->i_pid;
556     }
557 }
558 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
559 {
560     vlc_object_t *p_obj = p_session->p_obj;
561
562     msg_Dbg( p_obj, "SDTCallBack" );
563
564     if( p_session->p_sdt && p_session->p_sdt->b_current_next )
565     {
566         dvbpsi_DeleteSDT( p_session->p_sdt );
567         p_session->p_sdt = NULL;
568     }
569     if( p_session->p_sdt )
570     {
571         dvbpsi_DeleteSDT( p_sdt );
572         return;
573     }
574
575     /* */
576     p_session->p_sdt = p_sdt;
577
578     /* */
579     msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
580              p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
581              p_sdt->i_network_id );
582
583
584     dvbpsi_sdt_service_t *p_srv;
585     for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
586     {
587         dvbpsi_descriptor_t *p_dr;
588
589         msg_Dbg( p_obj, "  * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
590                  p_srv->i_service_id, p_srv->b_eit_schedule,
591                  p_srv->b_eit_present, p_srv->i_running_status,
592                  p_srv->b_free_ca );
593         for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
594         {
595             if( p_dr->i_tag == 0x48 )
596             {
597                 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
598                 char str2[257];
599
600                 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
601                 str2[pD->i_service_name_length] = '\0';
602
603                 msg_Dbg( p_obj, "    - type=%d name=%s",
604                          pD->i_service_type, str2 );
605             }
606             else
607             {
608                 msg_Dbg( p_obj, "    * dsc 0x%x", p_dr->i_tag );
609             }
610         }
611     }
612 }
613
614 #ifdef DVBPSI_USE_NIT
615 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
616 {
617     vlc_object_t *p_obj = p_session->p_obj;
618
619     msg_Dbg( p_obj, "NITCallBack" );
620     msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
621              p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
622
623     /* */
624     if( p_session->p_nit && p_session->p_nit->b_current_next )
625     {
626         dvbpsi_DeleteNIT( p_session->p_nit );
627         p_session->p_nit = NULL;
628     }
629     if( p_session->p_nit )
630     {
631         dvbpsi_DeleteNIT( p_nit );
632         return;
633     }
634
635     /* */
636     p_session->p_nit = p_nit;
637
638     dvbpsi_descriptor_t *p_dsc;
639     for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
640     {
641         if( p_dsc->i_tag == 0x40 )
642         {
643             msg_Dbg( p_obj, "   * network name descriptor" );
644             char str1[257];
645
646             memcpy( str1, p_dsc->p_data, p_dsc->i_length );
647             str1[p_dsc->i_length] = '\0';
648             msg_Dbg( p_obj, "       * name %s", str1 );
649         }
650         else if( p_dsc->i_tag == 0x4a )
651         {
652             msg_Dbg( p_obj, "   * linkage descriptor" );
653             uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
654             uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
655             uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
656             int i_linkage_type = p_dsc->p_data[6];
657
658             msg_Dbg( p_obj, "       * ts_id %d", i_ts_id );
659             msg_Dbg( p_obj, "       * on_id %d", i_on_id );
660             msg_Dbg( p_obj, "       * service_id %d", i_service_id );
661             msg_Dbg( p_obj, "       * linkage_type %d", i_linkage_type );
662         }
663         else 
664         {
665             msg_Dbg( p_obj, "   * dsc 0x%x", p_dsc->i_tag );
666         }
667     }
668
669     dvbpsi_nit_ts_t *p_ts;
670     for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
671     {
672         msg_Dbg( p_obj, "   * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
673
674         uint32_t i_private_data_id = 0;
675         dvbpsi_descriptor_t *p_dsc;
676         for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
677         {
678             if( p_dsc->i_tag == 0x41 )
679             {
680                 msg_Dbg( p_obj, "       * service list descriptor" );
681                 for( int i = 0; i < p_dsc->i_length/3; i++ )
682                 {
683                     uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
684                     uint8_t  i_service_type = p_dsc->p_data[3*i+2];
685                     msg_Dbg( p_obj, "           * service_id=%d type=%d", i_service_id, i_service_type );
686                 }
687             }
688             else if( p_dsc->i_tag == 0x5a )
689             {
690                 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
691                 msg_Dbg( p_obj, "       * terrestrial delivery system" );
692                 msg_Dbg( p_obj, "           * centre_frequency 0x%x", p_t->i_centre_frequency  );
693                 msg_Dbg( p_obj, "           * bandwidth %d", 8 - p_t->i_bandwidth );
694                 msg_Dbg( p_obj, "           * constellation %d", p_t->i_constellation );
695                 msg_Dbg( p_obj, "           * hierarchy %d", p_t->i_hierarchy_information );
696                 msg_Dbg( p_obj, "           * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
697                 msg_Dbg( p_obj, "           * guard_interval %d", p_t->i_guard_interval );
698                 msg_Dbg( p_obj, "           * transmission_mode %d", p_t->i_transmission_mode );
699                 msg_Dbg( p_obj, "           * other_frequency_flag %d", p_t->i_other_frequency_flag );
700             }
701             else if( p_dsc->i_tag == 0x5f )
702             {
703                 msg_Dbg( p_obj, "       * private data specifier descriptor" );
704                 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
705                 msg_Dbg( p_obj, "           * value 0x%8.8x", i_private_data_id );
706             }
707             else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
708             {
709                 msg_Dbg( p_obj, "       * logical channel descriptor (EICTA)" );
710                 for( int i = 0; i < p_dsc->i_length/4; i++ )
711                 {
712                     uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
713                     int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
714                     msg_Dbg( p_obj, "           * service_id=%d channel_number=%d", i_service_id, i_channel_number );
715                 }
716
717             }
718             else
719             {
720                 msg_Warn( p_obj, "       * dsc 0x%x", p_dsc->i_tag );
721             }
722         }
723     }
724 }
725 #endif
726
727 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t  i_table_id, uint16_t i_extension )
728 {
729     if( i_table_id == 0x42 )
730         dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
731 #ifdef DVBPSI_USE_NIT
732     else if( i_table_id == 0x40 )
733         dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
734 #endif
735 }
736
737
738 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
739 {
740     /* */
741     memset( p_session, 0, sizeof(*p_session) );
742     p_session->p_obj = p_obj;
743     p_session->cfg = *p_cfg;
744     p_session->i_snr = -1;
745     p_session->pat = NULL;
746     p_session->p_pat = NULL;
747     p_session->i_nit_pid = -1;
748     p_session->sdt = NULL;
749     p_session->p_sdt = NULL;
750 #ifdef DVBPSI_USE_NIT
751     p_session->nit = NULL;
752     p_session->p_nit = NULL;
753 #endif
754     return VLC_SUCCESS;
755 }
756
757 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
758 {
759     const int i_service_start = p_scan->i_service;
760
761     dvbpsi_pat_t *p_pat = p_session->p_pat;
762     dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
763
764 #ifdef DVBPSI_USE_NIT
765     dvbpsi_nit_t *p_nit = p_session->p_nit;
766 #endif
767
768     if( p_pat )
769     {
770         /* Parse PAT */
771         dvbpsi_pat_program_t *p_program;
772         for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
773         {
774             if( p_program->i_number == 0 )  /* NIT */
775                 continue;
776
777             scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
778             TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
779         }
780     }
781     /* Parse SDT */
782     if( p_pat && p_sdt )
783     {
784         dvbpsi_sdt_service_t *p_srv;
785         for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
786         {
787             scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
788             dvbpsi_descriptor_t *p_dr;
789
790             if( s )
791                 s->b_crypted = p_srv->b_free_ca;
792
793             for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
794             {
795                 if( p_dr->i_tag == 0x48 )
796                 {
797                     dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
798
799                     if( s )
800                     {
801                         if( !s->psz_name )
802                             s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length );
803
804                         if( s->type == SERVICE_UNKNOWN )
805                         {
806                             switch( pD->i_service_type )
807                             {
808                             case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
809                             case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
810                             case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
811                             case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
812                             }
813                         }
814                     }
815                 }
816             }
817         }
818     }
819
820 #ifdef DVBPSI_USE_NIT
821     /* Parse NIT */
822     if( p_pat && p_nit )
823     {
824         dvbpsi_nit_ts_t *p_ts;
825         for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
826         {
827             uint32_t i_private_data_id = 0;
828             dvbpsi_descriptor_t *p_dsc;
829
830             if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
831                 continue;
832
833             for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
834             {
835                 if( p_dsc->i_tag == 0x5f )
836                 {
837                     i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
838                 }
839                 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
840                 {
841                     for( int i = 0; i < p_dsc->i_length/4; i++ )
842                     {
843                         uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
844                         int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
845
846                         scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
847                         if( s && s->i_channel < 0 )
848                             s->i_channel = i_channel_number;
849                     }
850                 }
851             }
852         }
853     }
854 #endif
855
856     /* */
857     for( int i = i_service_start; i < p_scan->i_service; i++ )
858     {
859         scan_service_t *p_srv = p_scan->pp_service[i];
860
861         p_srv->i_snr = p_session->i_snr;
862         if( p_sdt )
863             p_srv->i_sdt_version = p_sdt->i_version;
864 #ifdef DVBPSI_USE_NIT
865         if( p_nit )
866         {
867             p_srv->i_network_id = p_nit->i_network_id;
868             p_srv->i_nit_version = p_nit->i_version;
869         }
870 #endif
871     }
872
873
874     /* */
875     if( p_session->pat )
876         dvbpsi_DetachPAT( p_session->pat );
877     if( p_session->p_pat )
878         dvbpsi_DeletePAT( p_session->p_pat );
879
880     if( p_session->sdt )
881         dvbpsi_DetachDemux( p_session->sdt );
882     if( p_session->p_sdt )
883         dvbpsi_DeleteSDT( p_session->p_sdt );
884 #ifdef DVBPSI_USE_NIT
885     if( p_session->nit )
886         dvbpsi_DetachDemux( p_session->nit );
887     if( p_session->p_nit )
888         dvbpsi_DeleteNIT( p_session->p_nit );
889 #endif
890 }
891
892 static int ScanServiceCmp( const void *a, const void *b )
893 {
894     scan_service_t *sa = *(scan_service_t**)a;
895     scan_service_t *sb = *(scan_service_t**)b;
896
897     if( sa->i_channel == sb->i_channel )
898     {
899         if( sa->psz_name && sb->psz_name )
900             return strcmp( sa->psz_name, sb->psz_name );
901         return 0;
902     }
903     if( sa->i_channel == -1 )
904         return 1;
905     else if( sb->i_channel == -1 )
906         return -1;
907
908     if( sa->i_channel < sb->i_channel )
909         return -1;
910     else if( sa->i_channel > sb->i_channel )
911         return 1;
912     return 0;
913 }
914
915 static block_t *BlockString( const char *psz )
916 {
917     block_t *p = block_Alloc( strlen(psz) );
918     if( p )
919         memcpy( p->p_buffer, psz, p->i_buffer );
920     return p;
921 }
922
923 block_t *scan_GetM3U( scan_t *p_scan )
924 {
925     vlc_object_t *p_obj = p_scan->p_obj;
926     block_t *p_playlist = NULL;
927
928     if( p_scan->i_service <= 0 )
929         return NULL;
930
931     /* */
932     qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
933
934     /* */
935     p_playlist = BlockString( "#EXTM3U\n\n" );/* */
936
937     for( int i = 0; i < p_scan->i_service; i++ )
938     {
939         scan_service_t *s = p_scan->pp_service[i];
940
941         if( s->type == SERVICE_UNKNOWN )
942         {
943             /* We should only select service that have been described by SDT */
944             msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
945             continue;
946         }
947
948         const char *psz_type;
949         switch( s->type )
950         {
951         case SERVICE_DIGITAL_TELEVISION:       psz_type = "Digital television"; break;
952         case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
953         case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
954         case SERVICE_DIGITAL_RADIO:            psz_type = "Digital radio"; break;
955         default:
956             psz_type = "Unknown";
957             break;
958         }
959         msg_Warn( p_obj, "scan_GetM3U: service number %d type '%s' name '%s' channel %d cypted=%d| network_id %d (nit:%d sdt:%d)| f=%d bw=%d snr=%d",
960                   s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
961                   s->i_network_id, s->i_nit_version, s->i_sdt_version,
962                   s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
963
964         if( !s->cfg.i_fec )
965             s->cfg.i_fec = 9;   /* FEC_AUTO */
966
967         char *psz;
968         if( asprintf( &psz, "#EXTINF:,,%s\n"
969                         "#EXTVLCOPT:program=%d\n"
970                         "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
971                         "\n",
972                       s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
973                       s->i_program,
974                       s->cfg.i_frequency,
975                       s->cfg.i_bandwidth,
976                       s->cfg.c_polarization == 'H' ? 18 : 13,
977                       s->cfg.i_fec ) < 0 )
978             psz = NULL;
979         if( psz )
980         {
981             block_t *p_block = BlockString( psz );
982             if( p_block )
983                 block_ChainAppend( &p_playlist, p_block );
984         }
985     }
986
987     return p_playlist ? block_ChainGather( p_playlist ) : NULL;
988 }
989
990 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
991 {
992     if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
993     {
994         block_Release( p_block );
995         return false;
996     }
997
998     /* */
999     const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1000     if( i_pid == 0x00 )
1001     {
1002         if( !p_scan->pat )
1003             p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1004
1005         if( p_scan->pat )
1006             dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1007     }
1008     else if( i_pid == 0x11 )
1009     {
1010         if( !p_scan->sdt )
1011             p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1012
1013         if( p_scan->sdt )
1014             dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1015     }
1016     else if( i_pid == p_scan->i_nit_pid )
1017     {
1018 #ifdef DVBPSI_USE_NIT
1019         if( !p_scan->nit )
1020             p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1021
1022         if( p_scan->nit )
1023             dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1024 #endif
1025     }
1026
1027     block_Release( p_block );
1028
1029     return p_scan->p_pat && p_scan->p_sdt && 
1030 #ifdef DVBPSI_USE_NIT
1031         p_scan->p_nit;
1032 #else
1033         true;
1034 #endif
1035 }
1036
1037 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1038 {
1039     p_session->i_snr = i_snr;
1040 }
1041