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