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 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_access.h>
34 #include <vlc_dialog.h>
41 #include <sys/types.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>
56 # include "descriptor.h"
57 # include "tables/pat.h"
58 # include "tables/pmt.h"
59 # include "descriptors/dr.h"
62 # include "tables/sdt.h"
66 # include <vlc_httpd.h>
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) );
78 p_srv->i_program = i_program;
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;
94 void scan_service_Delete( scan_service_t *p_srv )
96 free( p_srv->psz_name );
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 );
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);
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();
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" );
165 /* if there are no transponders in mem, laod from config file */
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 )
179 free( p_scan->parameter.sat_info.psz_name );
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 );
191 /* find the requested file in the directory */
195 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
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 );
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 );
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" );
224 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
231 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
233 &p_transponders[*pi_count].i_frequency,
234 &p_transponders[*pi_count].c_polarization,
235 &p_transponders[*pi_count].i_symbol_rate,
238 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
243 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
244 char *p_fec = strstr( psz_fec_list, psz_fec );
246 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
248 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
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);
258 p_scan->parameter.sat_info.p_transponders = p_transponders;
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 );
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",
284 p_cfg->i_symbol_rate,
286 p_cfg->c_polarization );
288 *pf_pos = (double)p_scan->i_index / *pi_count;
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;
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,
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;
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 )
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;
354 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
356 static const int i_band_count = 2;
359 const char *psz_name;
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;
384 for( i = 0; i < i_band_count; i++ )
386 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
389 if( i >=i_band_count )
391 if( i_fi > band[i_band_count-1].i_max )
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 )
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 );
420 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
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 );
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 );
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 )
455 if( scan_IsCancelled( p_scan ) )
458 memset( p_cfg, 0, sizeof(*p_cfg) );
459 switch( p_scan->parameter.type )
462 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
465 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
468 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
471 i_ret = VLC_EGENERIC;
481 for( int i = 0; i < p_scan->i_service; i++ )
483 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
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 )
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 );
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];
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" );
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 );
541 dvbpsi_pat_program_t *p_program;
544 p_session->p_pat = p_pat;
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 );
574 p_session->p_sdt = p_sdt;
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,
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 );
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 );
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 );
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 );
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" );
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 );
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 );
718 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
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 );
736 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
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;
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;
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 */
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 );
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;
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 );
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
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 )
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;
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;
861 p_srv->i_sdt_version = p_sdt->i_version;
862 #ifdef DVBPSI_USE_NIT
865 p_srv->i_network_id = p_nit->i_network_id;
866 p_srv->i_nit_version = p_nit->i_version;
874 dvbpsi_DetachPAT( p_session->pat );
875 if( p_session->p_pat )
876 dvbpsi_DeletePAT( p_session->p_pat );
879 dvbpsi_DetachDemux( p_session->sdt );
880 if( p_session->p_sdt )
881 dvbpsi_DeleteSDT( p_session->p_sdt );
882 #ifdef DVBPSI_USE_NIT
884 dvbpsi_DetachDemux( p_session->nit );
885 if( p_session->p_nit )
886 dvbpsi_DeleteNIT( p_session->p_nit );
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 );
901 if( sa->i_channel == -1 )
903 else if( sb->i_channel == -1 )
906 if( sa->i_channel < sb->i_channel )
908 else if( sa->i_channel > sb->i_channel )
913 static block_t *BlockString( const char *psz )
915 block_t *p = block_Alloc( strlen(psz) );
917 memcpy( p->p_buffer, psz, p->i_buffer );
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 )
930 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
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 );
946 const char *psz_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;
954 psz_type = "Unknown";
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 );
963 s->cfg.i_fec = 9; /* FEC_AUTO */
966 if( asprintf( &psz, "#EXTINF:,,%s\n"
967 "#EXTVLCOPT:program=%d\n"
968 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
970 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
974 s->cfg.c_polarization == 'H' ? 18 : 13,
979 block_t *p_block = BlockString( psz );
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 );
997 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1001 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1004 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1006 else if( i_pid == 0x11 )
1009 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
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
1018 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1021 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1025 block_Release( p_block );
1027 return p_scan->p_pat && p_scan->p_sdt &&
1028 #ifdef DVBPSI_USE_NIT
1035 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1037 p_session->i_snr = i_snr;