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_block.h>
33 #include <vlc_dialog.h>
36 #include <sys/types.h>
38 /* Include dvbpsi headers */
39 # include <dvbpsi/dvbpsi.h>
40 # include <dvbpsi/descriptor.h>
41 # include <dvbpsi/pat.h>
42 # include <dvbpsi/pmt.h>
43 # include <dvbpsi/dr.h>
44 # include <dvbpsi/psi.h>
45 # include <dvbpsi/demux.h>
46 # include <dvbpsi/sdt.h>
51 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg )
53 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
57 p_srv->i_program = i_program;
61 p_srv->type = SERVICE_UNKNOWN;
62 p_srv->psz_name = NULL;
63 p_srv->i_channel = -1;
64 p_srv->b_crypted = false;
66 p_srv->i_network_id = -1;
67 p_srv->i_nit_version = -1;
68 p_srv->i_sdt_version = -1;
73 void scan_service_Delete( scan_service_t *p_srv )
75 free( p_srv->psz_name );
80 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
82 if( p_parameter->type == SCAN_DVB_T )
84 msg_Dbg( p_obj, "DVB-T scanning:" );
85 msg_Dbg( p_obj, " - frequency [%d, %d]",
86 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
87 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
88 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
89 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
91 else if( p_parameter->type == SCAN_DVB_C )
93 msg_Dbg( p_obj, "DVB-C scanning:" );
94 msg_Dbg( p_obj, " - frequency [%d, %d]",
95 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
96 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
97 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
98 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
100 else if( p_parameter->type == SCAN_DVB_S )
102 msg_Dbg( p_obj, "DVB-S scanning:" );
103 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
109 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
110 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
112 p_scan->p_obj = VLC_OBJECT(p_obj);
114 p_scan->p_dialog = NULL;
115 TAB_INIT( p_scan->i_service, p_scan->pp_service );
116 p_scan->parameter = *p_parameter;
117 p_scan->i_time_start = mdate();
122 void scan_Clean( scan_t *p_scan )
124 if( p_scan->p_dialog != NULL )
125 dialog_ProgressDestroy( p_scan->p_dialog );
127 for( int i = 0; i < p_scan->i_service; i++ )
128 scan_service_Delete( p_scan->pp_service[i] );
129 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
132 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
134 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
136 int *pi_count = &p_scan->parameter.sat_info.i_count;
138 if( !p_scan->parameter.sat_info.psz_name )
140 msg_Err( p_scan->p_obj, "no satellite selected" );
144 /* if there are no transponders in mem, laod from config file */
149 char *psz_dir = NULL;
150 char *data_dir = config_GetDataDir( p_scan->p_obj );
152 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
158 free( p_scan->parameter.sat_info.psz_name );
162 /* open config directory */
163 if( !( p_dir = vlc_opendir( psz_dir ) ) )
165 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
166 free( p_scan->parameter.sat_info.psz_name );
170 /* find the requested file in the directory */
174 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
177 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
179 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
180 p_scan->parameter.sat_info.psz_path = NULL;
182 free( psz_filename );
189 if( !p_scan->parameter.sat_info.psz_path )
191 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
192 free( p_scan->parameter.sat_info.psz_name );
196 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
198 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
203 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
210 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
212 &p_transponders[*pi_count].i_frequency,
213 &p_transponders[*pi_count].c_polarization,
214 &p_transponders[*pi_count].i_symbol_rate,
217 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
222 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
223 char *p_fec = strstr( psz_fec_list, psz_fec );
225 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
227 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
231 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
232 } while (res != EOF);
234 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
237 p_scan->parameter.sat_info.p_transponders = p_transponders;
241 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
242 free( p_scan->parameter.sat_info.psz_name );
243 free( p_scan->parameter.sat_info.psz_path );
246 free( p_scan->parameter.sat_info.psz_name );
247 free( p_scan->parameter.sat_info.psz_path );
250 if( p_scan->i_index < *pi_count )
252 /* setup params for scan */
253 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
254 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
255 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
256 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
258 msg_Dbg( p_scan->p_obj,
259 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
263 p_cfg->i_symbol_rate,
265 p_cfg->c_polarization );
267 *pf_pos = (double)p_scan->i_index / *pi_count;
272 if( p_scan->parameter.sat_info.p_transponders )
274 free( p_scan->parameter.sat_info.p_transponders );
275 p_scan->parameter.sat_info.p_transponders = NULL;
281 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
283 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
284 /* Values taken from dvb-scan utils frequency-files, sorted by how
285 * often they appear. This hopefully speeds up finding services. */
286 static const unsigned short frequencies[] = {
287 410, 426, 418, 394, 402, 362,
288 370, 354, 346, 442, 434, 386,
289 378, 450, 306, 162, 154, 474,
290 466, 458, 338, 754, 714, 586,
291 562, 546, 514, 490, 314, 170,
292 113, 770, 762, 746, 738, 730,
293 722, 706, 690, 682, 674, 666,
294 650, 642, 634, 554, 538, 530,
295 506, 498, 330, 322, 283, 850,
296 842, 834, 818, 810, 802, 794,
297 786, 778, 748, 732, 728, 724,
298 720, 698, 660, 658, 656, 610,
299 594, 578, 570, 522, 482, 377,
300 372, 347, 339, 323, 315, 299,
301 298, 291, 275, 267, 259, 255,
302 251, 243, 235, 232, 227, 219,
303 211, 203, 195, 187, 179, 171,
304 163, 155, 147, 146, 143, 139,
307 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
309 if( p_scan->i_index < num_frequencies )
311 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
312 *pf_pos = (double)p_scan->i_index / num_frequencies;
318 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
320 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
323 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
324 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
326 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
327 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
329 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
333 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
335 static const int i_band_count = 2;
338 const char *psz_name;
347 const int i_offset_count = 5;
348 const int i_mhz = 1000000;
350 /* We will probe the whole band divided in all bandwidth possibility trying
351 * i_offset_count offset around the position
353 for( ;; p_scan->i_index++ )
356 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
357 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
358 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
360 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
363 for( i = 0; i < i_band_count; i++ )
365 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
368 if( i >=i_band_count )
370 if( i_fi > band[i_band_count-1].i_max )
375 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
376 const int i_frequency_base = i_fi*i_mhz;
378 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
380 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
382 if( i_frequency < p_scan->parameter.frequency.i_min ||
383 i_frequency > p_scan->parameter.frequency.i_max )
386 p_cfg->i_frequency = i_frequency;
387 p_cfg->i_bandwidth = i_bandwidth;
389 int i_current = 0, i_total = 0;
390 for( int i = 0; i < i_band_count; i++ )
392 const int i_frag = band[i].i_max-band[i].i_min;
394 if( i_fi >= band[i].i_min )
395 i_current += __MIN( i_fi - band[i].i_min, i_frag );
399 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
405 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
407 if( p_scan->parameter.b_exhaustive )
408 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
410 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
413 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
415 if( p_scan->parameter.b_exhaustive )
416 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
418 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
421 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
423 if( p_scan->parameter.b_exhaustive )
424 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
426 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
429 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
434 if( scan_IsCancelled( p_scan ) )
437 memset( p_cfg, 0, sizeof(*p_cfg) );
438 switch( p_scan->parameter.type )
441 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
444 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
447 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
450 i_ret = VLC_EGENERIC;
460 for( int i = 0; i < p_scan->i_service; i++ )
462 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
466 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
467 char psz_eta[MSTRTIME_MAX_SIZE];
469 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
470 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
473 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
475 if( p_scan->p_dialog == NULL )
476 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
477 if( p_scan->p_dialog != NULL )
478 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
486 bool scan_IsCancelled( scan_t *p_scan )
488 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
491 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
493 for( int i = i_service_start; i < p_scan->i_service; i++ )
495 if( p_scan->pp_service[i]->i_program == i_program )
496 return p_scan->pp_service[i];
501 /* FIXME handle properly string (convert to utf8) */
502 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
504 vlc_object_t *p_obj = p_session->p_obj;
506 msg_Dbg( p_obj, "PATCallBack" );
509 if( p_session->p_pat && p_session->p_pat->b_current_next )
511 dvbpsi_DeletePAT( p_session->p_pat );
512 p_session->p_pat = NULL;
514 if( p_session->p_pat )
516 dvbpsi_DeletePAT( p_pat );
520 dvbpsi_pat_program_t *p_program;
523 p_session->p_pat = p_pat;
526 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
527 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
528 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
530 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
531 if( p_program->i_number == 0 )
532 p_session->i_nit_pid = p_program->i_pid;
535 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
537 vlc_object_t *p_obj = p_session->p_obj;
539 msg_Dbg( p_obj, "SDTCallBack" );
541 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
543 dvbpsi_DeleteSDT( p_session->p_sdt );
544 p_session->p_sdt = NULL;
546 if( p_session->p_sdt )
548 dvbpsi_DeleteSDT( p_sdt );
553 p_session->p_sdt = p_sdt;
556 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
557 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
558 p_sdt->i_network_id );
561 dvbpsi_sdt_service_t *p_srv;
562 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
564 dvbpsi_descriptor_t *p_dr;
566 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
567 p_srv->i_service_id, p_srv->b_eit_schedule,
568 p_srv->b_eit_present, p_srv->i_running_status,
570 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
572 if( p_dr->i_tag == 0x48 )
574 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
577 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
578 str2[pD->i_service_name_length] = '\0';
580 msg_Dbg( p_obj, " - type=%d name=%s",
581 pD->i_service_type, str2 );
585 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
591 #ifdef DVBPSI_USE_NIT
592 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
594 vlc_object_t *p_obj = p_session->p_obj;
596 msg_Dbg( p_obj, "NITCallBack" );
597 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
598 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
601 if( p_session->p_nit && p_session->p_nit->b_current_next )
603 dvbpsi_DeleteNIT( p_session->p_nit );
604 p_session->p_nit = NULL;
606 if( p_session->p_nit )
608 dvbpsi_DeleteNIT( p_nit );
613 p_session->p_nit = p_nit;
615 dvbpsi_descriptor_t *p_dsc;
616 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
618 if( p_dsc->i_tag == 0x40 )
620 msg_Dbg( p_obj, " * network name descriptor" );
623 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
624 str1[p_dsc->i_length] = '\0';
625 msg_Dbg( p_obj, " * name %s", str1 );
627 else if( p_dsc->i_tag == 0x4a )
629 msg_Dbg( p_obj, " * linkage descriptor" );
630 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
631 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
632 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
633 int i_linkage_type = p_dsc->p_data[6];
635 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
636 msg_Dbg( p_obj, " * on_id %d", i_on_id );
637 msg_Dbg( p_obj, " * service_id %d", i_service_id );
638 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
642 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
646 dvbpsi_nit_ts_t *p_ts;
647 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
649 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
651 uint32_t i_private_data_id = 0;
652 dvbpsi_descriptor_t *p_dsc;
653 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
655 if( p_dsc->i_tag == 0x41 )
657 msg_Dbg( p_obj, " * service list descriptor" );
658 for( int i = 0; i < p_dsc->i_length/3; i++ )
660 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
661 uint8_t i_service_type = p_dsc->p_data[3*i+2];
662 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
665 else if( p_dsc->i_tag == 0x5a )
667 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
668 msg_Dbg( p_obj, " * terrestrial delivery system" );
669 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
670 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
671 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
672 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
673 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
674 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
675 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
676 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
678 else if( p_dsc->i_tag == 0x5f )
680 msg_Dbg( p_obj, " * private data specifier descriptor" );
681 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
682 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
684 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
686 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
687 for( int i = 0; i < p_dsc->i_length/4; i++ )
689 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
690 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
691 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
697 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
704 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
706 if( i_table_id == 0x42 )
707 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
708 #ifdef DVBPSI_USE_NIT
709 else if( i_table_id == 0x40 )
710 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
715 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
718 memset( p_session, 0, sizeof(*p_session) );
719 p_session->p_obj = p_obj;
720 p_session->cfg = *p_cfg;
721 p_session->i_snr = -1;
722 p_session->pat = NULL;
723 p_session->p_pat = NULL;
724 p_session->i_nit_pid = -1;
725 p_session->sdt = NULL;
726 p_session->p_sdt = NULL;
727 #ifdef DVBPSI_USE_NIT
728 p_session->nit = NULL;
729 p_session->p_nit = NULL;
734 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
736 const int i_service_start = p_scan->i_service;
738 dvbpsi_pat_t *p_pat = p_session->p_pat;
739 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
741 #ifdef DVBPSI_USE_NIT
742 dvbpsi_nit_t *p_nit = p_session->p_nit;
748 dvbpsi_pat_program_t *p_program;
749 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
751 if( p_program->i_number == 0 ) /* NIT */
754 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
755 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
761 dvbpsi_sdt_service_t *p_srv;
762 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
764 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
765 dvbpsi_descriptor_t *p_dr;
768 s->b_crypted = p_srv->b_free_ca;
770 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
772 if( p_dr->i_tag == 0x48 )
774 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
779 s->psz_name = dvbsi_to_utf8( (const char *)pD->i_service_name, pD->i_service_name_length );
781 if( s->type == SERVICE_UNKNOWN )
783 switch( pD->i_service_type )
785 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
786 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
787 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
788 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
797 #ifdef DVBPSI_USE_NIT
801 dvbpsi_nit_ts_t *p_ts;
802 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
804 uint32_t i_private_data_id = 0;
805 dvbpsi_descriptor_t *p_dsc;
807 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
810 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
812 if( p_dsc->i_tag == 0x5f )
814 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
816 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
818 for( int i = 0; i < p_dsc->i_length/4; i++ )
820 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
821 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
823 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
824 if( s && s->i_channel < 0 )
825 s->i_channel = i_channel_number;
834 for( int i = i_service_start; i < p_scan->i_service; i++ )
836 scan_service_t *p_srv = p_scan->pp_service[i];
838 p_srv->i_snr = p_session->i_snr;
840 p_srv->i_sdt_version = p_sdt->i_version;
841 #ifdef DVBPSI_USE_NIT
844 p_srv->i_network_id = p_nit->i_network_id;
845 p_srv->i_nit_version = p_nit->i_version;
853 dvbpsi_DetachPAT( p_session->pat );
854 if( p_session->p_pat )
855 dvbpsi_DeletePAT( p_session->p_pat );
858 dvbpsi_DetachDemux( p_session->sdt );
859 if( p_session->p_sdt )
860 dvbpsi_DeleteSDT( p_session->p_sdt );
861 #ifdef DVBPSI_USE_NIT
863 dvbpsi_DetachDemux( p_session->nit );
864 if( p_session->p_nit )
865 dvbpsi_DeleteNIT( p_session->p_nit );
869 static int ScanServiceCmp( const void *a, const void *b )
871 scan_service_t *sa = *(scan_service_t**)a;
872 scan_service_t *sb = *(scan_service_t**)b;
874 if( sa->i_channel == sb->i_channel )
876 if( sa->psz_name && sb->psz_name )
877 return strcmp( sa->psz_name, sb->psz_name );
880 if( sa->i_channel == -1 )
882 else if( sb->i_channel == -1 )
885 if( sa->i_channel < sb->i_channel )
887 else if( sa->i_channel > sb->i_channel )
892 static block_t *BlockString( const char *psz )
894 block_t *p = block_Alloc( strlen(psz) );
896 memcpy( p->p_buffer, psz, p->i_buffer );
900 block_t *scan_GetM3U( scan_t *p_scan )
902 vlc_object_t *p_obj = p_scan->p_obj;
903 block_t *p_playlist = NULL;
905 if( p_scan->i_service <= 0 )
909 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
912 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
914 for( int i = 0; i < p_scan->i_service; i++ )
916 scan_service_t *s = p_scan->pp_service[i];
918 if( s->type == SERVICE_UNKNOWN )
920 /* We should only select service that have been described by SDT */
921 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
925 const char *psz_type;
928 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
929 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
930 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
931 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
933 psz_type = "Unknown";
936 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",
937 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
938 s->i_network_id, s->i_nit_version, s->i_sdt_version,
939 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
942 s->cfg.i_fec = 9; /* FEC_AUTO */
945 if( asprintf( &psz, "#EXTINF:,,%s\n"
946 "#EXTVLCOPT:program=%d\n"
947 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
949 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
953 s->cfg.c_polarization == 'H' ? 18 : 13,
958 block_t *p_block = BlockString( psz );
960 block_ChainAppend( &p_playlist, p_block );
964 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
967 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
969 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
971 block_Release( p_block );
976 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
980 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
983 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
985 else if( i_pid == 0x11 )
988 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
991 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
993 else if( i_pid == p_scan->i_nit_pid )
995 #ifdef DVBPSI_USE_NIT
997 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1000 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1004 block_Release( p_block );
1006 return p_scan->p_pat && p_scan->p_sdt &&
1007 #ifdef DVBPSI_USE_NIT
1014 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1016 p_session->i_snr = i_snr;