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