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