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