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>
47 #ifdef _DVBPSI_DR_43_H_
48 # define DVBPSI_USE_NIT 1
49 # include <dvbpsi/nit.h>
58 SERVICE_DIGITAL_RADIO,
59 SERVICE_DIGITAL_TELEVISION,
60 SERVICE_DIGITAL_TELEVISION_AC_SD,
61 SERVICE_DIGITAL_TELEVISION_AC_HD,
62 } scan_service_type_t;
66 int i_program; /* program number (service id) */
67 scan_configuration_t cfg;
70 scan_service_type_t type;
71 char *psz_name; /* channel name in utf8 or NULL */
72 int i_channel; /* -1 if unknown */
73 bool b_crypted; /* True if potentially crypted */
85 struct dialog_progress_bar_t *p_dialog;
87 scan_parameter_t parameter;
91 scan_service_t **pp_service;
98 scan_configuration_t cfg;
108 #ifdef DVBPSI_USE_NIT
112 # warning NIT is not supported by your libdvbpsi version
118 static scan_service_t *scan_service_New( int i_program,
119 const scan_configuration_t *p_cfg )
121 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
125 p_srv->i_program = i_program;
129 p_srv->type = SERVICE_UNKNOWN;
130 p_srv->psz_name = NULL;
131 p_srv->i_channel = -1;
132 p_srv->b_crypted = false;
134 p_srv->i_network_id = -1;
135 p_srv->i_nit_version = -1;
136 p_srv->i_sdt_version = -1;
141 static void scan_service_Delete( scan_service_t *p_srv )
143 free( p_srv->psz_name );
148 scan_t *scan_New( vlc_object_t *p_obj, const scan_parameter_t *p_parameter )
150 if( p_parameter->type == SCAN_DVB_T )
152 msg_Dbg( p_obj, "DVB-T scanning:" );
153 msg_Dbg( p_obj, " - frequency [%d, %d]",
154 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
155 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
156 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
157 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
159 else if( p_parameter->type == SCAN_DVB_C )
161 msg_Dbg( p_obj, "DVB-C scanning:" );
162 msg_Dbg( p_obj, " - frequency [%d, %d]",
163 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
164 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
165 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
166 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
168 else if( p_parameter->type == SCAN_DVB_S )
170 msg_Dbg( p_obj, "DVB-S scanning:" );
171 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
177 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
178 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
180 scan_t *p_scan = malloc( sizeof( *p_scan ) );
181 if( unlikely(p_scan == NULL) )
184 p_scan->p_obj = VLC_OBJECT(p_obj);
186 p_scan->p_dialog = NULL;
187 TAB_INIT( p_scan->i_service, p_scan->pp_service );
188 p_scan->parameter = *p_parameter;
189 p_scan->i_time_start = mdate();
194 void scan_Destroy( scan_t *p_scan )
196 if( p_scan->p_dialog != NULL )
197 dialog_ProgressDestroy( p_scan->p_dialog );
199 for( int i = 0; i < p_scan->i_service; i++ )
200 scan_service_Delete( p_scan->pp_service[i] );
201 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
205 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
207 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
209 int *pi_count = &p_scan->parameter.sat_info.i_count;
211 if( !p_scan->parameter.sat_info.psz_name )
213 msg_Err( p_scan->p_obj, "no satellite selected" );
217 /* if there are no transponders in mem, laod from config file */
222 char *psz_dir = NULL;
223 char *data_dir = config_GetDataDir( p_scan->p_obj );
225 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
231 free( p_scan->parameter.sat_info.psz_name );
235 /* open config directory */
236 if( !( p_dir = vlc_opendir( psz_dir ) ) )
238 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
239 free( p_scan->parameter.sat_info.psz_name );
243 /* find the requested file in the directory */
247 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
250 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
252 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
253 p_scan->parameter.sat_info.psz_path = NULL;
255 free( psz_filename );
262 if( !p_scan->parameter.sat_info.psz_path )
264 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
265 free( p_scan->parameter.sat_info.psz_name );
269 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
271 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
276 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
283 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
285 &p_transponders[*pi_count].i_frequency,
286 &p_transponders[*pi_count].c_polarization,
287 &p_transponders[*pi_count].i_symbol_rate,
290 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
295 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
296 char *p_fec = strstr( psz_fec_list, psz_fec );
298 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
300 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
304 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
305 } while (res != EOF);
307 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
310 p_scan->parameter.sat_info.p_transponders = p_transponders;
314 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
315 free( p_scan->parameter.sat_info.psz_name );
316 free( p_scan->parameter.sat_info.psz_path );
319 free( p_scan->parameter.sat_info.psz_name );
320 free( p_scan->parameter.sat_info.psz_path );
323 if( p_scan->i_index < *pi_count )
325 /* setup params for scan */
326 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
327 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
328 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
329 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
331 msg_Dbg( p_scan->p_obj,
332 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
336 p_cfg->i_symbol_rate,
338 p_cfg->c_polarization );
340 *pf_pos = (double)p_scan->i_index / *pi_count;
345 if( p_scan->parameter.sat_info.p_transponders )
347 free( p_scan->parameter.sat_info.p_transponders );
348 p_scan->parameter.sat_info.p_transponders = NULL;
354 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
356 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
357 /* Values taken from dvb-scan utils frequency-files, sorted by how
358 * often they appear. This hopefully speeds up finding services. */
359 static const unsigned short frequencies[] = {
360 410, 426, 418, 394, 402, 362,
361 370, 354, 346, 442, 434, 386,
362 378, 450, 306, 162, 154, 474,
363 466, 458, 338, 754, 714, 586,
364 562, 546, 514, 490, 314, 170,
365 113, 770, 762, 746, 738, 730,
366 722, 706, 690, 682, 674, 666,
367 650, 642, 634, 554, 538, 530,
368 506, 498, 330, 322, 283, 850,
369 842, 834, 818, 810, 802, 794,
370 786, 778, 748, 732, 728, 724,
371 720, 698, 660, 658, 656, 610,
372 594, 578, 570, 522, 482, 377,
373 372, 347, 339, 323, 315, 299,
374 298, 291, 275, 267, 259, 255,
375 251, 243, 235, 232, 227, 219,
376 211, 203, 195, 187, 179, 171,
377 163, 155, 147, 146, 143, 139,
380 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
382 if( p_scan->i_index < num_frequencies )
384 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
385 *pf_pos = (double)p_scan->i_index / num_frequencies;
391 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
393 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
396 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
397 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
399 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
400 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
402 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
406 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
408 static const int i_band_count = 2;
411 const char *psz_name;
420 const int i_offset_count = 5;
421 const int i_mhz = 1000000;
423 /* We will probe the whole band divided in all bandwidth possibility trying
424 * i_offset_count offset around the position
426 for( ;; p_scan->i_index++ )
429 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
430 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
431 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
433 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
436 for( i = 0; i < i_band_count; i++ )
438 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
441 if( i >=i_band_count )
443 if( i_fi > band[i_band_count-1].i_max )
448 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
449 const int i_frequency_base = i_fi*i_mhz;
451 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
453 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
455 if( i_frequency < p_scan->parameter.frequency.i_min ||
456 i_frequency > p_scan->parameter.frequency.i_max )
459 p_cfg->i_frequency = i_frequency;
460 p_cfg->i_bandwidth = i_bandwidth;
462 int i_current = 0, i_total = 0;
463 for( int i = 0; i < i_band_count; i++ )
465 const int i_frag = band[i].i_max-band[i].i_min;
467 if( i_fi >= band[i].i_min )
468 i_current += __MIN( i_fi - band[i].i_min, i_frag );
472 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
478 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
480 if( p_scan->parameter.b_exhaustive )
481 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
483 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
486 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
488 if( p_scan->parameter.b_exhaustive )
489 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
491 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
494 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
496 if( p_scan->parameter.b_exhaustive )
497 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
499 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
502 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
507 if( scan_IsCancelled( p_scan ) )
510 memset( p_cfg, 0, sizeof(*p_cfg) );
511 switch( p_scan->parameter.type )
514 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
517 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
520 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
523 i_ret = VLC_EGENERIC;
533 for( int i = 0; i < p_scan->i_service; i++ )
535 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
539 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
540 char psz_eta[MSTRTIME_MAX_SIZE];
542 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
543 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
546 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
548 if( p_scan->p_dialog == NULL )
549 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
550 if( p_scan->p_dialog != NULL )
551 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
559 bool scan_IsCancelled( scan_t *p_scan )
561 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
564 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
566 for( int i = i_service_start; i < p_scan->i_service; i++ )
568 if( p_scan->pp_service[i]->i_program == i_program )
569 return p_scan->pp_service[i];
574 /* FIXME handle properly string (convert to utf8) */
575 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
577 vlc_object_t *p_obj = p_session->p_obj;
579 msg_Dbg( p_obj, "PATCallBack" );
582 if( p_session->p_pat && p_session->p_pat->b_current_next )
584 dvbpsi_DeletePAT( p_session->p_pat );
585 p_session->p_pat = NULL;
587 if( p_session->p_pat )
589 dvbpsi_DeletePAT( p_pat );
593 dvbpsi_pat_program_t *p_program;
596 p_session->p_pat = p_pat;
599 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
600 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
601 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
603 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
604 if( p_program->i_number == 0 )
605 p_session->i_nit_pid = p_program->i_pid;
608 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
610 vlc_object_t *p_obj = p_session->p_obj;
612 msg_Dbg( p_obj, "SDTCallBack" );
614 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
616 dvbpsi_DeleteSDT( p_session->p_sdt );
617 p_session->p_sdt = NULL;
619 if( p_session->p_sdt )
621 dvbpsi_DeleteSDT( p_sdt );
626 p_session->p_sdt = p_sdt;
629 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
630 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
631 p_sdt->i_network_id );
634 dvbpsi_sdt_service_t *p_srv;
635 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
637 dvbpsi_descriptor_t *p_dr;
639 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
640 p_srv->i_service_id, p_srv->b_eit_schedule,
641 p_srv->b_eit_present, p_srv->i_running_status,
643 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
645 if( p_dr->i_tag == 0x48 )
647 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
650 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
651 str2[pD->i_service_name_length] = '\0';
653 msg_Dbg( p_obj, " - type=%d name=%s",
654 pD->i_service_type, str2 );
658 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
664 #ifdef DVBPSI_USE_NIT
665 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
667 vlc_object_t *p_obj = p_session->p_obj;
669 msg_Dbg( p_obj, "NITCallBack" );
670 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
671 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
674 if( p_session->p_nit && p_session->p_nit->b_current_next )
676 dvbpsi_DeleteNIT( p_session->p_nit );
677 p_session->p_nit = NULL;
679 if( p_session->p_nit )
681 dvbpsi_DeleteNIT( p_nit );
686 p_session->p_nit = p_nit;
688 dvbpsi_descriptor_t *p_dsc;
689 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
691 if( p_dsc->i_tag == 0x40 )
693 msg_Dbg( p_obj, " * network name descriptor" );
696 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
697 str1[p_dsc->i_length] = '\0';
698 msg_Dbg( p_obj, " * name %s", str1 );
700 else if( p_dsc->i_tag == 0x4a )
702 msg_Dbg( p_obj, " * linkage descriptor" );
703 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
704 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
705 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
706 int i_linkage_type = p_dsc->p_data[6];
708 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
709 msg_Dbg( p_obj, " * on_id %d", i_on_id );
710 msg_Dbg( p_obj, " * service_id %d", i_service_id );
711 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
715 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
719 dvbpsi_nit_ts_t *p_ts;
720 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
722 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
724 uint32_t i_private_data_id = 0;
725 dvbpsi_descriptor_t *p_dsc;
726 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
728 if( p_dsc->i_tag == 0x41 )
730 msg_Dbg( p_obj, " * service list descriptor" );
731 for( int i = 0; i < p_dsc->i_length/3; i++ )
733 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
734 uint8_t i_service_type = p_dsc->p_data[3*i+2];
735 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
738 else if( p_dsc->i_tag == 0x5a )
740 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
741 msg_Dbg( p_obj, " * terrestrial delivery system" );
742 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
743 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
744 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
745 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
746 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
747 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
748 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
749 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
751 else if( p_dsc->i_tag == 0x5f )
753 msg_Dbg( p_obj, " * private data specifier descriptor" );
754 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
755 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
757 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
759 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
760 for( int i = 0; i < p_dsc->i_length/4; i++ )
762 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
763 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
764 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
770 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
777 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
779 if( i_table_id == 0x42 )
780 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
781 #ifdef DVBPSI_USE_NIT
782 else if( i_table_id == 0x40 )
783 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
787 scan_session_t *scan_session_New( vlc_object_t *p_obj,
788 const scan_configuration_t *p_cfg )
790 scan_session_t *p_session = malloc( sizeof( *p_session ) );
791 if( unlikely(p_session == NULL) )
793 p_session->p_obj = p_obj;
794 p_session->cfg = *p_cfg;
795 p_session->i_snr = -1;
796 p_session->pat = NULL;
797 p_session->p_pat = NULL;
798 p_session->i_nit_pid = -1;
799 p_session->sdt = NULL;
800 p_session->p_sdt = NULL;
801 #ifdef DVBPSI_USE_NIT
802 p_session->nit = NULL;
803 p_session->p_nit = NULL;
808 void scan_session_Destroy( scan_t *p_scan, scan_session_t *p_session )
810 const int i_service_start = p_scan->i_service;
812 dvbpsi_pat_t *p_pat = p_session->p_pat;
813 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
815 #ifdef DVBPSI_USE_NIT
816 dvbpsi_nit_t *p_nit = p_session->p_nit;
822 dvbpsi_pat_program_t *p_program;
823 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
825 if( p_program->i_number == 0 ) /* NIT */
828 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
829 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
835 dvbpsi_sdt_service_t *p_srv;
836 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
838 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
839 dvbpsi_descriptor_t *p_dr;
842 s->b_crypted = p_srv->b_free_ca;
844 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
846 if( p_dr->i_tag == 0x48 )
848 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
853 s->psz_name = dvbsi_to_utf8( (const char *)pD->i_service_name, pD->i_service_name_length );
855 if( s->type == SERVICE_UNKNOWN )
857 switch( pD->i_service_type )
859 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
860 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
861 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
862 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
871 #ifdef DVBPSI_USE_NIT
875 dvbpsi_nit_ts_t *p_ts;
876 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
878 uint32_t i_private_data_id = 0;
879 dvbpsi_descriptor_t *p_dsc;
881 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
884 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
886 if( p_dsc->i_tag == 0x5f )
888 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
890 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
892 for( int i = 0; i < p_dsc->i_length/4; i++ )
894 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
895 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
897 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
898 if( s && s->i_channel < 0 )
899 s->i_channel = i_channel_number;
908 for( int i = i_service_start; i < p_scan->i_service; i++ )
910 scan_service_t *p_srv = p_scan->pp_service[i];
912 p_srv->i_snr = p_session->i_snr;
914 p_srv->i_sdt_version = p_sdt->i_version;
915 #ifdef DVBPSI_USE_NIT
918 p_srv->i_network_id = p_nit->i_network_id;
919 p_srv->i_nit_version = p_nit->i_version;
927 dvbpsi_DetachPAT( p_session->pat );
928 if( p_session->p_pat )
929 dvbpsi_DeletePAT( p_session->p_pat );
932 dvbpsi_DetachDemux( p_session->sdt );
933 if( p_session->p_sdt )
934 dvbpsi_DeleteSDT( p_session->p_sdt );
935 #ifdef DVBPSI_USE_NIT
937 dvbpsi_DetachDemux( p_session->nit );
938 if( p_session->p_nit )
939 dvbpsi_DeleteNIT( p_session->p_nit );
944 static int ScanServiceCmp( const void *a, const void *b )
946 scan_service_t *sa = *(scan_service_t**)a;
947 scan_service_t *sb = *(scan_service_t**)b;
949 if( sa->i_channel == sb->i_channel )
951 if( sa->psz_name && sb->psz_name )
952 return strcmp( sa->psz_name, sb->psz_name );
955 if( sa->i_channel == -1 )
957 else if( sb->i_channel == -1 )
960 if( sa->i_channel < sb->i_channel )
962 else if( sa->i_channel > sb->i_channel )
967 static block_t *BlockString( const char *psz )
969 block_t *p = block_Alloc( strlen(psz) );
971 memcpy( p->p_buffer, psz, p->i_buffer );
975 block_t *scan_GetM3U( scan_t *p_scan )
977 vlc_object_t *p_obj = p_scan->p_obj;
978 block_t *p_playlist = NULL;
980 if( p_scan->i_service <= 0 )
984 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
987 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
989 for( int i = 0; i < p_scan->i_service; i++ )
991 scan_service_t *s = p_scan->pp_service[i];
993 if( s->type == SERVICE_UNKNOWN )
995 /* We should only select service that have been described by SDT */
996 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
1000 const char *psz_type;
1003 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
1004 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
1005 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
1006 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
1008 psz_type = "Unknown";
1011 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",
1012 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
1013 s->i_network_id, s->i_nit_version, s->i_sdt_version,
1014 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
1017 s->cfg.i_fec = 9; /* FEC_AUTO */
1020 if( asprintf( &psz, "#EXTINF:,,%s\n"
1021 "#EXTVLCOPT:program=%d\n"
1022 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
1024 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
1028 s->cfg.c_polarization == 'H' ? 18 : 13,
1029 s->cfg.i_fec ) < 0 )
1033 block_t *p_block = BlockString( psz );
1035 block_ChainAppend( &p_playlist, p_block );
1039 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
1042 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
1044 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
1046 block_Release( p_block );
1051 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1055 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1058 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1060 else if( i_pid == 0x11 )
1063 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1066 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1068 else if( i_pid == p_scan->i_nit_pid )
1070 #ifdef DVBPSI_USE_NIT
1072 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1075 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1079 block_Release( p_block );
1081 return p_scan->p_pat && p_scan->p_sdt &&
1082 #ifdef DVBPSI_USE_NIT
1089 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1091 p_session->i_snr = i_snr;