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 # include <dvbpsi/dvbpsi.h>
46 # include <dvbpsi/descriptor.h>
47 # include <dvbpsi/pat.h>
48 # include <dvbpsi/pmt.h>
49 # include <dvbpsi/dr.h>
50 # include <dvbpsi/psi.h>
51 # include <dvbpsi/demux.h>
52 # include <dvbpsi/sdt.h>
55 # include <vlc_httpd.h>
61 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg )
63 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
67 p_srv->i_program = i_program;
71 p_srv->type = SERVICE_UNKNOWN;
72 p_srv->psz_name = NULL;
73 p_srv->i_channel = -1;
74 p_srv->b_crypted = false;
76 p_srv->i_network_id = -1;
77 p_srv->i_nit_version = -1;
78 p_srv->i_sdt_version = -1;
83 void scan_service_Delete( scan_service_t *p_srv )
85 free( p_srv->psz_name );
90 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
92 if( p_parameter->type == SCAN_DVB_T )
94 msg_Dbg( p_obj, "DVB-T scanning:" );
95 msg_Dbg( p_obj, " - frequency [%d, %d]",
96 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
97 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
98 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
99 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
101 else if( p_parameter->type == SCAN_DVB_C )
103 msg_Dbg( p_obj, "DVB-C 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" );
110 else if( p_parameter->type == SCAN_DVB_S )
112 msg_Dbg( p_obj, "DVB-S scanning:" );
113 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
119 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
120 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
122 p_scan->p_obj = VLC_OBJECT(p_obj);
124 p_scan->p_dialog = NULL;
125 TAB_INIT( p_scan->i_service, p_scan->pp_service );
126 p_scan->parameter = *p_parameter;
127 p_scan->i_time_start = mdate();
132 void scan_Clean( scan_t *p_scan )
134 if( p_scan->p_dialog != NULL )
135 dialog_ProgressDestroy( p_scan->p_dialog );
137 for( int i = 0; i < p_scan->i_service; i++ )
138 scan_service_Delete( p_scan->pp_service[i] );
139 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
142 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
144 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
146 int *pi_count = &p_scan->parameter.sat_info.i_count;
148 if( !p_scan->parameter.sat_info.psz_name )
150 msg_Err( p_scan->p_obj, "no satellite selected" );
154 /* if there are no transponders in mem, laod from config file */
159 char *psz_dir = NULL;
160 char *data_dir = config_GetDataDir( p_scan->p_obj );
162 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
168 free( p_scan->parameter.sat_info.psz_name );
172 /* open config directory */
173 if( !( p_dir = vlc_opendir( psz_dir ) ) )
175 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
176 free( p_scan->parameter.sat_info.psz_name );
180 /* find the requested file in the directory */
184 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
187 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
189 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
190 p_scan->parameter.sat_info.psz_path = NULL;
192 free( psz_filename );
199 if( !p_scan->parameter.sat_info.psz_path )
201 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
202 free( p_scan->parameter.sat_info.psz_name );
206 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
208 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
213 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
220 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
222 &p_transponders[*pi_count].i_frequency,
223 &p_transponders[*pi_count].c_polarization,
224 &p_transponders[*pi_count].i_symbol_rate,
227 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
232 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
233 char *p_fec = strstr( psz_fec_list, psz_fec );
235 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
237 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
241 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
242 } while (res != EOF);
244 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
247 p_scan->parameter.sat_info.p_transponders = p_transponders;
251 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
252 free( p_scan->parameter.sat_info.psz_name );
253 free( p_scan->parameter.sat_info.psz_path );
256 free( p_scan->parameter.sat_info.psz_name );
257 free( p_scan->parameter.sat_info.psz_path );
260 if( p_scan->i_index < *pi_count )
262 /* setup params for scan */
263 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
264 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
265 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
266 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
268 msg_Dbg( p_scan->p_obj,
269 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
273 p_cfg->i_symbol_rate,
275 p_cfg->c_polarization );
277 *pf_pos = (double)p_scan->i_index / *pi_count;
282 if( p_scan->parameter.sat_info.p_transponders )
284 free( p_scan->parameter.sat_info.p_transponders );
285 p_scan->parameter.sat_info.p_transponders = NULL;
291 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
293 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
294 /* Values taken from dvb-scan utils frequency-files, sorted by how
295 * often they appear. This hopefully speeds up finding services. */
296 static const unsigned short frequencies[] = {
297 410, 426, 418, 394, 402, 362,
298 370, 354, 346, 442, 434, 386,
299 378, 450, 306, 162, 154, 474,
300 466, 458, 338, 754, 714, 586,
301 562, 546, 514, 490, 314, 170,
302 113, 770, 762, 746, 738, 730,
303 722, 706, 690, 682, 674, 666,
304 650, 642, 634, 554, 538, 530,
305 506, 498, 330, 322, 283, 850,
306 842, 834, 818, 810, 802, 794,
307 786, 778, 748, 732, 728, 724,
308 720, 698, 660, 658, 656, 610,
309 594, 578, 570, 522, 482, 377,
310 372, 347, 339, 323, 315, 299,
311 298, 291, 275, 267, 259, 255,
312 251, 243, 235, 232, 227, 219,
313 211, 203, 195, 187, 179, 171,
314 163, 155, 147, 146, 143, 139,
317 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
319 if( p_scan->i_index < num_frequencies )
321 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
322 *pf_pos = (double)p_scan->i_index / num_frequencies;
328 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
330 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
333 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
334 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
336 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
337 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
339 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
343 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
345 static const int i_band_count = 2;
348 const char *psz_name;
357 const int i_offset_count = 5;
358 const int i_mhz = 1000000;
360 /* We will probe the whole band divided in all bandwidth possibility trying
361 * i_offset_count offset around the position
363 for( ;; p_scan->i_index++ )
366 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
367 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
368 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
370 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
373 for( i = 0; i < i_band_count; i++ )
375 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
378 if( i >=i_band_count )
380 if( i_fi > band[i_band_count-1].i_max )
385 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
386 const int i_frequency_base = i_fi*i_mhz;
388 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
390 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
392 if( i_frequency < p_scan->parameter.frequency.i_min ||
393 i_frequency > p_scan->parameter.frequency.i_max )
396 p_cfg->i_frequency = i_frequency;
397 p_cfg->i_bandwidth = i_bandwidth;
399 int i_current = 0, i_total = 0;
400 for( int i = 0; i < i_band_count; i++ )
402 const int i_frag = band[i].i_max-band[i].i_min;
404 if( i_fi >= band[i].i_min )
405 i_current += __MIN( i_fi - band[i].i_min, i_frag );
409 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
415 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
417 if( p_scan->parameter.b_exhaustive )
418 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
420 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
423 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
425 if( p_scan->parameter.b_exhaustive )
426 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
428 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
431 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
433 if( p_scan->parameter.b_exhaustive )
434 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
436 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
439 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
444 if( scan_IsCancelled( p_scan ) )
447 memset( p_cfg, 0, sizeof(*p_cfg) );
448 switch( p_scan->parameter.type )
451 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
454 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
457 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
460 i_ret = VLC_EGENERIC;
470 for( int i = 0; i < p_scan->i_service; i++ )
472 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
476 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
477 char psz_eta[MSTRTIME_MAX_SIZE];
479 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
480 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
483 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
485 if( p_scan->p_dialog == NULL )
486 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
487 if( p_scan->p_dialog != NULL )
488 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
496 bool scan_IsCancelled( scan_t *p_scan )
498 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
501 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
503 for( int i = i_service_start; i < p_scan->i_service; i++ )
505 if( p_scan->pp_service[i]->i_program == i_program )
506 return p_scan->pp_service[i];
511 /* FIXME handle properly string (convert to utf8) */
512 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
514 vlc_object_t *p_obj = p_session->p_obj;
516 msg_Dbg( p_obj, "PATCallBack" );
519 if( p_session->p_pat && p_session->p_pat->b_current_next )
521 dvbpsi_DeletePAT( p_session->p_pat );
522 p_session->p_pat = NULL;
524 if( p_session->p_pat )
526 dvbpsi_DeletePAT( p_pat );
530 dvbpsi_pat_program_t *p_program;
533 p_session->p_pat = p_pat;
536 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
537 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
538 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
540 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
541 if( p_program->i_number == 0 )
542 p_session->i_nit_pid = p_program->i_pid;
545 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
547 vlc_object_t *p_obj = p_session->p_obj;
549 msg_Dbg( p_obj, "SDTCallBack" );
551 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
553 dvbpsi_DeleteSDT( p_session->p_sdt );
554 p_session->p_sdt = NULL;
556 if( p_session->p_sdt )
558 dvbpsi_DeleteSDT( p_sdt );
563 p_session->p_sdt = p_sdt;
566 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
567 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
568 p_sdt->i_network_id );
571 dvbpsi_sdt_service_t *p_srv;
572 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
574 dvbpsi_descriptor_t *p_dr;
576 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
577 p_srv->i_service_id, p_srv->b_eit_schedule,
578 p_srv->b_eit_present, p_srv->i_running_status,
580 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
582 if( p_dr->i_tag == 0x48 )
584 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
587 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
588 str2[pD->i_service_name_length] = '\0';
590 msg_Dbg( p_obj, " - type=%d name=%s",
591 pD->i_service_type, str2 );
595 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
601 #ifdef DVBPSI_USE_NIT
602 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
604 vlc_object_t *p_obj = p_session->p_obj;
606 msg_Dbg( p_obj, "NITCallBack" );
607 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
608 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
611 if( p_session->p_nit && p_session->p_nit->b_current_next )
613 dvbpsi_DeleteNIT( p_session->p_nit );
614 p_session->p_nit = NULL;
616 if( p_session->p_nit )
618 dvbpsi_DeleteNIT( p_nit );
623 p_session->p_nit = p_nit;
625 dvbpsi_descriptor_t *p_dsc;
626 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
628 if( p_dsc->i_tag == 0x40 )
630 msg_Dbg( p_obj, " * network name descriptor" );
633 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
634 str1[p_dsc->i_length] = '\0';
635 msg_Dbg( p_obj, " * name %s", str1 );
637 else if( p_dsc->i_tag == 0x4a )
639 msg_Dbg( p_obj, " * linkage descriptor" );
640 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
641 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
642 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
643 int i_linkage_type = p_dsc->p_data[6];
645 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
646 msg_Dbg( p_obj, " * on_id %d", i_on_id );
647 msg_Dbg( p_obj, " * service_id %d", i_service_id );
648 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
652 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
656 dvbpsi_nit_ts_t *p_ts;
657 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
659 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
661 uint32_t i_private_data_id = 0;
662 dvbpsi_descriptor_t *p_dsc;
663 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
665 if( p_dsc->i_tag == 0x41 )
667 msg_Dbg( p_obj, " * service list descriptor" );
668 for( int i = 0; i < p_dsc->i_length/3; i++ )
670 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
671 uint8_t i_service_type = p_dsc->p_data[3*i+2];
672 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
675 else if( p_dsc->i_tag == 0x5a )
677 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
678 msg_Dbg( p_obj, " * terrestrial delivery system" );
679 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
680 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
681 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
682 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
683 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
684 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
685 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
686 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
688 else if( p_dsc->i_tag == 0x5f )
690 msg_Dbg( p_obj, " * private data specifier descriptor" );
691 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
692 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
694 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
696 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
697 for( int i = 0; i < p_dsc->i_length/4; i++ )
699 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
700 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
701 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
707 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
714 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
716 if( i_table_id == 0x42 )
717 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
718 #ifdef DVBPSI_USE_NIT
719 else if( i_table_id == 0x40 )
720 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
725 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
728 memset( p_session, 0, sizeof(*p_session) );
729 p_session->p_obj = p_obj;
730 p_session->cfg = *p_cfg;
731 p_session->i_snr = -1;
732 p_session->pat = NULL;
733 p_session->p_pat = NULL;
734 p_session->i_nit_pid = -1;
735 p_session->sdt = NULL;
736 p_session->p_sdt = NULL;
737 #ifdef DVBPSI_USE_NIT
738 p_session->nit = NULL;
739 p_session->p_nit = NULL;
744 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
746 const int i_service_start = p_scan->i_service;
748 dvbpsi_pat_t *p_pat = p_session->p_pat;
749 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
751 #ifdef DVBPSI_USE_NIT
752 dvbpsi_nit_t *p_nit = p_session->p_nit;
758 dvbpsi_pat_program_t *p_program;
759 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
761 if( p_program->i_number == 0 ) /* NIT */
764 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
765 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
771 dvbpsi_sdt_service_t *p_srv;
772 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
774 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
775 dvbpsi_descriptor_t *p_dr;
778 s->b_crypted = p_srv->b_free_ca;
780 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
782 if( p_dr->i_tag == 0x48 )
784 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
789 s->psz_name = dvbsi_to_utf8( (const char *)pD->i_service_name, pD->i_service_name_length );
791 if( s->type == SERVICE_UNKNOWN )
793 switch( pD->i_service_type )
795 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
796 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
797 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
798 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
807 #ifdef DVBPSI_USE_NIT
811 dvbpsi_nit_ts_t *p_ts;
812 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
814 uint32_t i_private_data_id = 0;
815 dvbpsi_descriptor_t *p_dsc;
817 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
820 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
822 if( p_dsc->i_tag == 0x5f )
824 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
826 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
828 for( int i = 0; i < p_dsc->i_length/4; i++ )
830 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
831 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
833 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
834 if( s && s->i_channel < 0 )
835 s->i_channel = i_channel_number;
844 for( int i = i_service_start; i < p_scan->i_service; i++ )
846 scan_service_t *p_srv = p_scan->pp_service[i];
848 p_srv->i_snr = p_session->i_snr;
850 p_srv->i_sdt_version = p_sdt->i_version;
851 #ifdef DVBPSI_USE_NIT
854 p_srv->i_network_id = p_nit->i_network_id;
855 p_srv->i_nit_version = p_nit->i_version;
863 dvbpsi_DetachPAT( p_session->pat );
864 if( p_session->p_pat )
865 dvbpsi_DeletePAT( p_session->p_pat );
868 dvbpsi_DetachDemux( p_session->sdt );
869 if( p_session->p_sdt )
870 dvbpsi_DeleteSDT( p_session->p_sdt );
871 #ifdef DVBPSI_USE_NIT
873 dvbpsi_DetachDemux( p_session->nit );
874 if( p_session->p_nit )
875 dvbpsi_DeleteNIT( p_session->p_nit );
879 static int ScanServiceCmp( const void *a, const void *b )
881 scan_service_t *sa = *(scan_service_t**)a;
882 scan_service_t *sb = *(scan_service_t**)b;
884 if( sa->i_channel == sb->i_channel )
886 if( sa->psz_name && sb->psz_name )
887 return strcmp( sa->psz_name, sb->psz_name );
890 if( sa->i_channel == -1 )
892 else if( sb->i_channel == -1 )
895 if( sa->i_channel < sb->i_channel )
897 else if( sa->i_channel > sb->i_channel )
902 static block_t *BlockString( const char *psz )
904 block_t *p = block_Alloc( strlen(psz) );
906 memcpy( p->p_buffer, psz, p->i_buffer );
910 block_t *scan_GetM3U( scan_t *p_scan )
912 vlc_object_t *p_obj = p_scan->p_obj;
913 block_t *p_playlist = NULL;
915 if( p_scan->i_service <= 0 )
919 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
922 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
924 for( int i = 0; i < p_scan->i_service; i++ )
926 scan_service_t *s = p_scan->pp_service[i];
928 if( s->type == SERVICE_UNKNOWN )
930 /* We should only select service that have been described by SDT */
931 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
935 const char *psz_type;
938 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
939 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
940 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
941 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
943 psz_type = "Unknown";
946 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",
947 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
948 s->i_network_id, s->i_nit_version, s->i_sdt_version,
949 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
952 s->cfg.i_fec = 9; /* FEC_AUTO */
955 if( asprintf( &psz, "#EXTINF:,,%s\n"
956 "#EXTVLCOPT:program=%d\n"
957 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
959 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
963 s->cfg.c_polarization == 'H' ? 18 : 13,
968 block_t *p_block = BlockString( psz );
970 block_ChainAppend( &p_playlist, p_block );
974 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
977 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
979 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
981 block_Release( p_block );
986 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
990 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
993 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
995 else if( i_pid == 0x11 )
998 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1001 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1003 else if( i_pid == p_scan->i_nit_pid )
1005 #ifdef DVBPSI_USE_NIT
1007 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1010 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1014 block_Release( p_block );
1016 return p_scan->p_pat && p_scan->p_sdt &&
1017 #ifdef DVBPSI_USE_NIT
1024 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1026 p_session->i_snr = i_snr;