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