1 /*****************************************************************************
2 * scan.c: DVB scanner helpers
3 *****************************************************************************
4 * Copyright (C) 2008,2010 the VideoLAN team
6 * Authors: Laurent Aimar <fenrir@videolan.org>
7 * David Kaplan <david@2of1.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_access.h>
34 #include <vlc_dialog.h>
41 #include <sys/types.h>
44 /* Include dvbpsi headers */
45 #ifdef HAVE_DVBPSI_DR_H
46 # include <dvbpsi/dvbpsi.h>
47 # include <dvbpsi/descriptor.h>
48 # include <dvbpsi/pat.h>
49 # include <dvbpsi/pmt.h>
50 # include <dvbpsi/dr.h>
51 # include <dvbpsi/psi.h>
52 # include <dvbpsi/demux.h>
53 # include <dvbpsi/sdt.h>
56 # include "descriptor.h"
57 # include "tables/pat.h"
58 # include "tables/pmt.h"
59 # include "descriptors/dr.h"
62 # include "tables/sdt.h"
66 # include <vlc_httpd.h>
72 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg )
74 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
78 p_srv->i_program = i_program;
82 p_srv->type = SERVICE_UNKNOWN;
83 p_srv->psz_name = NULL;
84 p_srv->i_channel = -1;
85 p_srv->b_crypted = false;
87 p_srv->i_network_id = -1;
88 p_srv->i_nit_version = -1;
89 p_srv->i_sdt_version = -1;
94 void scan_service_Delete( scan_service_t *p_srv )
96 free( p_srv->psz_name );
101 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
103 if( p_parameter->type == SCAN_DVB_T )
105 msg_Dbg( p_obj, "DVB-T scanning:" );
106 msg_Dbg( p_obj, " - frequency [%d, %d]",
107 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
108 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
109 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
110 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
112 else if( p_parameter->type == SCAN_DVB_C )
114 msg_Dbg( p_obj, "DVB-C scanning:" );
115 msg_Dbg( p_obj, " - frequency [%d, %d]",
116 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
117 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
118 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
119 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
121 else if( p_parameter->type == SCAN_DVB_S )
123 msg_Dbg( p_obj, "DVB-S scanning:" );
124 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
130 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
131 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
133 p_scan->p_obj = VLC_OBJECT(p_obj);
135 p_scan->p_dialog = NULL;
136 TAB_INIT( p_scan->i_service, p_scan->pp_service );
137 p_scan->parameter = *p_parameter;
138 p_scan->i_time_start = mdate();
143 void scan_Clean( scan_t *p_scan )
145 if( p_scan->p_dialog != NULL )
146 dialog_ProgressDestroy( p_scan->p_dialog );
148 for( int i = 0; i < p_scan->i_service; i++ )
149 scan_service_Delete( p_scan->pp_service[i] );
150 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
153 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
155 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
157 int *pi_count = &p_scan->parameter.sat_info.i_count;
159 if( !p_scan->parameter.sat_info.psz_name )
161 msg_Err( p_scan->p_obj, "no satellite selected" );
165 /* if there are no transponders in mem, laod from config file */
168 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
172 char *psz_dir = NULL;
173 char *data_dir = config_GetDataDir( p_scan->p_obj );
175 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
181 free( p_scan->parameter.sat_info.psz_name );
185 /* open config directory */
186 if( !( p_dir = vlc_opendir( psz_dir ) ) )
188 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
189 free( p_scan->parameter.sat_info.psz_name );
193 /* find the requested file in the directory */
197 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
200 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
202 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
203 p_scan->parameter.sat_info.psz_path = NULL;
205 free( psz_filename );
212 if( !p_scan->parameter.sat_info.psz_path )
214 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
215 free( p_scan->parameter.sat_info.psz_name );
219 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
221 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
232 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
234 &p_transponders[*pi_count].i_frequency,
235 &p_transponders[*pi_count].c_polarization,
236 &p_transponders[*pi_count].i_symbol_rate,
239 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
244 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
245 char *p_fec = strstr( psz_fec_list, psz_fec );
247 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
249 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
253 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
254 } while (res != EOF);
256 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
262 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
263 free( p_scan->parameter.sat_info.psz_name );
264 free( p_scan->parameter.sat_info.psz_path );
267 free( p_scan->parameter.sat_info.psz_name );
268 free( p_scan->parameter.sat_info.psz_path );
270 p_scan->parameter.sat_info.p_transponders = p_transponders;
273 if( p_scan->i_index < *pi_count )
275 /* setup params for scan */
276 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
277 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
278 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
279 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
281 msg_Dbg( p_scan->p_obj,
282 "transponder [%d/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
286 p_cfg->i_symbol_rate,
288 p_cfg->c_polarization );
290 *pf_pos = (double)p_scan->i_index / *pi_count;
295 if( p_scan->parameter.sat_info.p_transponders )
297 free( p_scan->parameter.sat_info.p_transponders );
298 p_scan->parameter.sat_info.p_transponders = NULL;
304 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
306 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
307 /* Values taken from dvb-scan utils frequency-files, sorted by how
308 * often they appear. This hopefully speeds up finding services. */
309 static const unsigned short frequencies[] = {
310 410, 426, 418, 394, 402, 362,
311 370, 354, 346, 442, 434, 386,
312 378, 450, 306, 162, 154, 474,
313 466, 458, 338, 754, 714, 586,
314 562, 546, 514, 490, 314, 170,
315 113, 770, 762, 746, 738, 730,
316 722, 706, 690, 682, 674, 666,
317 650, 642, 634, 554, 538, 530,
318 506, 498, 330, 322, 283, 850,
319 842, 834, 818, 810, 802, 794,
320 786, 778, 748, 732, 728, 724,
321 720, 698, 660, 658, 656, 610,
322 594, 578, 570, 522, 482, 377,
323 372, 347, 339, 323, 315, 299,
324 298, 291, 275, 267, 259, 255,
325 251, 243, 235, 232, 227, 219,
326 211, 203, 195, 187, 179, 171,
327 163, 155, 147, 146, 143, 139,
330 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
332 if( p_scan->i_index < num_frequencies )
334 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
335 *pf_pos = (double)p_scan->i_index / num_frequencies;
341 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
343 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
346 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
347 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
349 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
350 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
352 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
356 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
358 static const int i_band_count = 2;
361 const char *psz_name;
370 const int i_offset_count = 5;
371 const int i_mhz = 1000000;
373 /* We will probe the whole band divided in all bandwidth possibility trying
374 * i_offset_count offset around the position
376 for( ;; p_scan->i_index++ )
379 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
380 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
381 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
383 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
386 for( i = 0; i < i_band_count; i++ )
388 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
391 if( i >=i_band_count )
393 if( i_fi > band[i_band_count-1].i_max )
398 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
399 const int i_frequency_base = i_fi*i_mhz;
401 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
403 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
405 if( i_frequency < p_scan->parameter.frequency.i_min ||
406 i_frequency > p_scan->parameter.frequency.i_max )
409 p_cfg->i_frequency = i_frequency;
410 p_cfg->i_bandwidth = i_bandwidth;
412 int i_current = 0, i_total = 0;
413 for( int i = 0; i < i_band_count; i++ )
415 const int i_frag = band[i].i_max-band[i].i_min;
417 if( i_fi >= band[i].i_min )
418 i_current += __MIN( i_fi - band[i].i_min, i_frag );
422 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
428 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
430 if( p_scan->parameter.b_exhaustive )
431 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
433 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
436 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
438 if( p_scan->parameter.b_exhaustive )
439 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
441 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
444 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
446 if( p_scan->parameter.b_exhaustive )
447 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
449 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
452 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
457 if( scan_IsCancelled( p_scan ) )
460 memset( p_cfg, 0, sizeof(*p_cfg) );
461 switch( p_scan->parameter.type )
464 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
467 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
470 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
473 i_ret = VLC_EGENERIC;
483 for( int i = 0; i < p_scan->i_service; i++ )
485 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
489 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
490 char psz_eta[MSTRTIME_MAX_SIZE];
492 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
493 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
496 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
498 if( p_scan->p_dialog == NULL )
499 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
500 if( p_scan->p_dialog != NULL )
501 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
509 bool scan_IsCancelled( scan_t *p_scan )
511 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
514 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
516 for( int i = i_service_start; i < p_scan->i_service; i++ )
518 if( p_scan->pp_service[i]->i_program == i_program )
519 return p_scan->pp_service[i];
524 /* FIXME handle properly string (convert to utf8) */
525 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
527 vlc_object_t *p_obj = p_session->p_obj;
529 msg_Dbg( p_obj, "PATCallBack" );
532 if( p_session->p_pat && p_session->p_pat->b_current_next )
534 dvbpsi_DeletePAT( p_session->p_pat );
535 p_session->p_pat = NULL;
537 if( p_session->p_pat )
539 dvbpsi_DeletePAT( p_pat );
543 dvbpsi_pat_program_t *p_program;
546 p_session->p_pat = p_pat;
549 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
550 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
551 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
553 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
554 if( p_program->i_number == 0 )
555 p_session->i_nit_pid = p_program->i_pid;
558 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
560 vlc_object_t *p_obj = p_session->p_obj;
562 msg_Dbg( p_obj, "SDTCallBack" );
564 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
566 dvbpsi_DeleteSDT( p_session->p_sdt );
567 p_session->p_sdt = NULL;
569 if( p_session->p_sdt )
571 dvbpsi_DeleteSDT( p_sdt );
576 p_session->p_sdt = p_sdt;
579 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
580 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
581 p_sdt->i_network_id );
584 dvbpsi_sdt_service_t *p_srv;
585 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
587 dvbpsi_descriptor_t *p_dr;
589 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
590 p_srv->i_service_id, p_srv->b_eit_schedule,
591 p_srv->b_eit_present, p_srv->i_running_status,
593 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
595 if( p_dr->i_tag == 0x48 )
597 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
600 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
601 str2[pD->i_service_name_length] = '\0';
603 msg_Dbg( p_obj, " - type=%d name=%s",
604 pD->i_service_type, str2 );
608 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
614 #ifdef DVBPSI_USE_NIT
615 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
617 vlc_object_t *p_obj = p_session->p_obj;
619 msg_Dbg( p_obj, "NITCallBack" );
620 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
621 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
624 if( p_session->p_nit && p_session->p_nit->b_current_next )
626 dvbpsi_DeleteNIT( p_session->p_nit );
627 p_session->p_nit = NULL;
629 if( p_session->p_nit )
631 dvbpsi_DeleteNIT( p_nit );
636 p_session->p_nit = p_nit;
638 dvbpsi_descriptor_t *p_dsc;
639 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
641 if( p_dsc->i_tag == 0x40 )
643 msg_Dbg( p_obj, " * network name descriptor" );
646 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
647 str1[p_dsc->i_length] = '\0';
648 msg_Dbg( p_obj, " * name %s", str1 );
650 else if( p_dsc->i_tag == 0x4a )
652 msg_Dbg( p_obj, " * linkage descriptor" );
653 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
654 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
655 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
656 int i_linkage_type = p_dsc->p_data[6];
658 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
659 msg_Dbg( p_obj, " * on_id %d", i_on_id );
660 msg_Dbg( p_obj, " * service_id %d", i_service_id );
661 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
665 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
669 dvbpsi_nit_ts_t *p_ts;
670 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
672 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
674 uint32_t i_private_data_id = 0;
675 dvbpsi_descriptor_t *p_dsc;
676 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
678 if( p_dsc->i_tag == 0x41 )
680 msg_Dbg( p_obj, " * service list descriptor" );
681 for( int i = 0; i < p_dsc->i_length/3; i++ )
683 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
684 uint8_t i_service_type = p_dsc->p_data[3*i+2];
685 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
688 else if( p_dsc->i_tag == 0x5a )
690 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
691 msg_Dbg( p_obj, " * terrestrial delivery system" );
692 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
693 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
694 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
695 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
696 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
697 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
698 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
699 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
701 else if( p_dsc->i_tag == 0x5f )
703 msg_Dbg( p_obj, " * private data specifier descriptor" );
704 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
705 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
707 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
709 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
710 for( int i = 0; i < p_dsc->i_length/4; i++ )
712 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
713 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
714 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
720 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
727 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
729 if( i_table_id == 0x42 )
730 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
731 #ifdef DVBPSI_USE_NIT
732 else if( i_table_id == 0x40 )
733 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
738 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
741 memset( p_session, 0, sizeof(*p_session) );
742 p_session->p_obj = p_obj;
743 p_session->cfg = *p_cfg;
744 p_session->i_snr = -1;
745 p_session->pat = NULL;
746 p_session->p_pat = NULL;
747 p_session->i_nit_pid = -1;
748 p_session->sdt = NULL;
749 p_session->p_sdt = NULL;
750 #ifdef DVBPSI_USE_NIT
751 p_session->nit = NULL;
752 p_session->p_nit = NULL;
757 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
759 const int i_service_start = p_scan->i_service;
761 dvbpsi_pat_t *p_pat = p_session->p_pat;
762 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
764 #ifdef DVBPSI_USE_NIT
765 dvbpsi_nit_t *p_nit = p_session->p_nit;
771 dvbpsi_pat_program_t *p_program;
772 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
774 if( p_program->i_number == 0 ) /* NIT */
777 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
778 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
784 dvbpsi_sdt_service_t *p_srv;
785 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
787 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
788 dvbpsi_descriptor_t *p_dr;
791 s->b_crypted = p_srv->b_free_ca;
793 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
795 if( p_dr->i_tag == 0x48 )
797 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
802 s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length );
804 if( s->type == SERVICE_UNKNOWN )
806 switch( pD->i_service_type )
808 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
809 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
810 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
811 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
820 #ifdef DVBPSI_USE_NIT
824 dvbpsi_nit_ts_t *p_ts;
825 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
827 uint32_t i_private_data_id = 0;
828 dvbpsi_descriptor_t *p_dsc;
830 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
833 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
835 if( p_dsc->i_tag == 0x5f )
837 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
839 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
841 for( int i = 0; i < p_dsc->i_length/4; i++ )
843 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
844 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
846 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
847 if( s && s->i_channel < 0 )
848 s->i_channel = i_channel_number;
857 for( int i = i_service_start; i < p_scan->i_service; i++ )
859 scan_service_t *p_srv = p_scan->pp_service[i];
861 p_srv->i_snr = p_session->i_snr;
863 p_srv->i_sdt_version = p_sdt->i_version;
864 #ifdef DVBPSI_USE_NIT
867 p_srv->i_network_id = p_nit->i_network_id;
868 p_srv->i_nit_version = p_nit->i_version;
876 dvbpsi_DetachPAT( p_session->pat );
877 if( p_session->p_pat )
878 dvbpsi_DeletePAT( p_session->p_pat );
881 dvbpsi_DetachDemux( p_session->sdt );
882 if( p_session->p_sdt )
883 dvbpsi_DeleteSDT( p_session->p_sdt );
884 #ifdef DVBPSI_USE_NIT
886 dvbpsi_DetachDemux( p_session->nit );
887 if( p_session->p_nit )
888 dvbpsi_DeleteNIT( p_session->p_nit );
892 static int ScanServiceCmp( const void *a, const void *b )
894 scan_service_t *sa = *(scan_service_t**)a;
895 scan_service_t *sb = *(scan_service_t**)b;
897 if( sa->i_channel == sb->i_channel )
899 if( sa->psz_name && sb->psz_name )
900 return strcmp( sa->psz_name, sb->psz_name );
903 if( sa->i_channel == -1 )
905 else if( sb->i_channel == -1 )
908 if( sa->i_channel < sb->i_channel )
910 else if( sa->i_channel > sb->i_channel )
915 static block_t *BlockString( const char *psz )
917 block_t *p = block_Alloc( strlen(psz) );
919 memcpy( p->p_buffer, psz, p->i_buffer );
923 block_t *scan_GetM3U( scan_t *p_scan )
925 vlc_object_t *p_obj = p_scan->p_obj;
926 block_t *p_playlist = NULL;
928 if( p_scan->i_service <= 0 )
932 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
935 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
937 for( int i = 0; i < p_scan->i_service; i++ )
939 scan_service_t *s = p_scan->pp_service[i];
941 if( s->type == SERVICE_UNKNOWN )
943 /* We should only select service that have been described by SDT */
944 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
948 const char *psz_type;
951 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
952 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
953 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
954 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
956 psz_type = "Unknown";
959 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",
960 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
961 s->i_network_id, s->i_nit_version, s->i_sdt_version,
962 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
965 s->cfg.i_fec = 9; /* FEC_AUTO */
968 if( asprintf( &psz, "#EXTINF:,,%s\n"
969 "#EXTVLCOPT:program=%d\n"
970 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d\n"
972 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
976 s->cfg.c_polarization == 'H' ? 18 : 13,
981 block_t *p_block = BlockString( psz );
983 block_ChainAppend( &p_playlist, p_block );
987 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
990 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
992 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
994 block_Release( p_block );
999 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1003 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1006 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1008 else if( i_pid == 0x11 )
1011 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1014 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1016 else if( i_pid == p_scan->i_nit_pid )
1018 #ifdef DVBPSI_USE_NIT
1020 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1023 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1027 block_Release( p_block );
1029 return p_scan->p_pat && p_scan->p_sdt &&
1030 #ifdef DVBPSI_USE_NIT
1037 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1039 p_session->i_snr = i_snr;