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