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>
45 /* Include dvbpsi headers */
46 #ifdef HAVE_DVBPSI_DR_H
47 # include <dvbpsi/dvbpsi.h>
48 # include <dvbpsi/descriptor.h>
49 # include <dvbpsi/pat.h>
50 # include <dvbpsi/pmt.h>
51 # include <dvbpsi/dr.h>
52 # include <dvbpsi/psi.h>
53 # include <dvbpsi/demux.h>
54 # include <dvbpsi/sdt.h>
57 # include "descriptor.h"
58 # include "tables/pat.h"
59 # include "tables/pmt.h"
60 # include "descriptors/dr.h"
63 # include "tables/sdt.h"
67 # include <vlc_httpd.h>
73 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg )
75 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
79 p_srv->i_program = i_program;
83 p_srv->type = SERVICE_UNKNOWN;
84 p_srv->psz_name = NULL;
85 p_srv->i_channel = -1;
86 p_srv->b_crypted = false;
88 p_srv->i_network_id = -1;
89 p_srv->i_nit_version = -1;
90 p_srv->i_sdt_version = -1;
95 void scan_service_Delete( scan_service_t *p_srv )
97 free( p_srv->psz_name );
102 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
104 if( p_parameter->type == SCAN_DVB_T )
106 msg_Dbg( p_obj, "DVB-T scanning:" );
107 msg_Dbg( p_obj, " - frequency [%d, %d]",
108 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
109 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
110 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
111 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
113 else if( p_parameter->type == SCAN_DVB_C )
115 msg_Dbg( p_obj, "DVB-C scanning:" );
116 msg_Dbg( p_obj, " - frequency [%d, %d]",
117 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
118 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
119 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
120 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
127 p_scan->p_obj = VLC_OBJECT(p_obj);
129 p_scan->p_dialog = NULL;
130 TAB_INIT( p_scan->i_service, p_scan->pp_service );
131 p_scan->parameter = *p_parameter;
132 p_scan->i_time_start = mdate();
136 void scan_Clean( scan_t *p_scan )
138 if( p_scan->p_dialog != NULL )
139 dialog_ProgressDestroy( p_scan->p_dialog );
141 for( int i = 0; i < p_scan->i_service; i++ )
142 scan_service_Delete( p_scan->pp_service[i] );
143 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
146 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
148 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
149 /* Values taken from dvb-scan utils frequency-files, sorted by how
150 * often they appear. This hopefully speeds up finding services. */
151 static const unsigned short frequencies[] = {
152 410, 426, 418, 394, 402, 362,
153 370, 354, 346, 442, 434, 386,
154 378, 450, 306, 162, 154, 474,
155 466, 458, 338, 754, 714, 586,
156 562, 546, 514, 490, 314, 170,
157 113, 770, 762, 746, 738, 730,
158 722, 706, 690, 682, 674, 666,
159 650, 642, 634, 554, 538, 530,
160 506, 498, 330, 322, 283, 850,
161 842, 834, 818, 810, 802, 794,
162 786, 778, 748, 732, 728, 724,
163 720, 698, 660, 658, 656, 610,
164 594, 578, 570, 522, 482, 377,
165 372, 347, 339, 323, 315, 299,
166 298, 291, 275, 267, 259, 255,
167 251, 243, 235, 232, 227, 219,
168 211, 203, 195, 187, 179, 171,
169 163, 155, 147, 146, 143, 139,
172 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
174 if( p_scan->i_index < num_frequencies )
176 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
177 *pf_pos = (double)p_scan->i_index / num_frequencies;
183 static int ScanDvbTNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
185 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
188 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
189 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
191 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
192 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
194 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
198 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
200 static const int i_band_count = 2;
203 const char *psz_name;
212 const int i_offset_count = 5;
213 const int i_mhz = 1000000;
215 /* We will probe the whole band divided in all bandwidth possibility trying
216 * i_offset_count offset around the position
218 for( ;; p_scan->i_index++ )
221 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
222 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
223 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
225 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
228 for( i = 0; i < i_band_count; i++ )
230 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
233 if( i >=i_band_count )
235 if( i_fi > band[i_band_count-1].i_max )
240 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
241 const int i_frequency_base = i_fi*i_mhz;
243 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
245 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
247 if( i_frequency < p_scan->parameter.frequency.i_min ||
248 i_frequency > p_scan->parameter.frequency.i_max )
251 p_cfg->i_frequency = i_frequency;
252 p_cfg->i_bandwidth = i_bandwidth;
254 int i_current = 0, i_total = 0;
255 for( int i = 0; i < i_band_count; i++ )
257 const int i_frag = band[i].i_max-band[i].i_min;
259 if( i_fi >= band[i].i_min )
260 i_current += __MIN( i_fi - band[i].i_min, i_frag );
264 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
270 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
272 if( p_scan->parameter.b_exhaustive )
273 return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
275 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
278 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
280 if( p_scan->parameter.b_exhaustive )
281 return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
283 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
286 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
291 if( scan_IsCancelled( p_scan ) )
294 memset( p_cfg, 0, sizeof(*p_cfg) );
295 switch( p_scan->parameter.type )
298 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
301 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
304 i_ret = VLC_EGENERIC;
314 for( int i = 0; i < p_scan->i_service; i++ )
316 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
320 if( asprintf( &psz_text, _("%.1f MHz (%d services)"),
321 (double)p_cfg->i_frequency / 1000000, i_service ) >= 0 )
323 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
324 char psz_eta[MSTRTIME_MAX_SIZE];
327 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
329 if( p_scan->p_dialog == NULL )
330 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
331 if( p_scan->p_dialog != NULL )
332 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
340 bool scan_IsCancelled( scan_t *p_scan )
342 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
345 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
347 for( int i = i_service_start; i < p_scan->i_service; i++ )
349 if( p_scan->pp_service[i]->i_program == i_program )
350 return p_scan->pp_service[i];
355 /* FIXME handle properly string (convert to utf8) */
356 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
358 vlc_object_t *p_obj = p_session->p_obj;
360 msg_Dbg( p_obj, "PATCallBack" );
363 if( p_session->p_pat && p_session->p_pat->b_current_next )
365 dvbpsi_DeletePAT( p_session->p_pat );
366 p_session->p_pat = NULL;
368 if( p_session->p_pat )
370 dvbpsi_DeletePAT( p_pat );
374 dvbpsi_pat_program_t *p_program;
377 p_session->p_pat = p_pat;
380 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
381 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
382 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
384 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
385 if( p_program->i_number == 0 )
386 p_session->i_nit_pid = p_program->i_pid;
389 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
391 vlc_object_t *p_obj = p_session->p_obj;
393 msg_Dbg( p_obj, "SDTCallBack" );
395 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
397 dvbpsi_DeleteSDT( p_session->p_sdt );
398 p_session->p_sdt = NULL;
400 if( p_session->p_sdt )
402 dvbpsi_DeleteSDT( p_sdt );
407 p_session->p_sdt = p_sdt;
410 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
411 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
412 p_sdt->i_network_id );
415 dvbpsi_sdt_service_t *p_srv;
416 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
418 dvbpsi_descriptor_t *p_dr;
420 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
421 p_srv->i_service_id, p_srv->b_eit_schedule,
422 p_srv->b_eit_present, p_srv->i_running_status,
424 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
426 if( p_dr->i_tag == 0x48 )
428 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
431 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
432 str2[pD->i_service_name_length] = '\0';
434 msg_Dbg( p_obj, " - type=%d name=%s",
435 pD->i_service_type, str2 );
439 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
445 #ifdef DVBPSI_USE_NIT
446 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
448 vlc_object_t *p_obj = p_session->p_obj;
450 msg_Dbg( p_obj, "NITCallBack" );
451 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
452 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
455 if( p_session->p_nit && p_session->p_nit->b_current_next )
457 dvbpsi_DeleteNIT( p_session->p_nit );
458 p_session->p_nit = NULL;
460 if( p_session->p_nit )
462 dvbpsi_DeleteNIT( p_nit );
467 p_session->p_nit = p_nit;
469 dvbpsi_descriptor_t *p_dsc;
470 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
472 if( p_dsc->i_tag == 0x40 )
474 msg_Dbg( p_obj, " * network name descriptor" );
477 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
478 str1[p_dsc->i_length] = '\0';
479 msg_Dbg( p_obj, " * name %s", str1 );
481 else if( p_dsc->i_tag == 0x4a )
483 msg_Dbg( p_obj, " * linkage descriptor" );
484 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
485 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
486 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
487 int i_linkage_type = p_dsc->p_data[6];
489 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
490 msg_Dbg( p_obj, " * on_id %d", i_on_id );
491 msg_Dbg( p_obj, " * service_id %d", i_service_id );
492 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
496 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
500 dvbpsi_nit_ts_t *p_ts;
501 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
503 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
505 uint32_t i_private_data_id = 0;
506 dvbpsi_descriptor_t *p_dsc;
507 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
509 if( p_dsc->i_tag == 0x41 )
511 msg_Dbg( p_obj, " * service list descriptor" );
512 for( int i = 0; i < p_dsc->i_length/3; i++ )
514 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
515 uint8_t i_service_type = p_dsc->p_data[3*i+2];
516 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
519 else if( p_dsc->i_tag == 0x5a )
521 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
522 msg_Dbg( p_obj, " * terrestrial delivery system" );
523 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
524 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
525 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
526 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
527 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
528 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
529 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
530 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
532 else if( p_dsc->i_tag == 0x5f )
534 msg_Dbg( p_obj, " * private data specifier descriptor" );
535 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
536 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
538 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
540 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
541 for( int i = 0; i < p_dsc->i_length/4; i++ )
543 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
544 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
545 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
551 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
558 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
560 if( i_table_id == 0x42 )
561 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
562 #ifdef DVBPSI_USE_NIT
563 else if( i_table_id == 0x40 )
564 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
569 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
572 memset( p_session, 0, sizeof(*p_session) );
573 p_session->p_obj = p_obj;
574 p_session->cfg = *p_cfg;
575 p_session->i_snr = -1;
576 p_session->pat = NULL;
577 p_session->p_pat = NULL;
578 p_session->i_nit_pid = -1;
579 p_session->sdt = NULL;
580 p_session->p_sdt = NULL;
581 #ifdef DVBPSI_USE_NIT
582 p_session->nit = NULL;
583 p_session->p_nit = NULL;
588 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
590 const int i_service_start = p_scan->i_service;
592 dvbpsi_pat_t *p_pat = p_session->p_pat;
593 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
595 #ifdef DVBPSI_USE_NIT
596 dvbpsi_nit_t *p_nit = p_session->p_nit;
602 dvbpsi_pat_program_t *p_program;
603 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
605 if( p_program->i_number == 0 ) /* NIT */
608 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
609 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
615 dvbpsi_sdt_service_t *p_srv;
616 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
618 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
619 dvbpsi_descriptor_t *p_dr;
622 s->b_crypted = p_srv->b_free_ca;
624 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
626 if( p_dr->i_tag == 0x48 )
628 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
633 s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length );
635 if( s->type == SERVICE_UNKNOWN )
637 switch( pD->i_service_type )
639 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
640 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
641 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
642 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
651 #ifdef DVBPSI_USE_NIT
655 dvbpsi_nit_ts_t *p_ts;
656 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
658 uint32_t i_private_data_id = 0;
659 dvbpsi_descriptor_t *p_dsc;
661 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
664 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
666 if( p_dsc->i_tag == 0x5f )
668 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
670 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
672 for( int i = 0; i < p_dsc->i_length/4; i++ )
674 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
675 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
677 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
678 if( s && s->i_channel < 0 )
679 s->i_channel = i_channel_number;
688 for( int i = i_service_start; i < p_scan->i_service; i++ )
690 scan_service_t *p_srv = p_scan->pp_service[i];
692 p_srv->i_snr = p_session->i_snr;
694 p_srv->i_sdt_version = p_sdt->i_version;
695 #ifdef DVBPSI_USE_NIT
698 p_srv->i_network_id = p_nit->i_network_id;
699 p_srv->i_nit_version = p_nit->i_version;
707 dvbpsi_DetachPAT( p_session->pat );
708 if( p_session->p_pat )
709 dvbpsi_DeletePAT( p_session->p_pat );
712 dvbpsi_DetachDemux( p_session->sdt );
713 if( p_session->p_sdt )
714 dvbpsi_DeleteSDT( p_session->p_sdt );
715 #ifdef DVBPSI_USE_NIT
717 dvbpsi_DetachDemux( p_session->nit );
718 if( p_session->p_nit )
719 dvbpsi_DeleteNIT( p_session->p_nit );
723 static int ScanServiceCmp( const void *a, const void *b )
725 scan_service_t *sa = *(scan_service_t**)a;
726 scan_service_t *sb = *(scan_service_t**)b;
728 if( sa->i_channel == sb->i_channel )
730 if( sa->psz_name && sb->psz_name )
731 return strcmp( sa->psz_name, sb->psz_name );
734 if( sa->i_channel == -1 )
736 else if( sb->i_channel == -1 )
739 if( sa->i_channel < sb->i_channel )
741 else if( sa->i_channel > sb->i_channel )
746 static block_t *BlockString( const char *psz )
748 block_t *p = block_Alloc( strlen(psz) );
750 memcpy( p->p_buffer, psz, p->i_buffer );
754 block_t *scan_GetM3U( scan_t *p_scan )
756 vlc_object_t *p_obj = p_scan->p_obj;
757 block_t *p_playlist = NULL;
759 if( p_scan->i_service <= 0 )
763 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
766 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
768 for( int i = 0; i < p_scan->i_service; i++ )
770 scan_service_t *s = p_scan->pp_service[i];
772 if( s->type == SERVICE_UNKNOWN )
774 /* We should only select service that have been described by SDT */
775 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
779 const char *psz_type;
782 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
783 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
784 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
785 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
787 psz_type = "Unknown";
790 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",
791 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
792 s->i_network_id, s->i_nit_version, s->i_sdt_version,
793 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
796 if( asprintf( &psz, "#EXTINF:,,%s\n"
797 "#EXTVLCOPT:program=%d\n"
798 "dvb://frequency=%d:bandwidth=%d\n"
800 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
802 s->cfg.i_frequency, s->cfg.i_bandwidth ) < 0 )
806 block_t *p_block = BlockString( psz );
808 block_ChainAppend( &p_playlist, p_block );
812 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
815 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
817 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
819 block_Release( p_block );
824 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
828 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
831 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
833 else if( i_pid == 0x11 )
836 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
839 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
841 else if( i_pid == p_scan->i_nit_pid )
843 #ifdef DVBPSI_USE_NIT
845 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
848 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
852 block_Release( p_block );
854 return p_scan->p_pat && p_scan->p_sdt &&
855 #ifdef DVBPSI_USE_NIT
862 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
864 p_session->i_snr = i_snr;