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>
8 * Ilkka Ollakka <ileoo@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_block.h>
34 #include <vlc_dialog.h>
36 #include <vlc_charset.h>
37 #include <vlc_access.h>
39 #include <sys/types.h>
41 /* Include dvbpsi headers */
42 #include <dvbpsi/dvbpsi.h>
43 #include <dvbpsi/descriptor.h>
44 #include <dvbpsi/pat.h>
45 #include <dvbpsi/pmt.h>
46 #include <dvbpsi/dr.h>
47 #include <dvbpsi/psi.h>
48 #include <dvbpsi/demux.h>
49 #include <dvbpsi/sdt.h>
50 #ifdef _DVBPSI_DR_43_H_
51 # define DVBPSI_USE_NIT 1
52 # include <dvbpsi/nit.h>
57 #include "../../demux/dvb-text.h"
62 SERVICE_DIGITAL_RADIO,
63 SERVICE_DIGITAL_TELEVISION,
64 SERVICE_DIGITAL_TELEVISION_AC_SD,
65 SERVICE_DIGITAL_TELEVISION_AC_HD,
66 } scan_service_type_t;
70 int i_program; /* program number (service id) */
71 scan_configuration_t cfg;
74 scan_service_type_t type;
75 char *psz_name; /* channel name in utf8 or NULL */
76 int i_channel; /* -1 if unknown */
77 bool b_crypted; /* True if potentially crypted */
89 struct dialog_progress_bar_t *p_dialog;
91 scan_parameter_t parameter;
95 scan_service_t **pp_service;
102 scan_configuration_t cfg;
112 #ifdef DVBPSI_USE_NIT
116 # warning NIT is not supported by your libdvbpsi version
122 static scan_service_t *scan_service_New( int i_program,
123 const scan_configuration_t *p_cfg )
125 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
129 p_srv->i_program = i_program;
133 p_srv->type = SERVICE_UNKNOWN;
134 p_srv->psz_name = NULL;
135 p_srv->i_channel = -1;
136 p_srv->b_crypted = false;
138 p_srv->i_network_id = -1;
139 p_srv->i_nit_version = -1;
140 p_srv->i_sdt_version = -1;
145 static void scan_service_Delete( scan_service_t *p_srv )
147 free( p_srv->psz_name );
151 static int decode_BCD( uint32_t input, uint32_t *output )
153 char *psz_decoded="";
156 if(asprintf( &psz_decoded, "%1d%1d%s", ( input & 0xf0 ) >> 4, input & 0x0f, psz_decoded ? psz_decoded : "" ) < 0 )
160 *output = atol( psz_decoded );
165 static int scan_service_type( int service_type )
167 switch( service_type )
169 case 0x01: return SERVICE_DIGITAL_TELEVISION; break;
170 case 0x02: return SERVICE_DIGITAL_RADIO; break;
171 case 0x16: return SERVICE_DIGITAL_TELEVISION_AC_SD; break;
172 case 0x19: return SERVICE_DIGITAL_TELEVISION_AC_HD; break;
173 default: return SERVICE_UNKNOWN; break;
178 scan_t *scan_New( vlc_object_t *p_obj, const scan_parameter_t *p_parameter )
180 if( p_parameter->type == SCAN_DVB_T )
182 msg_Dbg( p_obj, "DVB-T scanning:" );
183 msg_Dbg( p_obj, " - frequency [%d, %d]",
184 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
185 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
186 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
187 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
189 else if( p_parameter->type == SCAN_DVB_C )
191 msg_Dbg( p_obj, "DVB-C scanning:" );
192 msg_Dbg( p_obj, " - frequency [%d, %d]",
193 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
194 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
195 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
196 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
197 msg_Dbg( p_obj, " - scannin modulations %s", p_parameter->b_modulation_set ? "off" : "on" );
199 else if( p_parameter->type == SCAN_DVB_S )
201 msg_Dbg( p_obj, "DVB-S scanning:" );
202 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
208 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
209 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
211 scan_t *p_scan = malloc( sizeof( *p_scan ) );
212 if( unlikely(p_scan == NULL) )
215 p_scan->p_obj = VLC_OBJECT(p_obj);
217 p_scan->p_dialog = NULL;
218 TAB_INIT( p_scan->i_service, p_scan->pp_service );
219 p_scan->parameter = *p_parameter;
220 p_scan->i_time_start = mdate();
225 void scan_Destroy( scan_t *p_scan )
227 if( p_scan->p_dialog != NULL )
228 dialog_ProgressDestroy( p_scan->p_dialog );
230 for( int i = 0; i < p_scan->i_service; i++ )
231 scan_service_Delete( p_scan->pp_service[i] );
232 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
236 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
238 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
240 int *pi_count = &p_scan->parameter.sat_info.i_count;
242 if( !p_scan->parameter.sat_info.psz_name )
244 msg_Err( p_scan->p_obj, "no satellite selected" );
248 /* if there are no transponders in mem, laod from config file */
253 char *psz_dir = NULL;
254 char *data_dir = config_GetDataDir( p_scan->p_obj );
256 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
262 free( p_scan->parameter.sat_info.psz_name );
266 /* open config directory */
267 if( !( p_dir = vlc_opendir( psz_dir ) ) )
269 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
270 free( p_scan->parameter.sat_info.psz_name );
274 /* find the requested file in the directory */
278 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
281 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
283 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
284 p_scan->parameter.sat_info.psz_path = NULL;
286 free( psz_filename );
293 if( !p_scan->parameter.sat_info.psz_path )
295 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
296 free( p_scan->parameter.sat_info.psz_name );
300 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
302 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
307 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
314 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
316 &p_transponders[*pi_count].i_frequency,
317 &p_transponders[*pi_count].c_polarization,
318 &p_transponders[*pi_count].i_symbol_rate,
321 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
326 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
327 char *p_fec = strstr( psz_fec_list, psz_fec );
329 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
331 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
335 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
336 } while (res != EOF);
338 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
341 p_scan->parameter.sat_info.p_transponders = p_transponders;
345 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
346 free( p_scan->parameter.sat_info.psz_name );
347 free( p_scan->parameter.sat_info.psz_path );
350 free( p_scan->parameter.sat_info.psz_name );
351 free( p_scan->parameter.sat_info.psz_path );
354 if( p_scan->i_index < *pi_count )
356 /* setup params for scan */
357 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
358 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
359 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
360 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
362 msg_Dbg( p_scan->p_obj,
363 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
367 p_cfg->i_symbol_rate,
369 p_cfg->c_polarization );
371 *pf_pos = (double)p_scan->i_index / *pi_count;
376 if( p_scan->parameter.sat_info.p_transponders )
378 free( p_scan->parameter.sat_info.p_transponders );
379 p_scan->parameter.sat_info.p_transponders = NULL;
385 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
387 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
388 /* Values taken from dvb-scan utils frequency-files, sorted by how
389 * often they appear. This hopefully speeds up finding services. */
390 static const unsigned int frequencies[] = { 41000, 39400, 40200,
391 38600, 41800, 36200, 44200, 43400, 37000, 35400, 42600, 37800,
392 34600, 45800, 45000, 46600, 32200, 51400, 49000, 33800, 31400,
393 30600, 47400, 71400, 69000, 68200, 58600, 56200, 54600, 49800,
394 48200, 33000, 79400, 72200, 69800, 67400, 66600, 65000, 64200,
395 61000, 55400, 53000, 52200, 50600, 29800, 16200, 15400, 11300,
396 78600, 77000, 76200, 75400, 74600, 73800, 73000, 70600, 57800,
397 57000, 53800, 12100, 81000, 77800, 65800, 63400, 61800, 29000,
398 17000, 85000, 84200, 83400, 81800, 80200, 59400, 36900, 28300,
399 26600, 25800, 25000, 24200, 23400, 85800, 74800, 73200, 72800,
400 72400, 72000, 66000, 65600, 60200, 42500, 41700, 40900, 40100,
401 39300, 38500, 37775, 37700, 37200, 36100, 35600, 35300, 34700,
402 34500, 33900, 33700, 32900, 32300, 32100, 31500, 31300, 30500,
403 29900, 29700, 29100, 28950, 28200, 28000, 27500, 27400, 27200,
404 26700, 25900, 25500, 25100, 24300, 24100, 23500, 23200, 22700,
405 22600, 21900, 21800, 21100, 20300, 19500, 18700, 17900, 17100,
406 16300, 15500, 14700, 14600, 14500, 14300, 13900, 13700, 13100,
409 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
411 if( p_scan->i_index < num_frequencies )
413 p_cfg->i_frequency = 10000 * ( frequencies[ p_scan->i_index ] );
414 *pf_pos = (double)(p_scan->i_index * 1000 +
415 p_scan->parameter.i_symbolrate * 100 +
416 (256 - (p_scan->parameter.i_modulation >> 4)) )
417 / (num_frequencies * 1000 + 900 + 16);
423 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
425 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
428 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
429 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
431 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
432 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
434 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
438 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
440 static const int i_band_count = 2;
443 const char *psz_name;
452 const int i_offset_count = 5;
453 const int i_mhz = 1000000;
455 /* We will probe the whole band divided in all bandwidth possibility trying
456 * i_offset_count offset around the position
458 for( ;; p_scan->i_index++ )
461 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
462 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
463 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
465 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
468 for( i = 0; i < i_band_count; i++ )
470 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
473 if( i >=i_band_count )
475 if( i_fi > band[i_band_count-1].i_max )
480 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
481 const int i_frequency_base = i_fi*i_mhz;
483 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
485 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
487 if( i_frequency < p_scan->parameter.frequency.i_min ||
488 i_frequency > p_scan->parameter.frequency.i_max )
491 p_cfg->i_frequency = i_frequency;
492 p_cfg->i_bandwidth = i_bandwidth;
494 int i_current = 0, i_total = 0;
495 for( int i = 0; i < i_band_count; i++ )
497 const int i_frag = band[i].i_max-band[i].i_min;
499 if( i_fi >= band[i].i_min )
500 i_current += __MIN( i_fi - band[i].i_min, i_frag );
504 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
510 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
512 bool b_servicefound = false;
513 #ifdef _DVBPSI_DR_44_H_
514 /* We iterate frequencies/modulations/symbolrates until we get first hit and find NIT,
515 from that we fill pp_service with configurations and after that we iterate over
516 pp_services for all that doesn't have name yet (tune to that cfg and get SDT and name
519 for( int i = 0; i < p_scan->i_service; i++ )
521 /* We found radio/tv config that doesn't have a name,
522 lets tune to that mux
524 if( !p_scan->pp_service[i]->psz_name && ( p_scan->pp_service[i]->type != SERVICE_UNKNOWN ) )
526 p_cfg->i_frequency = p_scan->pp_service[i]->cfg.i_frequency;
527 p_cfg->i_symbolrate = p_scan->pp_service[i]->cfg.i_symbolrate;
528 p_cfg->i_modulation = p_scan->pp_service[i]->cfg.i_modulation;
529 p_scan->i_index = i+1;
530 msg_Dbg( p_scan->p_obj, "iterating to freq: %u, symbolrate %u, modulation %u index %d/%d",
531 p_cfg->i_frequency, p_cfg->i_symbolrate, p_cfg->i_modulation, p_scan->i_index, p_scan->i_service );
532 *pf_pos = (double)i/p_scan->i_service;
536 /* We should have iterated all channels by now */
537 if( p_scan->i_service )
540 /* fallback to old, so when we get one channe, use that
541 symbolrate/modulation until bitter end
543 for( int i=0; i < p_scan->i_service; i++ )
545 b_servicefound = p_scan->pp_service[i]->type != SERVICE_UNKNOWN;
551 if( !b_servicefound )
554 if( !p_scan->parameter.b_modulation_set )
556 p_scan->parameter.i_modulation = (p_scan->parameter.i_modulation >> 1 );
557 /* if we iterated all modulations, move on */
558 if( p_scan->parameter.i_modulation < 16)
560 p_scan->parameter.i_modulation = 256;
564 msg_Dbg( p_scan->p_obj, "modulation %d ", p_scan->parameter.i_modulation);
566 if( !p_scan->parameter.b_symbolrate_set )
568 /* symbol rates from dvb-tools dvb-c files */
569 static const unsigned short symbolrates[] = {
570 6900, 6875, 6950, 7000, 3450, 6111,
571 6428, 6952, 5900, 5000 };
573 enum { num_symbols = (sizeof(symbolrates)/sizeof(*symbolrates)) };
575 /* if we rotated modulations, rotate symbolrate */
577 p_scan->parameter.i_symbolrate = (++p_scan->parameter.i_symbolrate % num_symbols );
578 p_cfg->i_symbolrate = 1000 * (symbolrates[ p_scan->parameter.i_symbolrate ] );
579 msg_Dbg( p_scan->p_obj, "symbolrate %d", p_cfg->i_symbolrate );
580 if( p_scan->parameter.i_symbolrate )
583 if( !b_rotate && p_scan->i_index )
586 p_cfg->i_modulation = p_scan->parameter.i_modulation;
587 if( !p_cfg->i_symbolrate )
588 p_cfg->i_symbolrate = var_GetInteger( p_scan->p_obj, "dvb-srate" );
589 if( !p_cfg->i_modulation )
590 p_cfg->i_modulation = var_GetInteger( p_scan->p_obj, "dvb-modulation" );
592 if( p_scan->parameter.b_exhaustive )
593 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
595 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
598 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
600 if( p_scan->parameter.b_exhaustive )
601 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
603 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
606 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
608 if( p_scan->parameter.b_exhaustive )
609 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
611 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
614 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
619 if( scan_IsCancelled( p_scan ) )
622 memset( p_cfg, 0, sizeof(*p_cfg) );
623 switch( p_scan->parameter.type )
626 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
629 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
632 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
635 i_ret = VLC_EGENERIC;
645 for( int i = 0; i < p_scan->i_service; i++ )
647 if( p_scan->pp_service[i]->psz_name )
651 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
652 char psz_eta[MSTRTIME_MAX_SIZE];
654 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
655 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
658 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
660 if( p_scan->p_dialog == NULL )
661 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
662 if( p_scan->p_dialog != NULL )
663 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
671 bool scan_IsCancelled( scan_t *p_scan )
673 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
676 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
678 for( int i = i_service_start; i < p_scan->i_service; i++ )
680 if( p_scan->pp_service[i]->i_program == i_program )
681 return p_scan->pp_service[i];
686 /* FIXME handle properly string (convert to utf8) */
687 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
689 vlc_object_t *p_obj = p_session->p_obj;
691 msg_Dbg( p_obj, "PATCallBack" );
694 if( p_session->p_pat && p_session->p_pat->b_current_next )
696 dvbpsi_DeletePAT( p_session->p_pat );
697 p_session->p_pat = NULL;
699 if( p_session->p_pat )
701 dvbpsi_DeletePAT( p_pat );
705 dvbpsi_pat_program_t *p_program;
708 p_session->p_pat = p_pat;
711 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
712 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
713 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
715 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
716 if( p_program->i_number == 0 )
717 p_session->i_nit_pid = p_program->i_pid;
720 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
722 vlc_object_t *p_obj = p_session->p_obj;
724 msg_Dbg( p_obj, "SDTCallBack" );
726 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
728 dvbpsi_DeleteSDT( p_session->p_sdt );
729 p_session->p_sdt = NULL;
731 if( p_session->p_sdt )
733 dvbpsi_DeleteSDT( p_sdt );
738 p_session->p_sdt = p_sdt;
741 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
742 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
743 p_sdt->i_network_id );
746 dvbpsi_sdt_service_t *p_srv;
747 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
749 dvbpsi_descriptor_t *p_dr;
751 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
752 p_srv->i_service_id, p_srv->b_eit_schedule,
753 p_srv->b_eit_present, p_srv->i_running_status,
755 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
757 if( p_dr->i_tag == 0x48 )
759 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
762 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
763 str2[pD->i_service_name_length] = '\0';
765 msg_Dbg( p_obj, " - type=%d name=%s",
766 pD->i_service_type, str2 );
770 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
776 #ifdef DVBPSI_USE_NIT
777 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
779 vlc_object_t *p_obj = p_session->p_obj;
780 access_t *p_access = (access_t*)p_obj;
781 access_sys_t *p_sys = p_access->p_sys;
782 scan_t *p_scan = p_sys->scan;
784 msg_Dbg( p_obj, "NITCallBack" );
785 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
786 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
789 if( p_session->p_nit && p_session->p_nit->b_current_next )
791 dvbpsi_DeleteNIT( p_session->p_nit );
792 p_session->p_nit = NULL;
794 if( p_session->p_nit )
796 dvbpsi_DeleteNIT( p_nit );
801 p_session->p_nit = p_nit;
803 dvbpsi_descriptor_t *p_dsc;
804 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
806 if( p_dsc->i_tag == 0x40 )
808 msg_Dbg( p_obj, " * network name descriptor" );
811 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
812 str1[p_dsc->i_length] = '\0';
813 msg_Dbg( p_obj, " * name %s", str1 );
815 else if( p_dsc->i_tag == 0x4a )
817 msg_Dbg( p_obj, " * linkage descriptor" );
818 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
819 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
820 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
821 int i_linkage_type = p_dsc->p_data[6];
823 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
824 msg_Dbg( p_obj, " * on_id %d", i_on_id );
825 msg_Dbg( p_obj, " * service_id %d", i_service_id );
826 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
830 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
834 dvbpsi_nit_ts_t *p_ts;
835 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
837 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
839 uint32_t i_private_data_id = 0;
840 dvbpsi_descriptor_t *p_dsc;
841 scan_configuration_t *p_cfg = malloc(sizeof(*p_cfg));
842 if(!p_cfg) return VLC_ENOMEM;
843 memset(p_cfg,0,sizeof(*p_cfg));
844 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
846 if( p_dsc->i_tag == 0x41 )
848 msg_Dbg( p_obj, " * service list descriptor" );
849 for( int i = 0; i < p_dsc->i_length/3; i++ )
851 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
852 uint8_t i_service_type = p_dsc->p_data[3*i+2];
853 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
854 #ifdef _DVBPSI_DR_44_H_
855 if( (ScanFindService( p_scan, 0, i_service_id ) == NULL) &&
856 scan_service_type( i_service_type ) != SERVICE_UNKNOWN )
858 scan_service_t *s = scan_service_New( i_service_id, p_cfg );
859 s->type = scan_service_type( i_service_type );
860 s->i_network_id = p_nit->i_network_id;
861 s->i_nit_version = p_nit->i_version;
862 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
867 else if( p_dsc->i_tag == 0x5a )
869 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
870 msg_Dbg( p_obj, " * terrestrial delivery system" );
871 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
872 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
873 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
874 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
875 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
876 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
877 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
878 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
880 #ifdef _DVBPSI_DR_44_H_
881 else if( p_dsc->i_tag == 0x44 )
883 dvbpsi_cable_deliv_sys_dr_t *p_t = dvbpsi_DecodeCableDelivSysDr( p_dsc );
884 msg_Dbg( p_obj, " * Cable delivery system");
886 if( decode_BCD( p_t->i_frequency, &p_cfg->i_frequency ) < 0 )
888 p_cfg->i_frequency *= 100;
889 msg_Dbg( p_obj, " * frequency %d", p_cfg->i_frequency );
890 if( decode_BCD( p_t->i_symbol_rate, &p_cfg->i_symbolrate ) < 0 )
892 p_cfg->i_symbolrate *= 100;
893 msg_Dbg( p_obj, " * symbolrate %u", p_cfg->i_symbolrate );
894 p_cfg->i_modulation = (8 << p_t->i_modulation);
895 msg_Dbg( p_obj, " * modulation %u", p_cfg->i_modulation );
898 else if( p_dsc->i_tag == 0x5f )
900 msg_Dbg( p_obj, " * private data specifier descriptor" );
901 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
902 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
904 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
906 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
907 for( int i = 0; i < p_dsc->i_length/4; i++ )
909 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
910 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
911 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
912 scan_service_t *s = ScanFindService( p_scan, 0, i_service_id );
913 if( s && s->i_channel < 0 ) s->i_channel = i_channel_number;
919 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
926 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
928 if( i_table_id == 0x42 )
929 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
930 #ifdef DVBPSI_USE_NIT
931 else if( i_table_id == 0x40 || i_table_id == 0x41 )
932 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
936 scan_session_t *scan_session_New( vlc_object_t *p_obj,
937 const scan_configuration_t *p_cfg )
939 scan_session_t *p_session = malloc( sizeof( *p_session ) );
940 if( unlikely(p_session == NULL) )
942 p_session->p_obj = p_obj;
943 p_session->cfg = *p_cfg;
944 p_session->i_snr = -1;
945 p_session->pat = NULL;
946 p_session->p_pat = NULL;
947 p_session->i_nit_pid = -1;
948 p_session->sdt = NULL;
949 p_session->p_sdt = NULL;
950 #ifdef DVBPSI_USE_NIT
951 p_session->nit = NULL;
952 p_session->p_nit = NULL;
957 void scan_session_Destroy( scan_t *p_scan, scan_session_t *p_session )
959 const int i_service_start = p_scan->i_service;
961 dvbpsi_pat_t *p_pat = p_session->p_pat;
962 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
964 #ifdef DVBPSI_USE_NIT
965 dvbpsi_nit_t *p_nit = p_session->p_nit;
971 dvbpsi_pat_program_t *p_program;
972 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
974 if( p_program->i_number == 0 ) /* NIT */
977 scan_service_t *s = ScanFindService( p_scan, 0, p_program->i_number );
980 s = scan_service_New( p_program->i_number, &p_session->cfg );
981 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
988 dvbpsi_sdt_service_t *p_srv;
989 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
991 scan_service_t *s = ScanFindService( p_scan, 0, p_srv->i_service_id );
992 dvbpsi_descriptor_t *p_dr;
995 s->b_crypted = p_srv->b_free_ca;
997 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
999 if( p_dr->i_tag == 0x48 )
1001 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
1006 s->psz_name = vlc_from_EIT( pD->i_service_name,
1007 pD->i_service_name_length );
1009 if( s->type == SERVICE_UNKNOWN )
1010 s->type = scan_service_type( pD->i_service_type );
1017 #ifdef DVBPSI_USE_NIT
1019 if( p_pat && p_nit )
1021 dvbpsi_nit_ts_t *p_ts;
1022 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
1024 uint32_t i_private_data_id = 0;
1025 dvbpsi_descriptor_t *p_dsc;
1027 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
1030 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
1032 if( p_dsc->i_tag == 0x5f )
1034 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
1036 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
1038 for( int i = 0; i < p_dsc->i_length/4; i++ )
1040 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
1041 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
1043 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
1044 if( s && s->i_channel < 0 )
1045 s->i_channel = i_channel_number;
1054 for( int i = i_service_start; i < p_scan->i_service; i++ )
1056 scan_service_t *p_srv = p_scan->pp_service[i];
1058 p_srv->i_snr = p_session->i_snr;
1060 p_srv->i_sdt_version = p_sdt->i_version;
1061 #ifdef DVBPSI_USE_NIT
1064 p_srv->i_network_id = p_nit->i_network_id;
1065 p_srv->i_nit_version = p_nit->i_version;
1072 if( p_session->pat )
1073 dvbpsi_DetachPAT( p_session->pat );
1074 if( p_session->p_pat )
1075 dvbpsi_DeletePAT( p_session->p_pat );
1077 if( p_session->sdt )
1078 dvbpsi_DetachDemux( p_session->sdt );
1079 if( p_session->p_sdt )
1080 dvbpsi_DeleteSDT( p_session->p_sdt );
1081 #ifdef DVBPSI_USE_NIT
1082 if( p_session->nit )
1083 dvbpsi_DetachDemux( p_session->nit );
1084 if( p_session->p_nit )
1085 dvbpsi_DeleteNIT( p_session->p_nit );
1090 static int ScanServiceCmp( const void *a, const void *b )
1092 scan_service_t *sa = *(scan_service_t**)a;
1093 scan_service_t *sb = *(scan_service_t**)b;
1095 if( sa->i_channel == sb->i_channel )
1097 if( sa->psz_name && sb->psz_name )
1098 return strcmp( sa->psz_name, sb->psz_name );
1101 if( sa->i_channel == -1 )
1103 else if( sb->i_channel == -1 )
1106 if( sa->i_channel < sb->i_channel )
1108 else if( sa->i_channel > sb->i_channel )
1113 static block_t *BlockString( const char *psz )
1115 block_t *p = block_Alloc( strlen(psz) );
1117 memcpy( p->p_buffer, psz, p->i_buffer );
1121 block_t *scan_GetM3U( scan_t *p_scan )
1123 vlc_object_t *p_obj = p_scan->p_obj;
1124 block_t *p_playlist = NULL;
1126 if( p_scan->i_service <= 0 )
1130 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
1133 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
1135 for( int i = 0; i < p_scan->i_service; i++ )
1137 scan_service_t *s = p_scan->pp_service[i];
1139 if( s->type == SERVICE_UNKNOWN )
1141 /* We should only select service that have been described by SDT */
1142 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
1146 const char *psz_type;
1149 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
1150 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
1151 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
1152 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
1154 psz_type = "Unknown";
1157 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",
1158 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
1159 s->i_network_id, s->i_nit_version, s->i_sdt_version,
1160 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr, s->cfg.i_modulation );
1163 s->cfg.i_fec = 9; /* FEC_AUTO */
1166 if( asprintf( &psz, "#EXTINF:,,%s\n"
1167 "#EXTVLCOPT:program=%d\n"
1168 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d:modulation=%d:srate=%d\n"
1170 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
1174 s->cfg.c_polarization == 'H' ? 18 : 13,
1176 s->cfg.i_modulation,
1177 s->cfg.i_symbolrate ) < 0 )
1181 block_t *p_block = BlockString( psz );
1183 block_ChainAppend( &p_playlist, p_block );
1187 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
1190 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
1192 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
1194 block_Release( p_block );
1199 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1203 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1206 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1208 else if( i_pid == 0x11 )
1211 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1214 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1216 else /*if( i_pid == p_scan->i_nit_pid )*/
1218 #ifdef DVBPSI_USE_NIT
1220 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1223 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1227 block_Release( p_block );
1229 return p_scan->p_pat && p_scan->p_sdt &&
1230 #ifdef DVBPSI_USE_NIT
1237 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1239 p_session->i_snr = i_snr;