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