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>
35 #include <vlc_charset.h>
37 #include <sys/types.h>
39 /* Include dvbpsi headers */
40 #include <dvbpsi/dvbpsi.h>
41 #include <dvbpsi/descriptor.h>
42 #include <dvbpsi/pat.h>
43 #include <dvbpsi/pmt.h>
44 #include <dvbpsi/dr.h>
45 #include <dvbpsi/psi.h>
46 #include <dvbpsi/demux.h>
47 #include <dvbpsi/sdt.h>
48 #ifdef _DVBPSI_DR_43_H_
49 # define DVBPSI_USE_NIT 1
50 # include <dvbpsi/nit.h>
54 #include "../../demux/dvb-text.h"
59 SERVICE_DIGITAL_RADIO,
60 SERVICE_DIGITAL_TELEVISION,
61 SERVICE_DIGITAL_TELEVISION_AC_SD,
62 SERVICE_DIGITAL_TELEVISION_AC_HD,
63 } scan_service_type_t;
67 int i_program; /* program number (service id) */
68 scan_configuration_t cfg;
71 scan_service_type_t type;
72 char *psz_name; /* channel name in utf8 or NULL */
73 int i_channel; /* -1 if unknown */
74 bool b_crypted; /* True if potentially crypted */
86 struct dialog_progress_bar_t *p_dialog;
88 scan_parameter_t parameter;
92 scan_service_t **pp_service;
99 scan_configuration_t cfg;
109 #ifdef DVBPSI_USE_NIT
113 # warning NIT is not supported by your libdvbpsi version
119 static scan_service_t *scan_service_New( int i_program,
120 const scan_configuration_t *p_cfg )
122 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
126 p_srv->i_program = i_program;
130 p_srv->type = SERVICE_UNKNOWN;
131 p_srv->psz_name = NULL;
132 p_srv->i_channel = -1;
133 p_srv->b_crypted = false;
135 p_srv->i_network_id = -1;
136 p_srv->i_nit_version = -1;
137 p_srv->i_sdt_version = -1;
142 static void scan_service_Delete( scan_service_t *p_srv )
144 free( p_srv->psz_name );
149 scan_t *scan_New( vlc_object_t *p_obj, const scan_parameter_t *p_parameter )
151 if( p_parameter->type == SCAN_DVB_T )
153 msg_Dbg( p_obj, "DVB-T scanning:" );
154 msg_Dbg( p_obj, " - frequency [%d, %d]",
155 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
156 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
157 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
158 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
160 else if( p_parameter->type == SCAN_DVB_C )
162 msg_Dbg( p_obj, "DVB-C scanning:" );
163 msg_Dbg( p_obj, " - frequency [%d, %d]",
164 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
165 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
166 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
167 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
168 msg_Dbg( p_obj, " - scannin modulations %s", p_parameter->b_modulation_set ? "off" : "on" );
170 else if( p_parameter->type == SCAN_DVB_S )
172 msg_Dbg( p_obj, "DVB-S scanning:" );
173 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
179 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
180 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
182 scan_t *p_scan = malloc( sizeof( *p_scan ) );
183 if( unlikely(p_scan == NULL) )
186 p_scan->p_obj = VLC_OBJECT(p_obj);
188 p_scan->p_dialog = NULL;
189 TAB_INIT( p_scan->i_service, p_scan->pp_service );
190 p_scan->parameter = *p_parameter;
191 p_scan->i_time_start = mdate();
196 void scan_Destroy( scan_t *p_scan )
198 if( p_scan->p_dialog != NULL )
199 dialog_ProgressDestroy( p_scan->p_dialog );
201 for( int i = 0; i < p_scan->i_service; i++ )
202 scan_service_Delete( p_scan->pp_service[i] );
203 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
207 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
209 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
211 int *pi_count = &p_scan->parameter.sat_info.i_count;
213 if( !p_scan->parameter.sat_info.psz_name )
215 msg_Err( p_scan->p_obj, "no satellite selected" );
219 /* if there are no transponders in mem, laod from config file */
224 char *psz_dir = NULL;
225 char *data_dir = config_GetDataDir( p_scan->p_obj );
227 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
233 free( p_scan->parameter.sat_info.psz_name );
237 /* open config directory */
238 if( !( p_dir = vlc_opendir( psz_dir ) ) )
240 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
241 free( p_scan->parameter.sat_info.psz_name );
245 /* find the requested file in the directory */
249 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
252 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
254 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
255 p_scan->parameter.sat_info.psz_path = NULL;
257 free( psz_filename );
264 if( !p_scan->parameter.sat_info.psz_path )
266 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
267 free( p_scan->parameter.sat_info.psz_name );
271 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
273 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
278 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
285 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
287 &p_transponders[*pi_count].i_frequency,
288 &p_transponders[*pi_count].c_polarization,
289 &p_transponders[*pi_count].i_symbol_rate,
292 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
297 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
298 char *p_fec = strstr( psz_fec_list, psz_fec );
300 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
302 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
306 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
307 } while (res != EOF);
309 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
312 p_scan->parameter.sat_info.p_transponders = p_transponders;
316 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
317 free( p_scan->parameter.sat_info.psz_name );
318 free( p_scan->parameter.sat_info.psz_path );
321 free( p_scan->parameter.sat_info.psz_name );
322 free( p_scan->parameter.sat_info.psz_path );
325 if( p_scan->i_index < *pi_count )
327 /* setup params for scan */
328 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
329 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
330 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
331 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
333 msg_Dbg( p_scan->p_obj,
334 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
338 p_cfg->i_symbol_rate,
340 p_cfg->c_polarization );
342 *pf_pos = (double)p_scan->i_index / *pi_count;
347 if( p_scan->parameter.sat_info.p_transponders )
349 free( p_scan->parameter.sat_info.p_transponders );
350 p_scan->parameter.sat_info.p_transponders = NULL;
356 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
358 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
359 /* Values taken from dvb-scan utils frequency-files, sorted by how
360 * often they appear. This hopefully speeds up finding services. */
361 static const unsigned short frequencies[] = {
362 410, 426, 418, 394, 402, 362,
363 370, 354, 346, 442, 434, 386,
364 378, 450, 306, 162, 154, 474,
365 466, 458, 338, 754, 714, 586,
366 562, 546, 514, 490, 314, 170,
367 113, 770, 762, 746, 738, 730,
368 722, 706, 690, 682, 674, 666,
369 650, 642, 634, 554, 538, 530,
370 506, 498, 330, 322, 283, 850,
371 842, 834, 818, 810, 802, 794,
372 786, 778, 748, 732, 728, 724,
373 720, 698, 660, 658, 656, 610,
374 594, 578, 570, 522, 482, 377,
375 372, 347, 339, 323, 315, 299,
376 298, 291, 275, 267, 259, 255,
377 251, 243, 235, 232, 227, 219,
378 211, 203, 195, 187, 179, 171,
379 163, 155, 147, 146, 143, 139,
382 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
384 if( p_scan->i_index < num_frequencies )
386 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
387 *pf_pos = (double)p_scan->i_index / num_frequencies;
393 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
395 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
398 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
399 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
401 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
402 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
404 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
408 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
410 static const int i_band_count = 2;
413 const char *psz_name;
422 const int i_offset_count = 5;
423 const int i_mhz = 1000000;
425 /* We will probe the whole band divided in all bandwidth possibility trying
426 * i_offset_count offset around the position
428 for( ;; p_scan->i_index++ )
431 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
432 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
433 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
435 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
438 for( i = 0; i < i_band_count; i++ )
440 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
443 if( i >=i_band_count )
445 if( i_fi > band[i_band_count-1].i_max )
450 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
451 const int i_frequency_base = i_fi*i_mhz;
453 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
455 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
457 if( i_frequency < p_scan->parameter.frequency.i_min ||
458 i_frequency > p_scan->parameter.frequency.i_max )
461 p_cfg->i_frequency = i_frequency;
462 p_cfg->i_bandwidth = i_bandwidth;
464 int i_current = 0, i_total = 0;
465 for( int i = 0; i < i_band_count; i++ )
467 const int i_frag = band[i].i_max-band[i].i_min;
469 if( i_fi >= band[i].i_min )
470 i_current += __MIN( i_fi - band[i].i_min, i_frag );
474 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
480 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
482 if( p_scan->parameter.b_exhaustive )
483 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
485 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
488 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
490 if( p_scan->parameter.b_exhaustive )
491 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
493 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
496 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
498 if( p_scan->parameter.b_exhaustive )
499 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
501 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
504 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
509 if( scan_IsCancelled( p_scan ) )
512 memset( p_cfg, 0, sizeof(*p_cfg) );
513 switch( p_scan->parameter.type )
516 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
519 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
522 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
525 i_ret = VLC_EGENERIC;
535 for( int i = 0; i < p_scan->i_service; i++ )
537 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
541 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
542 char psz_eta[MSTRTIME_MAX_SIZE];
544 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
545 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
548 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
550 if( p_scan->p_dialog == NULL )
551 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
552 if( p_scan->p_dialog != NULL )
553 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
557 if( i_service == 0 &&
558 p_scan->parameter.type == SCAN_DVB_C &&
559 !p_scan->parameter.b_modulation_set )
561 p_scan->parameter.i_modulation = (p_scan->parameter.i_modulation << 1 ) % 512;
562 /* if we iterated all modulations, move on */
563 if( !p_cfg->i_modulation )
565 p_scan->parameter.i_modulation = 16;
568 msg_Dbg( p_scan->p_obj, "modulation %d ", p_cfg->i_modulation );
572 if( p_scan->parameter.type == SCAN_DVB_C )
573 p_cfg->i_modulation = p_scan->parameter.i_modulation;
577 bool scan_IsCancelled( scan_t *p_scan )
579 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
582 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
584 for( int i = i_service_start; i < p_scan->i_service; i++ )
586 if( p_scan->pp_service[i]->i_program == i_program )
587 return p_scan->pp_service[i];
592 /* FIXME handle properly string (convert to utf8) */
593 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
595 vlc_object_t *p_obj = p_session->p_obj;
597 msg_Dbg( p_obj, "PATCallBack" );
600 if( p_session->p_pat && p_session->p_pat->b_current_next )
602 dvbpsi_DeletePAT( p_session->p_pat );
603 p_session->p_pat = NULL;
605 if( p_session->p_pat )
607 dvbpsi_DeletePAT( p_pat );
611 dvbpsi_pat_program_t *p_program;
614 p_session->p_pat = p_pat;
617 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
618 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
619 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
621 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
622 if( p_program->i_number == 0 )
623 p_session->i_nit_pid = p_program->i_pid;
626 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
628 vlc_object_t *p_obj = p_session->p_obj;
630 msg_Dbg( p_obj, "SDTCallBack" );
632 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
634 dvbpsi_DeleteSDT( p_session->p_sdt );
635 p_session->p_sdt = NULL;
637 if( p_session->p_sdt )
639 dvbpsi_DeleteSDT( p_sdt );
644 p_session->p_sdt = p_sdt;
647 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
648 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
649 p_sdt->i_network_id );
652 dvbpsi_sdt_service_t *p_srv;
653 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
655 dvbpsi_descriptor_t *p_dr;
657 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
658 p_srv->i_service_id, p_srv->b_eit_schedule,
659 p_srv->b_eit_present, p_srv->i_running_status,
661 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
663 if( p_dr->i_tag == 0x48 )
665 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
668 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
669 str2[pD->i_service_name_length] = '\0';
671 msg_Dbg( p_obj, " - type=%d name=%s",
672 pD->i_service_type, str2 );
676 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
682 #ifdef DVBPSI_USE_NIT
683 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
685 vlc_object_t *p_obj = p_session->p_obj;
687 msg_Dbg( p_obj, "NITCallBack" );
688 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
689 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
692 if( p_session->p_nit && p_session->p_nit->b_current_next )
694 dvbpsi_DeleteNIT( p_session->p_nit );
695 p_session->p_nit = NULL;
697 if( p_session->p_nit )
699 dvbpsi_DeleteNIT( p_nit );
704 p_session->p_nit = p_nit;
706 dvbpsi_descriptor_t *p_dsc;
707 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
709 if( p_dsc->i_tag == 0x40 )
711 msg_Dbg( p_obj, " * network name descriptor" );
714 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
715 str1[p_dsc->i_length] = '\0';
716 msg_Dbg( p_obj, " * name %s", str1 );
718 else if( p_dsc->i_tag == 0x4a )
720 msg_Dbg( p_obj, " * linkage descriptor" );
721 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
722 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
723 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
724 int i_linkage_type = p_dsc->p_data[6];
726 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
727 msg_Dbg( p_obj, " * on_id %d", i_on_id );
728 msg_Dbg( p_obj, " * service_id %d", i_service_id );
729 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
733 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
737 dvbpsi_nit_ts_t *p_ts;
738 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
740 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
742 uint32_t i_private_data_id = 0;
743 dvbpsi_descriptor_t *p_dsc;
744 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
746 if( p_dsc->i_tag == 0x41 )
748 msg_Dbg( p_obj, " * service list descriptor" );
749 for( int i = 0; i < p_dsc->i_length/3; i++ )
751 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
752 uint8_t i_service_type = p_dsc->p_data[3*i+2];
753 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
756 else if( p_dsc->i_tag == 0x5a )
758 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
759 msg_Dbg( p_obj, " * terrestrial delivery system" );
760 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
761 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
762 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
763 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
764 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
765 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
766 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
767 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
769 else if( p_dsc->i_tag == 0x5f )
771 msg_Dbg( p_obj, " * private data specifier descriptor" );
772 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
773 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
775 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
777 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
778 for( int i = 0; i < p_dsc->i_length/4; i++ )
780 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
781 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
782 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
788 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
795 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
797 if( i_table_id == 0x42 )
798 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
799 #ifdef DVBPSI_USE_NIT
800 else if( i_table_id == 0x40 )
801 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
805 scan_session_t *scan_session_New( vlc_object_t *p_obj,
806 const scan_configuration_t *p_cfg )
808 scan_session_t *p_session = malloc( sizeof( *p_session ) );
809 if( unlikely(p_session == NULL) )
811 p_session->p_obj = p_obj;
812 p_session->cfg = *p_cfg;
813 p_session->i_snr = -1;
814 p_session->pat = NULL;
815 p_session->p_pat = NULL;
816 p_session->i_nit_pid = -1;
817 p_session->sdt = NULL;
818 p_session->p_sdt = NULL;
819 #ifdef DVBPSI_USE_NIT
820 p_session->nit = NULL;
821 p_session->p_nit = NULL;
826 void scan_session_Destroy( scan_t *p_scan, scan_session_t *p_session )
828 const int i_service_start = p_scan->i_service;
830 dvbpsi_pat_t *p_pat = p_session->p_pat;
831 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
833 #ifdef DVBPSI_USE_NIT
834 dvbpsi_nit_t *p_nit = p_session->p_nit;
840 dvbpsi_pat_program_t *p_program;
841 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
843 if( p_program->i_number == 0 ) /* NIT */
846 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
847 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
853 dvbpsi_sdt_service_t *p_srv;
854 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
856 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
857 dvbpsi_descriptor_t *p_dr;
860 s->b_crypted = p_srv->b_free_ca;
862 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
864 if( p_dr->i_tag == 0x48 )
866 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
871 s->psz_name = vlc_from_EIT( pD->i_service_name,
872 pD->i_service_name_length );
874 if( s->type == SERVICE_UNKNOWN )
876 switch( pD->i_service_type )
878 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
879 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
880 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
881 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
890 #ifdef DVBPSI_USE_NIT
894 dvbpsi_nit_ts_t *p_ts;
895 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
897 uint32_t i_private_data_id = 0;
898 dvbpsi_descriptor_t *p_dsc;
900 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
903 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
905 if( p_dsc->i_tag == 0x5f )
907 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
909 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
911 for( int i = 0; i < p_dsc->i_length/4; i++ )
913 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
914 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
916 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
917 if( s && s->i_channel < 0 )
918 s->i_channel = i_channel_number;
927 for( int i = i_service_start; i < p_scan->i_service; i++ )
929 scan_service_t *p_srv = p_scan->pp_service[i];
931 p_srv->i_snr = p_session->i_snr;
933 p_srv->i_sdt_version = p_sdt->i_version;
934 #ifdef DVBPSI_USE_NIT
937 p_srv->i_network_id = p_nit->i_network_id;
938 p_srv->i_nit_version = p_nit->i_version;
946 dvbpsi_DetachPAT( p_session->pat );
947 if( p_session->p_pat )
948 dvbpsi_DeletePAT( p_session->p_pat );
951 dvbpsi_DetachDemux( p_session->sdt );
952 if( p_session->p_sdt )
953 dvbpsi_DeleteSDT( p_session->p_sdt );
954 #ifdef DVBPSI_USE_NIT
956 dvbpsi_DetachDemux( p_session->nit );
957 if( p_session->p_nit )
958 dvbpsi_DeleteNIT( p_session->p_nit );
963 static int ScanServiceCmp( const void *a, const void *b )
965 scan_service_t *sa = *(scan_service_t**)a;
966 scan_service_t *sb = *(scan_service_t**)b;
968 if( sa->i_channel == sb->i_channel )
970 if( sa->psz_name && sb->psz_name )
971 return strcmp( sa->psz_name, sb->psz_name );
974 if( sa->i_channel == -1 )
976 else if( sb->i_channel == -1 )
979 if( sa->i_channel < sb->i_channel )
981 else if( sa->i_channel > sb->i_channel )
986 static block_t *BlockString( const char *psz )
988 block_t *p = block_Alloc( strlen(psz) );
990 memcpy( p->p_buffer, psz, p->i_buffer );
994 block_t *scan_GetM3U( scan_t *p_scan )
996 vlc_object_t *p_obj = p_scan->p_obj;
997 block_t *p_playlist = NULL;
999 if( p_scan->i_service <= 0 )
1003 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
1006 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
1008 for( int i = 0; i < p_scan->i_service; i++ )
1010 scan_service_t *s = p_scan->pp_service[i];
1012 if( s->type == SERVICE_UNKNOWN )
1014 /* We should only select service that have been described by SDT */
1015 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
1019 const char *psz_type;
1022 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
1023 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
1024 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
1025 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
1027 psz_type = "Unknown";
1030 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 modulation=%d",
1031 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
1032 s->i_network_id, s->i_nit_version, s->i_sdt_version,
1033 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr, s->cfg.i_modulation );
1036 s->cfg.i_fec = 9; /* FEC_AUTO */
1039 if( asprintf( &psz, "#EXTINF:,,%s\n"
1040 "#EXTVLCOPT:program=%d\n"
1041 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d:modulation=%d\n"
1043 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
1047 s->cfg.c_polarization == 'H' ? 18 : 13,
1049 s->cfg.i_modulation ) < 0 )
1053 block_t *p_block = BlockString( psz );
1055 block_ChainAppend( &p_playlist, p_block );
1059 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
1062 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
1064 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
1066 block_Release( p_block );
1071 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1075 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1078 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1080 else if( i_pid == 0x11 )
1083 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1086 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1088 else if( i_pid == p_scan->i_nit_pid )
1090 #ifdef DVBPSI_USE_NIT
1092 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1095 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1099 block_Release( p_block );
1101 return p_scan->p_pat && p_scan->p_sdt &&
1102 #ifdef DVBPSI_USE_NIT
1109 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1111 p_session->i_snr = i_snr;