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