1 /*****************************************************************************
2 * scan.c: DVB scanner helpers
3 *****************************************************************************
4 * Copyright (C) 2008 the VideoLAN team
6 * Authors: Laurent Aimar <fenrir@videolan.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_access.h>
33 #include <vlc_dialog.h>
40 #include <sys/types.h>
43 /* Include dvbpsi headers */
44 #ifdef HAVE_DVBPSI_DR_H
45 # include <dvbpsi/dvbpsi.h>
46 # include <dvbpsi/descriptor.h>
47 # include <dvbpsi/pat.h>
48 # include <dvbpsi/pmt.h>
49 # include <dvbpsi/dr.h>
50 # include <dvbpsi/psi.h>
51 # include <dvbpsi/demux.h>
52 # include <dvbpsi/sdt.h>
55 # include "descriptor.h"
56 # include "tables/pat.h"
57 # include "tables/pmt.h"
58 # include "descriptors/dr.h"
61 # include "tables/sdt.h"
65 # include <vlc_httpd.h>
71 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg )
73 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
77 p_srv->i_program = i_program;
81 p_srv->type = SERVICE_UNKNOWN;
82 p_srv->psz_name = NULL;
83 p_srv->i_channel = -1;
84 p_srv->b_crypted = false;
86 p_srv->i_network_id = -1;
87 p_srv->i_nit_version = -1;
88 p_srv->i_sdt_version = -1;
93 void scan_service_Delete( scan_service_t *p_srv )
95 free( p_srv->psz_name );
100 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
102 if( p_parameter->type == SCAN_DVB_T )
104 msg_Dbg( p_obj, "DVB-T scanning:" );
105 msg_Dbg( p_obj, " - frequency [%d, %d]",
106 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
107 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
108 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
109 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
111 else if( p_parameter->type == SCAN_DVB_C )
113 msg_Dbg( p_obj, "DVB-C scanning:" );
114 msg_Dbg( p_obj, " - frequency [%d, %d]",
115 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
116 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
117 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
118 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
125 p_scan->p_obj = VLC_OBJECT(p_obj);
127 p_scan->p_dialog = NULL;
128 TAB_INIT( p_scan->i_service, p_scan->pp_service );
129 p_scan->parameter = *p_parameter;
130 p_scan->i_time_start = mdate();
134 void scan_Clean( scan_t *p_scan )
136 if( p_scan->p_dialog != NULL )
137 dialog_ProgressDestroy( p_scan->p_dialog );
139 for( int i = 0; i < p_scan->i_service; i++ )
140 scan_service_Delete( p_scan->pp_service[i] );
141 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
144 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
146 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
147 /* Values taken from dvb-scan utils frequency-files, sorted by how
148 * often they appear. This hopefully speeds up finding services. */
149 static const unsigned short frequencies[] = {
150 410, 426, 418, 394, 402, 362,
151 370, 354, 346, 442, 434, 386,
152 378, 450, 306, 162, 154, 474,
153 466, 458, 338, 754, 714, 586,
154 562, 546, 514, 490, 314, 170,
155 113, 770, 762, 746, 738, 730,
156 722, 706, 690, 682, 674, 666,
157 650, 642, 634, 554, 538, 530,
158 506, 498, 330, 322, 283, 850,
159 842, 834, 818, 810, 802, 794,
160 786, 778, 748, 732, 728, 724,
161 720, 698, 660, 658, 656, 610,
162 594, 578, 570, 522, 482, 377,
163 372, 347, 339, 323, 315, 299,
164 298, 291, 275, 267, 259, 255,
165 251, 243, 235, 232, 227, 219,
166 211, 203, 195, 187, 179, 171,
167 163, 155, 147, 146, 143, 139,
170 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
172 if( p_scan->i_index < num_frequencies )
174 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
175 *pf_pos = (double)p_scan->i_index / num_frequencies;
181 static int ScanDvbTNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
183 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
186 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
187 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
189 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
190 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
192 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
196 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
198 static const int i_band_count = 2;
201 const char *psz_name;
210 const int i_offset_count = 5;
211 const int i_mhz = 1000000;
213 /* We will probe the whole band divided in all bandwidth possibility trying
214 * i_offset_count offset around the position
216 for( ;; p_scan->i_index++ )
219 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
220 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
221 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
223 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
226 for( i = 0; i < i_band_count; i++ )
228 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
231 if( i >=i_band_count )
233 if( i_fi > band[i_band_count-1].i_max )
238 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
239 const int i_frequency_base = i_fi*i_mhz;
241 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
243 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
245 if( i_frequency < p_scan->parameter.frequency.i_min ||
246 i_frequency > p_scan->parameter.frequency.i_max )
249 p_cfg->i_frequency = i_frequency;
250 p_cfg->i_bandwidth = i_bandwidth;
252 int i_current = 0, i_total = 0;
253 for( int i = 0; i < i_band_count; i++ )
255 const int i_frag = band[i].i_max-band[i].i_min;
257 if( i_fi >= band[i].i_min )
258 i_current += __MIN( i_fi - band[i].i_min, i_frag );
262 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
268 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
270 if( p_scan->parameter.b_exhaustive )
271 return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
273 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
276 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
278 if( p_scan->parameter.b_exhaustive )
279 return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
281 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
284 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
289 if( scan_IsCancelled( p_scan ) )
292 memset( p_cfg, 0, sizeof(*p_cfg) );
293 switch( p_scan->parameter.type )
296 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
299 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
302 i_ret = VLC_EGENERIC;
312 for( int i = 0; i < p_scan->i_service; i++ )
314 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
318 if( asprintf( &psz_text, _("%.1f MHz (%d services)"),
319 (double)p_cfg->i_frequency / 1000000, i_service ) >= 0 )
321 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
322 char psz_eta[MSTRTIME_MAX_SIZE];
325 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
327 if( p_scan->p_dialog == NULL )
328 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
329 if( p_scan->p_dialog != NULL )
330 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
338 bool scan_IsCancelled( scan_t *p_scan )
340 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
343 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
345 for( int i = i_service_start; i < p_scan->i_service; i++ )
347 if( p_scan->pp_service[i]->i_program == i_program )
348 return p_scan->pp_service[i];
353 /* FIXME handle properly string (convert to utf8) */
354 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
356 vlc_object_t *p_obj = p_session->p_obj;
358 msg_Dbg( p_obj, "PATCallBack" );
361 if( p_session->p_pat && p_session->p_pat->b_current_next )
363 dvbpsi_DeletePAT( p_session->p_pat );
364 p_session->p_pat = NULL;
366 if( p_session->p_pat )
368 dvbpsi_DeletePAT( p_pat );
372 dvbpsi_pat_program_t *p_program;
375 p_session->p_pat = p_pat;
378 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
379 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
380 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
382 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
383 if( p_program->i_number == 0 )
384 p_session->i_nit_pid = p_program->i_pid;
387 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
389 vlc_object_t *p_obj = p_session->p_obj;
391 msg_Dbg( p_obj, "SDTCallBack" );
393 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
395 dvbpsi_DeleteSDT( p_session->p_sdt );
396 p_session->p_sdt = NULL;
398 if( p_session->p_sdt )
400 dvbpsi_DeleteSDT( p_sdt );
405 p_session->p_sdt = p_sdt;
408 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
409 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
410 p_sdt->i_network_id );
413 dvbpsi_sdt_service_t *p_srv;
414 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
416 dvbpsi_descriptor_t *p_dr;
418 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
419 p_srv->i_service_id, p_srv->b_eit_schedule,
420 p_srv->b_eit_present, p_srv->i_running_status,
422 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
424 if( p_dr->i_tag == 0x48 )
426 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
429 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
430 str2[pD->i_service_name_length] = '\0';
432 msg_Dbg( p_obj, " - type=%d name=%s",
433 pD->i_service_type, str2 );
437 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
443 #ifdef DVBPSI_USE_NIT
444 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
446 vlc_object_t *p_obj = p_session->p_obj;
448 msg_Dbg( p_obj, "NITCallBack" );
449 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
450 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
453 if( p_session->p_nit && p_session->p_nit->b_current_next )
455 dvbpsi_DeleteNIT( p_session->p_nit );
456 p_session->p_nit = NULL;
458 if( p_session->p_nit )
460 dvbpsi_DeleteNIT( p_nit );
465 p_session->p_nit = p_nit;
467 dvbpsi_descriptor_t *p_dsc;
468 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
470 if( p_dsc->i_tag == 0x40 )
472 msg_Dbg( p_obj, " * network name descriptor" );
475 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
476 str1[p_dsc->i_length] = '\0';
477 msg_Dbg( p_obj, " * name %s", str1 );
479 else if( p_dsc->i_tag == 0x4a )
481 msg_Dbg( p_obj, " * linkage descriptor" );
482 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
483 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
484 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
485 int i_linkage_type = p_dsc->p_data[6];
487 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
488 msg_Dbg( p_obj, " * on_id %d", i_on_id );
489 msg_Dbg( p_obj, " * service_id %d", i_service_id );
490 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
494 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
498 dvbpsi_nit_ts_t *p_ts;
499 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
501 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
503 uint32_t i_private_data_id = 0;
504 dvbpsi_descriptor_t *p_dsc;
505 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
507 if( p_dsc->i_tag == 0x41 )
509 msg_Dbg( p_obj, " * service list descriptor" );
510 for( int i = 0; i < p_dsc->i_length/3; i++ )
512 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
513 uint8_t i_service_type = p_dsc->p_data[3*i+2];
514 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
517 else if( p_dsc->i_tag == 0x5a )
519 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
520 msg_Dbg( p_obj, " * terrestrial delivery system" );
521 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
522 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
523 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
524 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
525 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
526 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
527 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
528 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
530 else if( p_dsc->i_tag == 0x5f )
532 msg_Dbg( p_obj, " * private data specifier descriptor" );
533 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
534 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
536 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
538 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
539 for( int i = 0; i < p_dsc->i_length/4; i++ )
541 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
542 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
543 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
549 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
556 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
558 if( i_table_id == 0x42 )
559 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
560 #ifdef DVBPSI_USE_NIT
561 else if( i_table_id == 0x40 )
562 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
567 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
570 memset( p_session, 0, sizeof(*p_session) );
571 p_session->p_obj = p_obj;
572 p_session->cfg = *p_cfg;
573 p_session->i_snr = -1;
574 p_session->pat = NULL;
575 p_session->p_pat = NULL;
576 p_session->i_nit_pid = -1;
577 p_session->sdt = NULL;
578 p_session->p_sdt = NULL;
579 #ifdef DVBPSI_USE_NIT
580 p_session->nit = NULL;
581 p_session->p_nit = NULL;
586 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
588 const int i_service_start = p_scan->i_service;
590 dvbpsi_pat_t *p_pat = p_session->p_pat;
591 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
593 #ifdef DVBPSI_USE_NIT
594 dvbpsi_nit_t *p_nit = p_session->p_nit;
600 dvbpsi_pat_program_t *p_program;
601 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
603 if( p_program->i_number == 0 ) /* NIT */
606 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
607 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
613 dvbpsi_sdt_service_t *p_srv;
614 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
616 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
617 dvbpsi_descriptor_t *p_dr;
620 s->b_crypted = p_srv->b_free_ca;
622 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
624 if( p_dr->i_tag == 0x48 )
626 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
631 s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length );
633 if( s->type == SERVICE_UNKNOWN )
635 switch( pD->i_service_type )
637 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
638 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
639 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
640 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
649 #ifdef DVBPSI_USE_NIT
653 dvbpsi_nit_ts_t *p_ts;
654 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
656 uint32_t i_private_data_id = 0;
657 dvbpsi_descriptor_t *p_dsc;
659 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
662 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
664 if( p_dsc->i_tag == 0x5f )
666 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
668 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
670 for( int i = 0; i < p_dsc->i_length/4; i++ )
672 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
673 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
675 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
676 if( s && s->i_channel < 0 )
677 s->i_channel = i_channel_number;
686 for( int i = i_service_start; i < p_scan->i_service; i++ )
688 scan_service_t *p_srv = p_scan->pp_service[i];
690 p_srv->i_snr = p_session->i_snr;
692 p_srv->i_sdt_version = p_sdt->i_version;
693 #ifdef DVBPSI_USE_NIT
696 p_srv->i_network_id = p_nit->i_network_id;
697 p_srv->i_nit_version = p_nit->i_version;
705 dvbpsi_DetachPAT( p_session->pat );
706 if( p_session->p_pat )
707 dvbpsi_DeletePAT( p_session->p_pat );
710 dvbpsi_DetachDemux( p_session->sdt );
711 if( p_session->p_sdt )
712 dvbpsi_DeleteSDT( p_session->p_sdt );
713 #ifdef DVBPSI_USE_NIT
715 dvbpsi_DetachDemux( p_session->nit );
716 if( p_session->p_nit )
717 dvbpsi_DeleteNIT( p_session->p_nit );
721 static int ScanServiceCmp( const void *a, const void *b )
723 scan_service_t *sa = *(scan_service_t**)a;
724 scan_service_t *sb = *(scan_service_t**)b;
726 if( sa->i_channel == sb->i_channel )
728 if( sa->psz_name && sb->psz_name )
729 return strcmp( sa->psz_name, sb->psz_name );
732 if( sa->i_channel == -1 )
734 else if( sb->i_channel == -1 )
737 if( sa->i_channel < sb->i_channel )
739 else if( sa->i_channel > sb->i_channel )
744 static block_t *BlockString( const char *psz )
746 block_t *p = block_Alloc( strlen(psz) );
748 memcpy( p->p_buffer, psz, p->i_buffer );
752 block_t *scan_GetM3U( scan_t *p_scan )
754 vlc_object_t *p_obj = p_scan->p_obj;
755 block_t *p_playlist = NULL;
757 if( p_scan->i_service <= 0 )
761 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
764 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
766 for( int i = 0; i < p_scan->i_service; i++ )
768 scan_service_t *s = p_scan->pp_service[i];
770 if( s->type == SERVICE_UNKNOWN )
772 /* We should only select service that have been described by SDT */
773 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
777 const char *psz_type;
780 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
781 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
782 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
783 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
785 psz_type = "Unknown";
788 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",
789 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
790 s->i_network_id, s->i_nit_version, s->i_sdt_version,
791 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
794 if( asprintf( &psz, "#EXTINF:,,%s\n"
795 "#EXTVLCOPT:program=%d\n"
796 "dvb://frequency=%d:bandwidth=%d\n"
798 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
800 s->cfg.i_frequency, s->cfg.i_bandwidth ) < 0 )
804 block_t *p_block = BlockString( psz );
806 block_ChainAppend( &p_playlist, p_block );
810 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
813 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
815 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
817 block_Release( p_block );
822 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
826 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
829 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
831 else if( i_pid == 0x11 )
834 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
837 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
839 else if( i_pid == p_scan->i_nit_pid )
841 #ifdef DVBPSI_USE_NIT
843 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
846 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
850 block_Release( p_block );
852 return p_scan->p_pat && p_scan->p_sdt &&
853 #ifdef DVBPSI_USE_NIT
860 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
862 p_session->i_snr = i_snr;