dvb_scan: fix memleak.
[vlc/asuraparaju-public.git] / modules / access / dvb / scan.c
blob92655cdc719d6b15be8031d590f51f85e4acb83a
1 /*****************************************************************************
2 * scan.c: DVB scanner helpers
3 *****************************************************************************
4 * Copyright (C) 2008,2010 the VideoLAN team
6 * Authors: Laurent Aimar <fenrir@videolan.org>
7 * David Kaplan <david@2of1.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_access.h>
34 #include <vlc_dialog.h>
35 #include <vlc_fs.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
41 #include <sys/types.h>
42 #include <poll.h>
44 /* Include dvbpsi headers */
45 #ifdef HAVE_DVBPSI_DR_H
46 # include <dvbpsi/dvbpsi.h>
47 # include <dvbpsi/descriptor.h>
48 # include <dvbpsi/pat.h>
49 # include <dvbpsi/pmt.h>
50 # include <dvbpsi/dr.h>
51 # include <dvbpsi/psi.h>
52 # include <dvbpsi/demux.h>
53 # include <dvbpsi/sdt.h>
54 #else
55 # include "dvbpsi.h"
56 # include "descriptor.h"
57 # include "tables/pat.h"
58 # include "tables/pmt.h"
59 # include "descriptors/dr.h"
60 # include "psi.h"
61 # include "demux.h"
62 # include "tables/sdt.h"
63 #endif
65 #ifdef ENABLE_HTTPD
66 # include <vlc_httpd.h>
67 #endif
69 #include "dvb.h"
71 /* */
72 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg )
74 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
75 if( !p_srv )
76 return NULL;
78 p_srv->i_program = i_program;
79 p_srv->cfg = *p_cfg;
80 p_srv->i_snr = -1;
82 p_srv->type = SERVICE_UNKNOWN;
83 p_srv->psz_name = NULL;
84 p_srv->i_channel = -1;
85 p_srv->b_crypted = false;
87 p_srv->i_network_id = -1;
88 p_srv->i_nit_version = -1;
89 p_srv->i_sdt_version = -1;
91 return p_srv;
94 void scan_service_Delete( scan_service_t *p_srv )
96 free( p_srv->psz_name );
97 free( p_srv );
100 /* */
101 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
103 if( p_parameter->type == SCAN_DVB_T )
105 msg_Dbg( p_obj, "DVB-T scanning:" );
106 msg_Dbg( p_obj, " - frequency [%d, %d]",
107 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
108 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
109 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
110 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
112 else if( p_parameter->type == SCAN_DVB_C )
114 msg_Dbg( p_obj, "DVB-C scanning:" );
115 msg_Dbg( p_obj, " - frequency [%d, %d]",
116 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
117 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
118 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
119 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
121 else if( p_parameter->type == SCAN_DVB_S )
123 msg_Dbg( p_obj, "DVB-S scanning:" );
124 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
126 else
128 return VLC_EGENERIC;
130 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
131 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
133 p_scan->p_obj = VLC_OBJECT(p_obj);
134 p_scan->i_index = 0;
135 p_scan->p_dialog = NULL;
136 TAB_INIT( p_scan->i_service, p_scan->pp_service );
137 p_scan->parameter = *p_parameter;
138 p_scan->i_time_start = mdate();
140 return VLC_SUCCESS;
143 void scan_Clean( scan_t *p_scan )
145 if( p_scan->p_dialog != NULL )
146 dialog_ProgressDestroy( p_scan->p_dialog );
148 for( int i = 0; i < p_scan->i_service; i++ )
149 scan_service_Delete( p_scan->pp_service[i] );
150 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
153 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
155 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
157 int *pi_count = &p_scan->parameter.sat_info.i_count;
159 if( !p_scan->parameter.sat_info.psz_name )
161 msg_Err( p_scan->p_obj, "no satellite selected" );
162 return VLC_EGENERIC;
165 /* if there are no transponders in mem, laod from config file */
166 if( !*pi_count )
168 DIR *p_dir;
170 char *psz_dir = NULL;
171 char *data_dir = config_GetDataDir( p_scan->p_obj );
173 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
174 psz_dir = NULL;
175 free( data_dir );
177 if( !psz_dir )
179 free( p_scan->parameter.sat_info.psz_name );
180 return VLC_EGENERIC;
183 /* open config directory */
184 if( !( p_dir = vlc_opendir( psz_dir ) ) )
186 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
187 free( p_scan->parameter.sat_info.psz_name );
188 return VLC_EGENERIC;
191 /* find the requested file in the directory */
192 for( ; ; ) {
193 char *psz_filename;
195 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
196 break;
198 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
200 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
201 p_scan->parameter.sat_info.psz_path = NULL;
203 free( psz_filename );
204 break;
208 closedir( p_dir );
210 if( !p_scan->parameter.sat_info.psz_path )
212 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
213 free( p_scan->parameter.sat_info.psz_name );
214 return VLC_EGENERIC;
217 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
219 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
221 /* parse file */
222 if( f )
224 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
225 char type;
226 char psz_fec[3];
228 int res;
231 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
232 &type,
233 &p_transponders[*pi_count].i_frequency,
234 &p_transponders[*pi_count].c_polarization,
235 &p_transponders[*pi_count].i_symbol_rate,
236 psz_fec ) ) != 5 )
238 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
239 continue;
242 /* decode fec */
243 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
244 char *p_fec = strstr( psz_fec_list, psz_fec );
245 if ( !p_fec )
246 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
247 else
248 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
250 (*pi_count)++;
252 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
253 } while (res != EOF);
255 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
257 fclose( f );
258 p_scan->parameter.sat_info.p_transponders = p_transponders;
260 else
262 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
263 free( p_scan->parameter.sat_info.psz_name );
264 free( p_scan->parameter.sat_info.psz_path );
265 return VLC_EGENERIC;
267 free( p_scan->parameter.sat_info.psz_name );
268 free( p_scan->parameter.sat_info.psz_path );
271 if( p_scan->i_index < *pi_count )
273 /* setup params for scan */
274 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
275 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
276 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
277 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
279 msg_Dbg( p_scan->p_obj,
280 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
281 p_scan->i_index + 1,
282 *pi_count,
283 p_cfg->i_frequency,
284 p_cfg->i_symbol_rate,
285 p_cfg->i_fec,
286 p_cfg->c_polarization );
288 *pf_pos = (double)p_scan->i_index / *pi_count;
290 return VLC_SUCCESS;
293 if( p_scan->parameter.sat_info.p_transponders )
295 free( p_scan->parameter.sat_info.p_transponders );
296 p_scan->parameter.sat_info.p_transponders = NULL;
299 return VLC_EGENERIC;
302 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
304 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
305 /* Values taken from dvb-scan utils frequency-files, sorted by how
306 * often they appear. This hopefully speeds up finding services. */
307 static const unsigned short frequencies[] = {
308 410, 426, 418, 394, 402, 362,
309 370, 354, 346, 442, 434, 386,
310 378, 450, 306, 162, 154, 474,
311 466, 458, 338, 754, 714, 586,
312 562, 546, 514, 490, 314, 170,
313 113, 770, 762, 746, 738, 730,
314 722, 706, 690, 682, 674, 666,
315 650, 642, 634, 554, 538, 530,
316 506, 498, 330, 322, 283, 850,
317 842, 834, 818, 810, 802, 794,
318 786, 778, 748, 732, 728, 724,
319 720, 698, 660, 658, 656, 610,
320 594, 578, 570, 522, 482, 377,
321 372, 347, 339, 323, 315, 299,
322 298, 291, 275, 267, 259, 255,
323 251, 243, 235, 232, 227, 219,
324 211, 203, 195, 187, 179, 171,
325 163, 155, 147, 146, 143, 139,
326 131, 123, 121
328 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
330 if( p_scan->i_index < num_frequencies )
332 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
333 *pf_pos = (double)p_scan->i_index / num_frequencies;
334 return VLC_SUCCESS;
336 return VLC_EGENERIC;
339 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
341 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
342 return VLC_EGENERIC;
344 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
345 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
347 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
348 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
350 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
351 return VLC_SUCCESS;
354 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
356 static const int i_band_count = 2;
357 static const struct
359 const char *psz_name;
360 int i_min;
361 int i_max;
363 band[2] =
365 { "VHF", 174, 230 },
366 { "UHF", 470, 862 },
368 const int i_offset_count = 5;
369 const int i_mhz = 1000000;
371 /* We will probe the whole band divided in all bandwidth possibility trying
372 * i_offset_count offset around the position
374 for( ;; p_scan->i_index++ )
377 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
378 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
379 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
381 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
382 int i;
384 for( i = 0; i < i_band_count; i++ )
386 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
387 break;
389 if( i >=i_band_count )
391 if( i_fi > band[i_band_count-1].i_max )
392 return VLC_EGENERIC;
393 continue;
396 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
397 const int i_frequency_base = i_fi*i_mhz;
399 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
401 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
403 if( i_frequency < p_scan->parameter.frequency.i_min ||
404 i_frequency > p_scan->parameter.frequency.i_max )
405 continue;
407 p_cfg->i_frequency = i_frequency;
408 p_cfg->i_bandwidth = i_bandwidth;
410 int i_current = 0, i_total = 0;
411 for( int i = 0; i < i_band_count; i++ )
413 const int i_frag = band[i].i_max-band[i].i_min;
415 if( i_fi >= band[i].i_min )
416 i_current += __MIN( i_fi - band[i].i_min, i_frag );
417 i_total += i_frag;
420 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
421 return VLC_SUCCESS;
426 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
428 if( p_scan->parameter.b_exhaustive )
429 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
430 else
431 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
434 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
436 if( p_scan->parameter.b_exhaustive )
437 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
438 else
439 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
442 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
444 if( p_scan->parameter.b_exhaustive )
445 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
447 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
450 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
452 double f_position;
453 int i_ret;
455 if( scan_IsCancelled( p_scan ) )
456 return VLC_EGENERIC;
458 memset( p_cfg, 0, sizeof(*p_cfg) );
459 switch( p_scan->parameter.type )
461 case SCAN_DVB_T:
462 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
463 break;
464 case SCAN_DVB_C:
465 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
466 break;
467 case SCAN_DVB_S:
468 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
469 break;
470 default:
471 i_ret = VLC_EGENERIC;
472 break;
475 if( i_ret )
476 return i_ret;
478 char *psz_text;
479 int i_service = 0;
481 for( int i = 0; i < p_scan->i_service; i++ )
483 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
484 i_service++;
487 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
488 char psz_eta[MSTRTIME_MAX_SIZE];
490 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
491 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
493 if( i_eta >= 0 )
494 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
496 if( p_scan->p_dialog == NULL )
497 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
498 if( p_scan->p_dialog != NULL )
499 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
500 free( psz_text );
503 p_scan->i_index++;
504 return VLC_SUCCESS;
507 bool scan_IsCancelled( scan_t *p_scan )
509 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
512 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
514 for( int i = i_service_start; i < p_scan->i_service; i++ )
516 if( p_scan->pp_service[i]->i_program == i_program )
517 return p_scan->pp_service[i];
519 return NULL;
522 /* FIXME handle properly string (convert to utf8) */
523 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
525 vlc_object_t *p_obj = p_session->p_obj;
527 msg_Dbg( p_obj, "PATCallBack" );
529 /* */
530 if( p_session->p_pat && p_session->p_pat->b_current_next )
532 dvbpsi_DeletePAT( p_session->p_pat );
533 p_session->p_pat = NULL;
535 if( p_session->p_pat )
537 dvbpsi_DeletePAT( p_pat );
538 return;
541 dvbpsi_pat_program_t *p_program;
543 /* */
544 p_session->p_pat = p_pat;
546 /* */
547 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
548 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
549 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
551 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
552 if( p_program->i_number == 0 )
553 p_session->i_nit_pid = p_program->i_pid;
556 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
558 vlc_object_t *p_obj = p_session->p_obj;
560 msg_Dbg( p_obj, "SDTCallBack" );
562 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
564 dvbpsi_DeleteSDT( p_session->p_sdt );
565 p_session->p_sdt = NULL;
567 if( p_session->p_sdt )
569 dvbpsi_DeleteSDT( p_sdt );
570 return;
573 /* */
574 p_session->p_sdt = p_sdt;
576 /* */
577 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
578 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
579 p_sdt->i_network_id );
582 dvbpsi_sdt_service_t *p_srv;
583 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
585 dvbpsi_descriptor_t *p_dr;
587 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
588 p_srv->i_service_id, p_srv->b_eit_schedule,
589 p_srv->b_eit_present, p_srv->i_running_status,
590 p_srv->b_free_ca );
591 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
593 if( p_dr->i_tag == 0x48 )
595 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
596 char str2[257];
598 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
599 str2[pD->i_service_name_length] = '\0';
601 msg_Dbg( p_obj, " - type=%d name=%s",
602 pD->i_service_type, str2 );
604 else
606 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
612 #ifdef DVBPSI_USE_NIT
613 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
615 vlc_object_t *p_obj = p_session->p_obj;
617 msg_Dbg( p_obj, "NITCallBack" );
618 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
619 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
621 /* */
622 if( p_session->p_nit && p_session->p_nit->b_current_next )
624 dvbpsi_DeleteNIT( p_session->p_nit );
625 p_session->p_nit = NULL;
627 if( p_session->p_nit )
629 dvbpsi_DeleteNIT( p_nit );
630 return;
633 /* */
634 p_session->p_nit = p_nit;
636 dvbpsi_descriptor_t *p_dsc;
637 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
639 if( p_dsc->i_tag == 0x40 )
641 msg_Dbg( p_obj, " * network name descriptor" );
642 char str1[257];
644 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
645 str1[p_dsc->i_length] = '\0';
646 msg_Dbg( p_obj, " * name %s", str1 );
648 else if( p_dsc->i_tag == 0x4a )
650 msg_Dbg( p_obj, " * linkage descriptor" );
651 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
652 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
653 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
654 int i_linkage_type = p_dsc->p_data[6];
656 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
657 msg_Dbg( p_obj, " * on_id %d", i_on_id );
658 msg_Dbg( p_obj, " * service_id %d", i_service_id );
659 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
661 else
663 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
667 dvbpsi_nit_ts_t *p_ts;
668 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
670 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
672 uint32_t i_private_data_id = 0;
673 dvbpsi_descriptor_t *p_dsc;
674 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
676 if( p_dsc->i_tag == 0x41 )
678 msg_Dbg( p_obj, " * service list descriptor" );
679 for( int i = 0; i < p_dsc->i_length/3; i++ )
681 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
682 uint8_t i_service_type = p_dsc->p_data[3*i+2];
683 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
686 else if( p_dsc->i_tag == 0x5a )
688 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
689 msg_Dbg( p_obj, " * terrestrial delivery system" );
690 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
691 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
692 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
693 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
694 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
695 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
696 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
697 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
699 else if( p_dsc->i_tag == 0x5f )
701 msg_Dbg( p_obj, " * private data specifier descriptor" );
702 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
703 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
705 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
707 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
708 for( int i = 0; i < p_dsc->i_length/4; i++ )
710 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
711 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
712 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
716 else
718 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
723 #endif
725 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
727 if( i_table_id == 0x42 )
728 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
729 #ifdef DVBPSI_USE_NIT
730 else if( i_table_id == 0x40 )
731 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
732 #endif
736 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
738 /* */
739 memset( p_session, 0, sizeof(*p_session) );
740 p_session->p_obj = p_obj;
741 p_session->cfg = *p_cfg;
742 p_session->i_snr = -1;
743 p_session->pat = NULL;
744 p_session->p_pat = NULL;
745 p_session->i_nit_pid = -1;
746 p_session->sdt = NULL;
747 p_session->p_sdt = NULL;
748 #ifdef DVBPSI_USE_NIT
749 p_session->nit = NULL;
750 p_session->p_nit = NULL;
751 #endif
752 return VLC_SUCCESS;
755 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
757 const int i_service_start = p_scan->i_service;
759 dvbpsi_pat_t *p_pat = p_session->p_pat;
760 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
762 #ifdef DVBPSI_USE_NIT
763 dvbpsi_nit_t *p_nit = p_session->p_nit;
764 #endif
766 if( p_pat )
768 /* Parse PAT */
769 dvbpsi_pat_program_t *p_program;
770 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
772 if( p_program->i_number == 0 ) /* NIT */
773 continue;
775 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
776 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
779 /* Parse SDT */
780 if( p_pat && p_sdt )
782 dvbpsi_sdt_service_t *p_srv;
783 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
785 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
786 dvbpsi_descriptor_t *p_dr;
788 if( s )
789 s->b_crypted = p_srv->b_free_ca;
791 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
793 if( p_dr->i_tag == 0x48 )
795 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
797 if( s )
799 if( !s->psz_name )
800 s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length );
802 if( s->type == SERVICE_UNKNOWN )
804 switch( pD->i_service_type )
806 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
807 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
808 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
809 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
818 #ifdef DVBPSI_USE_NIT
819 /* Parse NIT */
820 if( p_pat && p_nit )
822 dvbpsi_nit_ts_t *p_ts;
823 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
825 uint32_t i_private_data_id = 0;
826 dvbpsi_descriptor_t *p_dsc;
828 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
829 continue;
831 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
833 if( p_dsc->i_tag == 0x5f )
835 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
837 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
839 for( int i = 0; i < p_dsc->i_length/4; i++ )
841 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
842 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
844 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
845 if( s && s->i_channel < 0 )
846 s->i_channel = i_channel_number;
852 #endif
854 /* */
855 for( int i = i_service_start; i < p_scan->i_service; i++ )
857 scan_service_t *p_srv = p_scan->pp_service[i];
859 p_srv->i_snr = p_session->i_snr;
860 if( p_sdt )
861 p_srv->i_sdt_version = p_sdt->i_version;
862 #ifdef DVBPSI_USE_NIT
863 if( p_nit )
865 p_srv->i_network_id = p_nit->i_network_id;
866 p_srv->i_nit_version = p_nit->i_version;
868 #endif
872 /* */
873 if( p_session->pat )
874 dvbpsi_DetachPAT( p_session->pat );
875 if( p_session->p_pat )
876 dvbpsi_DeletePAT( p_session->p_pat );
878 if( p_session->sdt )
879 dvbpsi_DetachDemux( p_session->sdt );
880 if( p_session->p_sdt )
881 dvbpsi_DeleteSDT( p_session->p_sdt );
882 #ifdef DVBPSI_USE_NIT
883 if( p_session->nit )
884 dvbpsi_DetachDemux( p_session->nit );
885 if( p_session->p_nit )
886 dvbpsi_DeleteNIT( p_session->p_nit );
887 #endif
890 static int ScanServiceCmp( const void *a, const void *b )
892 scan_service_t *sa = *(scan_service_t**)a;
893 scan_service_t *sb = *(scan_service_t**)b;
895 if( sa->i_channel == sb->i_channel )
897 if( sa->psz_name && sb->psz_name )
898 return strcmp( sa->psz_name, sb->psz_name );
899 return 0;
901 if( sa->i_channel == -1 )
902 return 1;
903 else if( sb->i_channel == -1 )
904 return -1;
906 if( sa->i_channel < sb->i_channel )
907 return -1;
908 else if( sa->i_channel > sb->i_channel )
909 return 1;
910 return 0;
913 static block_t *BlockString( const char *psz )
915 block_t *p = block_Alloc( strlen(psz) );
916 if( p )
917 memcpy( p->p_buffer, psz, p->i_buffer );
918 return p;
921 block_t *scan_GetM3U( scan_t *p_scan )
923 vlc_object_t *p_obj = p_scan->p_obj;
924 block_t *p_playlist = NULL;
926 if( p_scan->i_service <= 0 )
927 return NULL;
929 /* */
930 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
932 /* */
933 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
935 for( int i = 0; i < p_scan->i_service; i++ )
937 scan_service_t *s = p_scan->pp_service[i];
939 if( s->type == SERVICE_UNKNOWN )
941 /* We should only select service that have been described by SDT */
942 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
943 continue;
946 const char *psz_type;
947 switch( s->type )
949 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
950 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
951 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
952 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
953 default:
954 psz_type = "Unknown";
955 break;
957 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",
958 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
959 s->i_network_id, s->i_nit_version, s->i_sdt_version,
960 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
962 if( !s->cfg.i_fec )
963 s->cfg.i_fec = 9; /* FEC_AUTO */
965 char *psz;
966 if( asprintf( &psz, "#EXTINF:,,%s\n"
967 "#EXTVLCOPT:program=%d\n"
968 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
969 "\n",
970 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
971 s->i_program,
972 s->cfg.i_frequency,
973 s->cfg.i_bandwidth,
974 s->cfg.c_polarization == 'H' ? 18 : 13,
975 s->cfg.i_fec ) < 0 )
976 psz = NULL;
977 if( psz )
979 block_t *p_block = BlockString( psz );
980 if( p_block )
981 block_ChainAppend( &p_playlist, p_block );
985 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
988 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
990 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
992 block_Release( p_block );
993 return false;
996 /* */
997 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
998 if( i_pid == 0x00 )
1000 if( !p_scan->pat )
1001 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1003 if( p_scan->pat )
1004 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1006 else if( i_pid == 0x11 )
1008 if( !p_scan->sdt )
1009 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1011 if( p_scan->sdt )
1012 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1014 else if( i_pid == p_scan->i_nit_pid )
1016 #ifdef DVBPSI_USE_NIT
1017 if( !p_scan->nit )
1018 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1020 if( p_scan->nit )
1021 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1022 #endif
1025 block_Release( p_block );
1027 return p_scan->p_pat && p_scan->p_sdt &&
1028 #ifdef DVBPSI_USE_NIT
1029 p_scan->p_nit;
1030 #else
1031 true;
1032 #endif
1035 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1037 p_session->i_snr = i_snr;