Add DreX fourCCs
[vlc.git] / modules / access / dvb / scan.c
blob5f75e58a81a9b5834cba6407b8e61550f8f8a5bd
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 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
33 #include <vlc_block.h>
34 #include <vlc_dialog.h>
35 #include <vlc_fs.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>
53 #endif
55 #include "dvb.h"
56 #include "scan.h"
57 #include "../../demux/dvb-text.h"
59 typedef enum
61 SERVICE_UNKNOWN = 0,
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;
68 typedef struct
70 int i_program; /* program number (service id) */
71 scan_configuration_t cfg;
72 int i_snr;
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 */
79 int i_network_id;
81 int i_nit_version;
82 int i_sdt_version;
84 } scan_service_t;
86 struct scan_t
88 vlc_object_t *p_obj;
89 struct dialog_progress_bar_t *p_dialog;
90 int64_t i_index;
91 scan_parameter_t parameter;
92 int64_t i_time_start;
94 int i_service;
95 scan_service_t **pp_service;
98 struct scan_session_t
100 vlc_object_t *p_obj;
102 scan_configuration_t cfg;
103 int i_snr;
105 dvbpsi_handle pat;
106 dvbpsi_pat_t *p_pat;
107 int i_nit_pid;
109 dvbpsi_handle sdt;
110 dvbpsi_sdt_t *p_sdt;
112 #ifdef DVBPSI_USE_NIT
113 dvbpsi_handle nit;
114 dvbpsi_nit_t *p_nit;
115 #else
116 # warning NIT is not supported by your libdvbpsi version
117 #endif
121 /* */
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) );
126 if( !p_srv )
127 return NULL;
129 p_srv->i_program = i_program;
130 p_srv->cfg = *p_cfg;
131 p_srv->i_snr = -1;
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;
142 return p_srv;
145 static void scan_service_Delete( scan_service_t *p_srv )
147 free( p_srv->psz_name );
148 free( p_srv );
151 static uint32_t decode_BCD( uint32_t input )
153 uint32_t output = 0;
154 for( short index=28; index >= 0 ; index -= 4 )
156 output *= 10;
157 output += ((input >> index) & 0x0f);
159 return output;
162 static int scan_service_type( int service_type )
164 switch( service_type )
166 case 0x01: return SERVICE_DIGITAL_TELEVISION; break;
167 case 0x02: return SERVICE_DIGITAL_RADIO; break;
168 case 0x16: return SERVICE_DIGITAL_TELEVISION_AC_SD; break;
169 case 0x19: return SERVICE_DIGITAL_TELEVISION_AC_HD; break;
170 default: return SERVICE_UNKNOWN; break;
174 /* */
175 scan_t *scan_New( vlc_object_t *p_obj, const scan_parameter_t *p_parameter )
177 if( p_parameter->type == SCAN_DVB_T )
179 msg_Dbg( p_obj, "DVB-T scanning:" );
180 msg_Dbg( p_obj, " - frequency [%d, %d]",
181 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
182 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
183 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
184 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
186 else if( p_parameter->type == SCAN_DVB_C )
188 msg_Dbg( p_obj, "DVB-C scanning:" );
189 msg_Dbg( p_obj, " - frequency [%d, %d]",
190 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
191 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
192 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
193 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
194 msg_Dbg( p_obj, " - scannin modulations %s", p_parameter->b_modulation_set ? "off" : "on" );
196 else if( p_parameter->type == SCAN_DVB_S )
198 msg_Dbg( p_obj, "DVB-S scanning:" );
199 msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
201 else
203 return NULL;
205 msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
206 msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
208 scan_t *p_scan = malloc( sizeof( *p_scan ) );
209 if( unlikely(p_scan == NULL) )
210 return NULL;
212 p_scan->p_obj = VLC_OBJECT(p_obj);
213 p_scan->i_index = 0;
214 p_scan->p_dialog = NULL;
215 TAB_INIT( p_scan->i_service, p_scan->pp_service );
216 p_scan->parameter = *p_parameter;
217 p_scan->i_time_start = mdate();
219 return p_scan;
222 void scan_Destroy( scan_t *p_scan )
224 if( p_scan->p_dialog != NULL )
225 dialog_ProgressDestroy( p_scan->p_dialog );
227 for( int i = 0; i < p_scan->i_service; i++ )
228 scan_service_Delete( p_scan->pp_service[i] );
229 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
230 free( p_scan );
233 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
235 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
237 int *pi_count = &p_scan->parameter.sat_info.i_count;
239 if( !p_scan->parameter.sat_info.psz_name )
241 msg_Err( p_scan->p_obj, "no satellite selected" );
242 return VLC_EGENERIC;
245 /* if there are no transponders in mem, laod from config file */
246 if( !*pi_count )
248 DIR *p_dir;
250 char *psz_dir = NULL;
251 char *data_dir = config_GetDataDir( p_scan->p_obj );
253 if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
254 psz_dir = NULL;
255 free( data_dir );
257 if( !psz_dir )
259 free( p_scan->parameter.sat_info.psz_name );
260 return VLC_EGENERIC;
263 /* open config directory */
264 if( !( p_dir = vlc_opendir( psz_dir ) ) )
266 msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
267 free( p_scan->parameter.sat_info.psz_name );
268 return VLC_EGENERIC;
271 /* find the requested file in the directory */
272 for( ; ; ) {
273 char *psz_filename;
275 if( ! (psz_filename = vlc_readdir( p_dir ) ) )
276 break;
278 if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
280 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
281 p_scan->parameter.sat_info.psz_path = NULL;
283 free( psz_filename );
284 break;
288 closedir( p_dir );
290 if( !p_scan->parameter.sat_info.psz_path )
292 msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
293 free( p_scan->parameter.sat_info.psz_name );
294 return VLC_EGENERIC;
297 msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
299 FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
301 /* parse file */
302 if( f )
304 scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
305 char type;
306 char psz_fec[3];
308 int res;
311 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
312 &type,
313 &p_transponders[*pi_count].i_frequency,
314 &p_transponders[*pi_count].c_polarization,
315 &p_transponders[*pi_count].i_symbol_rate,
316 psz_fec ) ) != 5 )
318 msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
319 continue;
322 /* decode fec */
323 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
324 char *p_fec = strstr( psz_fec_list, psz_fec );
325 if ( !p_fec )
326 p_transponders[*pi_count].i_fec = 9; /* FEC_AUTO */
327 else
328 p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
330 (*pi_count)++;
332 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
333 } while (res != EOF);
335 msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
337 fclose( f );
338 p_scan->parameter.sat_info.p_transponders = p_transponders;
340 else
342 msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
343 free( p_scan->parameter.sat_info.psz_name );
344 free( p_scan->parameter.sat_info.psz_path );
345 return VLC_EGENERIC;
347 free( p_scan->parameter.sat_info.psz_name );
348 free( p_scan->parameter.sat_info.psz_path );
351 if( p_scan->i_index < *pi_count )
353 /* setup params for scan */
354 p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
355 p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
356 p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
357 p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
359 msg_Dbg( p_scan->p_obj,
360 "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
361 p_scan->i_index + 1,
362 *pi_count,
363 p_cfg->i_frequency,
364 p_cfg->i_symbol_rate,
365 p_cfg->i_fec,
366 p_cfg->c_polarization );
368 *pf_pos = (double)p_scan->i_index / *pi_count;
370 return VLC_SUCCESS;
373 if( p_scan->parameter.sat_info.p_transponders )
375 free( p_scan->parameter.sat_info.p_transponders );
376 p_scan->parameter.sat_info.p_transponders = NULL;
379 return VLC_EGENERIC;
382 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
384 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
385 /* Values taken from dvb-scan utils frequency-files, sorted by how
386 * often they appear. This hopefully speeds up finding services. */
387 static const unsigned int frequencies[] = { 41000, 39400, 40200,
388 38600, 41800, 36200, 44200, 43400, 37000, 35400, 42600, 37800,
389 34600, 45800, 45000, 46600, 32200, 51400, 49000, 33800, 31400,
390 30600, 47400, 71400, 69000, 68200, 58600, 56200, 54600, 49800,
391 48200, 33000, 79400, 72200, 69800, 67400, 66600, 65000, 64200,
392 61000, 55400, 53000, 52200, 50600, 29800, 16200, 15400, 11300,
393 78600, 77000, 76200, 75400, 74600, 73800, 73000, 70600, 57800,
394 57000, 53800, 12100, 81000, 77800, 65800, 63400, 61800, 29000,
395 17000, 85000, 84200, 83400, 81800, 80200, 59400, 36900, 28300,
396 26600, 25800, 25000, 24200, 23400, 85800, 74800, 73200, 72800,
397 72400, 72000, 66000, 65600, 60200, 42500, 41700, 40900, 40100,
398 39300, 38500, 37775, 37700, 37200, 36100, 35600, 35300, 34700,
399 34500, 33900, 33700, 32900, 32300, 32100, 31500, 31300, 30500,
400 29900, 29700, 29100, 28950, 28200, 28000, 27500, 27400, 27200,
401 26700, 25900, 25500, 25100, 24300, 24100, 23500, 23200, 22700,
402 22600, 21900, 21800, 21100, 20300, 19500, 18700, 17900, 17100,
403 16300, 15500, 14700, 14600, 14500, 14300, 13900, 13700, 13100,
404 12900, 12500, 12300
406 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
408 if( p_scan->i_index < num_frequencies )
410 p_cfg->i_frequency = 10000 * ( frequencies[ p_scan->i_index ] );
411 *pf_pos = (double)(p_scan->i_index * 1000 +
412 p_scan->parameter.i_symbolrate * 100 +
413 (256 - (p_scan->parameter.i_modulation >> 4)) )
414 / (num_frequencies * 1000 + 900 + 16);
415 return VLC_SUCCESS;
417 return VLC_EGENERIC;
420 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
422 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
423 return VLC_EGENERIC;
425 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
426 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
428 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
429 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
431 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
432 return VLC_SUCCESS;
435 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
437 static const int i_band_count = 2;
438 static const struct
440 const char *psz_name;
441 int i_min;
442 int i_max;
444 band[2] =
446 { "VHF", 174, 230 },
447 { "UHF", 470, 862 },
449 const int i_offset_count = 5;
450 const int i_mhz = 1000000;
452 /* We will probe the whole band divided in all bandwidth possibility trying
453 * i_offset_count offset around the position
455 for( ;; p_scan->i_index++ )
458 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
459 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
460 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
462 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
463 int i;
465 for( i = 0; i < i_band_count; i++ )
467 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
468 break;
470 if( i >=i_band_count )
472 if( i_fi > band[i_band_count-1].i_max )
473 return VLC_EGENERIC;
474 continue;
477 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
478 const int i_frequency_base = i_fi*i_mhz;
480 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
482 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
484 if( i_frequency < p_scan->parameter.frequency.i_min ||
485 i_frequency > p_scan->parameter.frequency.i_max )
486 continue;
488 p_cfg->i_frequency = i_frequency;
489 p_cfg->i_bandwidth = i_bandwidth;
491 int i_current = 0, i_total = 0;
492 for( int i = 0; i < i_band_count; i++ )
494 const int i_frag = band[i].i_max-band[i].i_min;
496 if( i_fi >= band[i].i_min )
497 i_current += __MIN( i_fi - band[i].i_min, i_frag );
498 i_total += i_frag;
501 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
502 return VLC_SUCCESS;
507 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
509 bool b_servicefound = false;
510 #ifdef _DVBPSI_DR_44_H_
511 /* We iterate frequencies/modulations/symbolrates until we get first hit and find NIT,
512 from that we fill pp_service with configurations and after that we iterate over
513 pp_services for all that doesn't have name yet (tune to that cfg and get SDT and name
514 for channel).
516 for( int i = 0; i < p_scan->i_service; i++ )
518 /* We found radio/tv config that doesn't have a name,
519 lets tune to that mux
521 if( !p_scan->pp_service[i]->psz_name && ( p_scan->pp_service[i]->type != SERVICE_UNKNOWN ) )
523 p_cfg->i_frequency = p_scan->pp_service[i]->cfg.i_frequency;
524 p_cfg->i_symbolrate = p_scan->pp_service[i]->cfg.i_symbolrate;
525 p_cfg->i_modulation = p_scan->pp_service[i]->cfg.i_modulation;
526 p_scan->i_index = i+1;
527 msg_Dbg( p_scan->p_obj, "iterating to freq: %u, symbolrate %u, modulation %u index %d/%d",
528 p_cfg->i_frequency, p_cfg->i_symbolrate, p_cfg->i_modulation, p_scan->i_index, p_scan->i_service );
529 *pf_pos = (double)i/p_scan->i_service;
530 return VLC_SUCCESS;
533 /* We should have iterated all channels by now */
534 if( p_scan->i_service )
535 return VLC_EGENERIC;
536 #else
537 /* fallback to old, so when we get one channe, use that
538 symbolrate/modulation until bitter end
540 for( int i=0; i < p_scan->i_service; i++ )
542 b_servicefound = p_scan->pp_service[i]->type != SERVICE_UNKNOWN;
543 if( b_servicefound )
544 break;
546 #endif
548 if( !b_servicefound )
550 bool b_rotate=true;
551 if( !p_scan->parameter.b_modulation_set )
553 p_scan->parameter.i_modulation = (p_scan->parameter.i_modulation >> 1 );
554 /* if we iterated all modulations, move on */
555 /* dvb utils dvb-c channels files seems to have only
556 QAM64...QAM256, so lets just iterate over those */
557 if( p_scan->parameter.i_modulation < 64)
559 p_scan->parameter.i_modulation = 256;
560 } else {
561 b_rotate=false;
563 msg_Dbg( p_scan->p_obj, "modulation %d ", p_scan->parameter.i_modulation);
565 if( !p_scan->parameter.b_symbolrate_set )
567 /* symbol rates from dvb-tools dvb-c files */
568 static const unsigned short symbolrates[] = {
569 6900, 6875, 6950
570 /* With DR_44 we can cover other symbolrates from NIT-info
571 as all channel-seed files have atleast one channel that
572 has one of these symbolrate
574 #ifndef _DVBPSI_DR_44_H_
575 ,7000, 3450, 6111,
576 6428, 6952, 5900, 5000
577 #endif
580 enum { num_symbols = (sizeof(symbolrates)/sizeof(*symbolrates)) };
582 /* if we rotated modulations, rotate symbolrate */
583 if( b_rotate )
584 p_scan->parameter.i_symbolrate = (++p_scan->parameter.i_symbolrate % num_symbols );
585 p_cfg->i_symbolrate = 1000 * (symbolrates[ p_scan->parameter.i_symbolrate ] );
586 msg_Dbg( p_scan->p_obj, "symbolrate %d", p_cfg->i_symbolrate );
587 if( p_scan->parameter.i_symbolrate )
588 b_rotate=false;
590 if( !b_rotate && p_scan->i_index )
591 p_scan->i_index--;
593 p_cfg->i_modulation = p_scan->parameter.i_modulation;
594 if( !p_cfg->i_symbolrate )
595 p_cfg->i_symbolrate = var_GetInteger( p_scan->p_obj, "dvb-srate" );
596 if( !p_cfg->i_modulation )
597 p_cfg->i_modulation = var_GetInteger( p_scan->p_obj, "dvb-modulation" );
599 if( p_scan->parameter.b_exhaustive )
600 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
601 else
602 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
605 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
607 if( p_scan->parameter.b_exhaustive )
608 return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
609 else
610 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
613 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
615 if( p_scan->parameter.b_exhaustive )
616 msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
618 return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
621 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
623 double f_position;
624 int i_ret;
626 if( scan_IsCancelled( p_scan ) )
627 return VLC_EGENERIC;
629 memset( p_cfg, 0, sizeof(*p_cfg) );
630 switch( p_scan->parameter.type )
632 case SCAN_DVB_T:
633 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
634 break;
635 case SCAN_DVB_C:
636 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
637 break;
638 case SCAN_DVB_S:
639 i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
640 break;
641 default:
642 i_ret = VLC_EGENERIC;
643 break;
646 if( i_ret )
647 return i_ret;
649 char *psz_text;
650 int i_service = 0;
652 for( int i = 0; i < p_scan->i_service; i++ )
654 if( p_scan->pp_service[i]->psz_name )
655 i_service++;
658 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
659 char psz_eta[MSTRTIME_MAX_SIZE];
661 if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
662 (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
664 if( i_eta >= 0 )
665 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
667 if( p_scan->p_dialog == NULL )
668 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
669 if( p_scan->p_dialog != NULL )
670 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
671 free( psz_text );
674 p_scan->i_index++;
675 return VLC_SUCCESS;
678 bool scan_IsCancelled( scan_t *p_scan )
680 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
683 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
685 for( int i = i_service_start; i < p_scan->i_service; i++ )
687 if( p_scan->pp_service[i]->i_program == i_program )
688 return p_scan->pp_service[i];
690 return NULL;
693 /* FIXME handle properly string (convert to utf8) */
694 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
696 vlc_object_t *p_obj = p_session->p_obj;
698 msg_Dbg( p_obj, "PATCallBack" );
700 /* */
701 if( p_session->p_pat && p_session->p_pat->b_current_next )
703 dvbpsi_DeletePAT( p_session->p_pat );
704 p_session->p_pat = NULL;
706 if( p_session->p_pat )
708 dvbpsi_DeletePAT( p_pat );
709 return;
712 dvbpsi_pat_program_t *p_program;
714 /* */
715 p_session->p_pat = p_pat;
717 /* */
718 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
719 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
720 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
722 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
723 if( p_program->i_number == 0 )
724 p_session->i_nit_pid = p_program->i_pid;
727 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
729 vlc_object_t *p_obj = p_session->p_obj;
731 msg_Dbg( p_obj, "SDTCallBack" );
733 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
735 dvbpsi_DeleteSDT( p_session->p_sdt );
736 p_session->p_sdt = NULL;
738 if( p_session->p_sdt )
740 dvbpsi_DeleteSDT( p_sdt );
741 return;
744 /* */
745 p_session->p_sdt = p_sdt;
747 /* */
748 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
749 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
750 p_sdt->i_network_id );
753 dvbpsi_sdt_service_t *p_srv;
754 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
756 dvbpsi_descriptor_t *p_dr;
758 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
759 p_srv->i_service_id, p_srv->b_eit_schedule,
760 p_srv->b_eit_present, p_srv->i_running_status,
761 p_srv->b_free_ca );
762 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
764 if( p_dr->i_tag == 0x48 )
766 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
767 char str2[257];
769 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
770 str2[pD->i_service_name_length] = '\0';
772 msg_Dbg( p_obj, " - type=%d name=%s",
773 pD->i_service_type, str2 );
775 else
777 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
783 #ifdef DVBPSI_USE_NIT
784 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
786 vlc_object_t *p_obj = p_session->p_obj;
787 access_t *p_access = (access_t*)p_obj;
788 access_sys_t *p_sys = p_access->p_sys;
789 scan_t *p_scan = p_sys->scan;
791 msg_Dbg( p_obj, "NITCallBack" );
792 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
793 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
795 /* */
796 if( p_session->p_nit && p_session->p_nit->b_current_next )
798 dvbpsi_DeleteNIT( p_session->p_nit );
799 p_session->p_nit = NULL;
801 if( p_session->p_nit )
803 dvbpsi_DeleteNIT( p_nit );
804 return;
807 /* */
808 p_session->p_nit = p_nit;
810 dvbpsi_descriptor_t *p_dsc;
811 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
813 if( p_dsc->i_tag == 0x40 )
815 msg_Dbg( p_obj, " * network name descriptor" );
816 char str1[257];
818 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
819 str1[p_dsc->i_length] = '\0';
820 msg_Dbg( p_obj, " * name %s", str1 );
822 else if( p_dsc->i_tag == 0x4a )
824 msg_Dbg( p_obj, " * linkage descriptor" );
825 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
826 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
827 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
828 int i_linkage_type = p_dsc->p_data[6];
830 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
831 msg_Dbg( p_obj, " * on_id %d", i_on_id );
832 msg_Dbg( p_obj, " * service_id %d", i_service_id );
833 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
835 else
837 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
841 dvbpsi_nit_ts_t *p_ts;
842 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
844 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
846 uint32_t i_private_data_id = 0;
847 dvbpsi_descriptor_t *p_dsc;
848 scan_configuration_t *p_cfg = malloc(sizeof(*p_cfg));
849 if(!p_cfg) return VLC_ENOMEM;
850 memset(p_cfg,0,sizeof(*p_cfg));
851 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
853 if( p_dsc->i_tag == 0x41 )
855 msg_Dbg( p_obj, " * service list descriptor" );
856 for( int i = 0; i < p_dsc->i_length/3; i++ )
858 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
859 uint8_t i_service_type = p_dsc->p_data[3*i+2];
860 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
861 #ifdef _DVBPSI_DR_44_H_
862 if( (ScanFindService( p_scan, 0, i_service_id ) == NULL) &&
863 scan_service_type( i_service_type ) != SERVICE_UNKNOWN )
865 scan_service_t *s = scan_service_New( i_service_id, p_cfg );
866 s->type = scan_service_type( i_service_type );
867 s->i_network_id = p_nit->i_network_id;
868 s->i_nit_version = p_nit->i_version;
869 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
871 #endif
874 else if( p_dsc->i_tag == 0x5a )
876 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
877 msg_Dbg( p_obj, " * terrestrial delivery system" );
878 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
879 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
880 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
881 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
882 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
883 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
884 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
885 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
887 #ifdef _DVBPSI_DR_44_H_
888 else if( p_dsc->i_tag == 0x44 )
890 dvbpsi_cable_deliv_sys_dr_t *p_t = dvbpsi_DecodeCableDelivSysDr( p_dsc );
891 msg_Dbg( p_obj, " * Cable delivery system");
893 pcfg->i_freqency = decode_BCD( p_t->i_frequency ) * 100;
894 msg_Dbg( p_obj, " * frequency %d", p_cfg->i_frequency );
895 p_cfg->i_symbolrate = decode_BCD( p_t->i_symbol_rate ) * 100;
896 msg_Dbg( p_obj, " * symbolrate %u", p_cfg->i_symbolrate );
897 p_cfg->i_modulation = (8 << p_t->i_modulation);
898 msg_Dbg( p_obj, " * modulation %u", p_cfg->i_modulation );
900 #endif
901 else if( p_dsc->i_tag == 0x5f )
903 msg_Dbg( p_obj, " * private data specifier descriptor" );
904 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
905 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
907 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
909 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
910 for( int i = 0; i < p_dsc->i_length/4; i++ )
912 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
913 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
914 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
915 scan_service_t *s = ScanFindService( p_scan, 0, i_service_id );
916 if( s && s->i_channel < 0 ) s->i_channel = i_channel_number;
920 else
922 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
927 #endif
929 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
931 if( i_table_id == 0x42 )
932 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
933 #ifdef DVBPSI_USE_NIT
934 else if( i_table_id == 0x40 || i_table_id == 0x41 )
935 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
936 #endif
939 scan_session_t *scan_session_New( vlc_object_t *p_obj,
940 const scan_configuration_t *p_cfg )
942 scan_session_t *p_session = malloc( sizeof( *p_session ) );
943 if( unlikely(p_session == NULL) )
944 return NULL;
945 p_session->p_obj = p_obj;
946 p_session->cfg = *p_cfg;
947 p_session->i_snr = -1;
948 p_session->pat = NULL;
949 p_session->p_pat = NULL;
950 p_session->i_nit_pid = -1;
951 p_session->sdt = NULL;
952 p_session->p_sdt = NULL;
953 #ifdef DVBPSI_USE_NIT
954 p_session->nit = NULL;
955 p_session->p_nit = NULL;
956 #endif
957 return p_session;;
960 void scan_session_Destroy( scan_t *p_scan, scan_session_t *p_session )
962 const int i_service_start = p_scan->i_service;
964 dvbpsi_pat_t *p_pat = p_session->p_pat;
965 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
967 #ifdef DVBPSI_USE_NIT
968 dvbpsi_nit_t *p_nit = p_session->p_nit;
969 #endif
971 if( p_pat )
973 /* Parse PAT */
974 dvbpsi_pat_program_t *p_program;
975 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
977 if( p_program->i_number == 0 ) /* NIT */
978 continue;
980 scan_service_t *s = ScanFindService( p_scan, 0, p_program->i_number );
981 if( s == NULL )
983 s = scan_service_New( p_program->i_number, &p_session->cfg );
984 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
988 /* Parse SDT */
989 if( p_pat && p_sdt )
991 dvbpsi_sdt_service_t *p_srv;
992 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
994 scan_service_t *s = ScanFindService( p_scan, 0, p_srv->i_service_id );
995 dvbpsi_descriptor_t *p_dr;
997 if( s )
998 s->b_crypted = p_srv->b_free_ca;
1000 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
1002 if( p_dr->i_tag == 0x48 )
1004 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
1006 if( s )
1008 if( !s->psz_name )
1009 s->psz_name = vlc_from_EIT( pD->i_service_name,
1010 pD->i_service_name_length );
1012 if( s->type == SERVICE_UNKNOWN )
1013 s->type = scan_service_type( pD->i_service_type );
1020 #ifdef DVBPSI_USE_NIT
1021 /* Parse NIT */
1022 if( p_pat && p_nit )
1024 dvbpsi_nit_ts_t *p_ts;
1025 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
1027 uint32_t i_private_data_id = 0;
1028 dvbpsi_descriptor_t *p_dsc;
1030 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
1031 continue;
1033 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
1035 if( p_dsc->i_tag == 0x5f )
1037 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
1039 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
1041 for( int i = 0; i < p_dsc->i_length/4; i++ )
1043 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
1044 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
1046 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
1047 if( s && s->i_channel < 0 )
1048 s->i_channel = i_channel_number;
1054 #endif
1056 /* */
1057 for( int i = i_service_start; i < p_scan->i_service; i++ )
1059 scan_service_t *p_srv = p_scan->pp_service[i];
1061 p_srv->i_snr = p_session->i_snr;
1062 if( p_sdt )
1063 p_srv->i_sdt_version = p_sdt->i_version;
1064 #ifdef DVBPSI_USE_NIT
1065 if( p_nit )
1067 p_srv->i_network_id = p_nit->i_network_id;
1068 p_srv->i_nit_version = p_nit->i_version;
1070 #endif
1074 /* */
1075 if( p_session->pat )
1076 dvbpsi_DetachPAT( p_session->pat );
1077 if( p_session->p_pat )
1078 dvbpsi_DeletePAT( p_session->p_pat );
1080 if( p_session->sdt )
1081 dvbpsi_DetachDemux( p_session->sdt );
1082 if( p_session->p_sdt )
1083 dvbpsi_DeleteSDT( p_session->p_sdt );
1084 #ifdef DVBPSI_USE_NIT
1085 if( p_session->nit )
1086 dvbpsi_DetachDemux( p_session->nit );
1087 if( p_session->p_nit )
1088 dvbpsi_DeleteNIT( p_session->p_nit );
1089 #endif
1090 free( p_session );
1093 static int ScanServiceCmp( const void *a, const void *b )
1095 scan_service_t *sa = *(scan_service_t**)a;
1096 scan_service_t *sb = *(scan_service_t**)b;
1098 if( sa->i_channel == sb->i_channel )
1100 if( sa->psz_name && sb->psz_name )
1101 return strcmp( sa->psz_name, sb->psz_name );
1102 return 0;
1104 if( sa->i_channel == -1 )
1105 return 1;
1106 else if( sb->i_channel == -1 )
1107 return -1;
1109 if( sa->i_channel < sb->i_channel )
1110 return -1;
1111 else if( sa->i_channel > sb->i_channel )
1112 return 1;
1113 return 0;
1116 static block_t *BlockString( const char *psz )
1118 block_t *p = block_Alloc( strlen(psz) );
1119 if( p )
1120 memcpy( p->p_buffer, psz, p->i_buffer );
1121 return p;
1124 block_t *scan_GetM3U( scan_t *p_scan )
1126 vlc_object_t *p_obj = p_scan->p_obj;
1127 block_t *p_playlist = NULL;
1129 if( p_scan->i_service <= 0 )
1130 return NULL;
1132 /* */
1133 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
1135 /* */
1136 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
1138 for( int i = 0; i < p_scan->i_service; i++ )
1140 scan_service_t *s = p_scan->pp_service[i];
1142 if( s->type == SERVICE_UNKNOWN )
1144 /* We should only select service that have been described by SDT */
1145 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
1146 continue;
1149 const char *psz_type;
1150 switch( s->type )
1152 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
1153 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
1154 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
1155 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
1156 default:
1157 psz_type = "Unknown";
1158 break;
1160 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",
1161 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
1162 s->i_network_id, s->i_nit_version, s->i_sdt_version,
1163 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr, s->cfg.i_modulation );
1165 if( !s->cfg.i_fec )
1166 s->cfg.i_fec = 9; /* FEC_AUTO */
1168 char *psz;
1169 if( asprintf( &psz, "#EXTINF:,,%s\n"
1170 "#EXTVLCOPT:program=%d\n"
1171 "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d:modulation=%d:srate=%d\n"
1172 "\n",
1173 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
1174 s->i_program,
1175 s->cfg.i_frequency,
1176 s->cfg.i_bandwidth,
1177 s->cfg.c_polarization == 'H' ? 18 : 13,
1178 s->cfg.i_fec,
1179 s->cfg.i_modulation,
1180 s->cfg.i_symbolrate ) < 0 )
1181 psz = NULL;
1182 if( psz )
1184 block_t *p_block = BlockString( psz );
1185 if( p_block )
1186 block_ChainAppend( &p_playlist, p_block );
1190 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
1193 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
1195 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
1197 block_Release( p_block );
1198 return false;
1201 /* */
1202 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1203 if( i_pid == 0x00 )
1205 if( !p_scan->pat )
1206 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1208 if( p_scan->pat )
1209 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1211 else if( i_pid == 0x11 )
1213 if( !p_scan->sdt )
1214 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1216 if( p_scan->sdt )
1217 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1219 else /*if( i_pid == p_scan->i_nit_pid )*/
1221 #ifdef DVBPSI_USE_NIT
1222 if( !p_scan->nit )
1223 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1225 if( p_scan->nit )
1226 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1227 #endif
1230 block_Release( p_block );
1232 return p_scan->p_pat && p_scan->p_sdt &&
1233 #ifdef DVBPSI_USE_NIT
1234 p_scan->p_nit;
1235 #else
1236 true;
1237 #endif
1240 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1242 p_session->i_snr = i_snr;