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