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>
39 #include <sys/types.h>
42 /* Include dvbpsi headers */
43 #ifdef HAVE_DVBPSI_DR_H
44 # include <dvbpsi/dvbpsi.h>
45 # include <dvbpsi/descriptor.h>
46 # include <dvbpsi/pat.h>
47 # include <dvbpsi/pmt.h>
48 # include <dvbpsi/dr.h>
49 # include <dvbpsi/psi.h>
50 # include <dvbpsi/demux.h>
51 # include <dvbpsi/sdt.h>
54 # include "descriptor.h"
55 # include "tables/pat.h"
56 # include "tables/pmt.h"
57 # include "descriptors/dr.h"
60 # include "tables/sdt.h"
64 # include <vlc_httpd.h>
70 scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg )
72 scan_service_t *p_srv = malloc( sizeof(*p_srv) );
76 p_srv->i_program = i_program;
80 p_srv->type = SERVICE_UNKNOWN;
81 p_srv->psz_name = NULL;
82 p_srv->i_channel = -1;
83 p_srv->b_crypted = false;
85 p_srv->i_network_id = -1;
86 p_srv->i_nit_version = -1;
87 p_srv->i_sdt_version = -1;
92 void scan_service_Delete( scan_service_t *p_srv )
94 free( p_srv->psz_name );
99 int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
101 if( p_parameter->type == SCAN_DVB_T )
103 msg_Dbg( p_obj, "DVB-T scanning:" );
104 msg_Dbg( p_obj, " - frequency [%d, %d]",
105 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
106 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
107 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
108 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
110 else if( p_parameter->type == SCAN_DVB_C )
112 msg_Dbg( p_obj, "DVB-C scanning:" );
113 msg_Dbg( p_obj, " - frequency [%d, %d]",
114 p_parameter->frequency.i_min, p_parameter->frequency.i_max );
115 msg_Dbg( p_obj, " - bandwidth [%d,%d]",
116 p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
117 msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
124 p_scan->p_obj = VLC_OBJECT(p_obj);
126 p_scan->p_dialog = NULL;
127 TAB_INIT( p_scan->i_service, p_scan->pp_service );
128 p_scan->parameter = *p_parameter;
129 p_scan->i_time_start = mdate();
133 void scan_Clean( scan_t *p_scan )
135 if( p_scan->p_dialog != NULL )
136 dialog_ProgressDestroy( p_scan->p_dialog );
138 for( int i = 0; i < p_scan->i_service; i++ )
139 scan_service_Delete( p_scan->pp_service[i] );
140 TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
143 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
145 msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
146 /* Values taken from dvb-scan utils frequency-files, sorted by how
147 * often they appear. This hopefully speeds up finding services. */
148 static const unsigned short frequencies[] = {
149 410, 426, 418, 394, 402, 362,
150 370, 354, 346, 442, 434, 386,
151 378, 450, 306, 162, 154, 474,
152 466, 458, 338, 754, 714, 586,
153 562, 546, 514, 490, 314, 170,
154 113, 770, 762, 746, 738, 730,
155 722, 706, 690, 682, 674, 666,
156 650, 642, 634, 554, 538, 530,
157 506, 498, 330, 322, 283, 850,
158 842, 834, 818, 810, 802, 794,
159 786, 778, 748, 732, 728, 724,
160 720, 698, 660, 658, 656, 610,
161 594, 578, 570, 522, 482, 377,
162 372, 347, 339, 323, 315, 299,
163 298, 291, 275, 267, 259, 255,
164 251, 243, 235, 232, 227, 219,
165 211, 203, 195, 187, 179, 171,
166 163, 155, 147, 146, 143, 139,
169 enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
171 if( p_scan->i_index < num_frequencies )
173 p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
174 *pf_pos = (double)p_scan->i_index / num_frequencies;
180 static int ScanDvbTNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
182 if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
185 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
186 const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
188 p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
189 p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
191 *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
195 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
197 static const int i_band_count = 2;
200 const char *psz_name;
209 const int i_offset_count = 5;
210 const int i_mhz = 1000000;
212 /* We will probe the whole band divided in all bandwidth possibility trying
213 * i_offset_count offset around the position
215 for( ;; p_scan->i_index++ )
218 const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
219 const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
220 const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
222 const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
225 for( i = 0; i < i_band_count; i++ )
227 if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
230 if( i >=i_band_count )
232 if( i_fi > band[i_band_count-1].i_max )
237 const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
238 const int i_frequency_base = i_fi*i_mhz;
240 if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
242 const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
244 if( i_frequency < p_scan->parameter.frequency.i_min ||
245 i_frequency > p_scan->parameter.frequency.i_max )
248 p_cfg->i_frequency = i_frequency;
249 p_cfg->i_bandwidth = i_bandwidth;
251 int i_current = 0, i_total = 0;
252 for( int i = 0; i < i_band_count; i++ )
254 const int i_frag = band[i].i_max-band[i].i_min;
256 if( i_fi >= band[i].i_min )
257 i_current += __MIN( i_fi - band[i].i_min, i_frag );
261 *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
267 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
269 if( p_scan->parameter.b_exhaustive )
270 return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
272 return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
275 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
277 if( p_scan->parameter.b_exhaustive )
278 return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
280 return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
283 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
288 if( scan_IsCancelled( p_scan ) )
291 memset( p_cfg, 0, sizeof(*p_cfg) );
292 switch( p_scan->parameter.type )
295 i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
298 i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
301 i_ret = VLC_EGENERIC;
311 for( int i = 0; i < p_scan->i_service; i++ )
313 if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
317 if( asprintf( &psz_text, _("%.1f MHz (%d services)"),
318 (double)p_cfg->i_frequency / 1000000, i_service ) >= 0 )
320 const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
321 char psz_eta[MSTRTIME_MAX_SIZE];
324 msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
326 if( p_scan->p_dialog == NULL )
327 p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
328 if( p_scan->p_dialog != NULL )
329 dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
337 bool scan_IsCancelled( scan_t *p_scan )
339 return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
342 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
344 for( int i = i_service_start; i < p_scan->i_service; i++ )
346 if( p_scan->pp_service[i]->i_program == i_program )
347 return p_scan->pp_service[i];
352 /* FIXME handle properly string (convert to utf8) */
353 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
355 vlc_object_t *p_obj = p_session->p_obj;
357 msg_Dbg( p_obj, "PATCallBack" );
360 if( p_session->p_pat && p_session->p_pat->b_current_next )
362 dvbpsi_DeletePAT( p_session->p_pat );
363 p_session->p_pat = NULL;
365 if( p_session->p_pat )
367 dvbpsi_DeletePAT( p_pat );
371 dvbpsi_pat_program_t *p_program;
374 p_session->p_pat = p_pat;
377 msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
378 p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
379 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
381 msg_Dbg( p_obj, " * number=%d pid=%d", p_program->i_number, p_program->i_pid );
382 if( p_program->i_number == 0 )
383 p_session->i_nit_pid = p_program->i_pid;
386 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
388 vlc_object_t *p_obj = p_session->p_obj;
390 msg_Dbg( p_obj, "SDTCallBack" );
392 if( p_session->p_sdt && p_session->p_sdt->b_current_next )
394 dvbpsi_DeleteSDT( p_session->p_sdt );
395 p_session->p_sdt = NULL;
397 if( p_session->p_sdt )
399 dvbpsi_DeleteSDT( p_sdt );
404 p_session->p_sdt = p_sdt;
407 msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
408 p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
409 p_sdt->i_network_id );
412 dvbpsi_sdt_service_t *p_srv;
413 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
415 dvbpsi_descriptor_t *p_dr;
417 msg_Dbg( p_obj, " * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
418 p_srv->i_service_id, p_srv->b_eit_schedule,
419 p_srv->b_eit_present, p_srv->i_running_status,
421 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
423 if( p_dr->i_tag == 0x48 )
425 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
428 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
429 str2[pD->i_service_name_length] = '\0';
431 msg_Dbg( p_obj, " - type=%d name=%s",
432 pD->i_service_type, str2 );
436 msg_Dbg( p_obj, " * dsc 0x%x", p_dr->i_tag );
442 #ifdef DVBPSI_USE_NIT
443 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
445 vlc_object_t *p_obj = p_session->p_obj;
447 msg_Dbg( p_obj, "NITCallBack" );
448 msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
449 p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
452 if( p_session->p_nit && p_session->p_nit->b_current_next )
454 dvbpsi_DeleteNIT( p_session->p_nit );
455 p_session->p_nit = NULL;
457 if( p_session->p_nit )
459 dvbpsi_DeleteNIT( p_nit );
464 p_session->p_nit = p_nit;
466 dvbpsi_descriptor_t *p_dsc;
467 for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
469 if( p_dsc->i_tag == 0x40 )
471 msg_Dbg( p_obj, " * network name descriptor" );
474 memcpy( str1, p_dsc->p_data, p_dsc->i_length );
475 str1[p_dsc->i_length] = '\0';
476 msg_Dbg( p_obj, " * name %s", str1 );
478 else if( p_dsc->i_tag == 0x4a )
480 msg_Dbg( p_obj, " * linkage descriptor" );
481 uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
482 uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
483 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
484 int i_linkage_type = p_dsc->p_data[6];
486 msg_Dbg( p_obj, " * ts_id %d", i_ts_id );
487 msg_Dbg( p_obj, " * on_id %d", i_on_id );
488 msg_Dbg( p_obj, " * service_id %d", i_service_id );
489 msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type );
493 msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag );
497 dvbpsi_nit_ts_t *p_ts;
498 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
500 msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
502 uint32_t i_private_data_id = 0;
503 dvbpsi_descriptor_t *p_dsc;
504 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
506 if( p_dsc->i_tag == 0x41 )
508 msg_Dbg( p_obj, " * service list descriptor" );
509 for( int i = 0; i < p_dsc->i_length/3; i++ )
511 uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
512 uint8_t i_service_type = p_dsc->p_data[3*i+2];
513 msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type );
516 else if( p_dsc->i_tag == 0x5a )
518 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
519 msg_Dbg( p_obj, " * terrestrial delivery system" );
520 msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency );
521 msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth );
522 msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation );
523 msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information );
524 msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
525 msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval );
526 msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode );
527 msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag );
529 else if( p_dsc->i_tag == 0x5f )
531 msg_Dbg( p_obj, " * private data specifier descriptor" );
532 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
533 msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id );
535 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
537 msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" );
538 for( int i = 0; i < p_dsc->i_length/4; i++ )
540 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
541 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
542 msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number );
548 msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag );
555 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t i_table_id, uint16_t i_extension )
557 if( i_table_id == 0x42 )
558 dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
559 #ifdef DVBPSI_USE_NIT
560 else if( i_table_id == 0x40 )
561 dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
566 int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
569 memset( p_session, 0, sizeof(*p_session) );
570 p_session->p_obj = p_obj;
571 p_session->cfg = *p_cfg;
572 p_session->i_snr = -1;
573 p_session->pat = NULL;
574 p_session->p_pat = NULL;
575 p_session->i_nit_pid = -1;
576 p_session->sdt = NULL;
577 p_session->p_sdt = NULL;
578 #ifdef DVBPSI_USE_NIT
579 p_session->nit = NULL;
580 p_session->p_nit = NULL;
585 void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
587 const int i_service_start = p_scan->i_service;
589 dvbpsi_pat_t *p_pat = p_session->p_pat;
590 dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
592 #ifdef DVBPSI_USE_NIT
593 dvbpsi_nit_t *p_nit = p_session->p_nit;
599 dvbpsi_pat_program_t *p_program;
600 for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
602 if( p_program->i_number == 0 ) /* NIT */
605 scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
606 TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
612 dvbpsi_sdt_service_t *p_srv;
613 for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
615 scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
616 dvbpsi_descriptor_t *p_dr;
619 s->b_crypted = p_srv->b_free_ca;
621 for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
623 if( p_dr->i_tag == 0x48 )
625 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
630 s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length );
632 if( s->type == SERVICE_UNKNOWN )
634 switch( pD->i_service_type )
636 case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
637 case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
638 case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
639 case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
648 #ifdef DVBPSI_USE_NIT
652 dvbpsi_nit_ts_t *p_ts;
653 for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
655 uint32_t i_private_data_id = 0;
656 dvbpsi_descriptor_t *p_dsc;
658 if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
661 for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
663 if( p_dsc->i_tag == 0x5f )
665 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
667 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
669 for( int i = 0; i < p_dsc->i_length/4; i++ )
671 uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
672 int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
674 scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
675 if( s && s->i_channel < 0 )
676 s->i_channel = i_channel_number;
685 for( int i = i_service_start; i < p_scan->i_service; i++ )
687 scan_service_t *p_srv = p_scan->pp_service[i];
689 p_srv->i_snr = p_session->i_snr;
691 p_srv->i_sdt_version = p_sdt->i_version;
692 #ifdef DVBPSI_USE_NIT
695 p_srv->i_network_id = p_nit->i_network_id;
696 p_srv->i_nit_version = p_nit->i_version;
704 dvbpsi_DetachPAT( p_session->pat );
705 if( p_session->p_pat )
706 dvbpsi_DeletePAT( p_session->p_pat );
709 dvbpsi_DetachDemux( p_session->sdt );
710 if( p_session->p_sdt )
711 dvbpsi_DeleteSDT( p_session->p_sdt );
712 #ifdef DVBPSI_USE_NIT
714 dvbpsi_DetachDemux( p_session->nit );
715 if( p_session->p_nit )
716 dvbpsi_DeleteNIT( p_session->p_nit );
720 static int ScanServiceCmp( const void *a, const void *b )
722 scan_service_t *sa = *(scan_service_t**)a;
723 scan_service_t *sb = *(scan_service_t**)b;
725 if( sa->i_channel == sb->i_channel )
727 if( sa->psz_name && sb->psz_name )
728 return strcmp( sa->psz_name, sb->psz_name );
731 if( sa->i_channel == -1 )
733 else if( sb->i_channel == -1 )
736 if( sa->i_channel < sb->i_channel )
738 else if( sa->i_channel > sb->i_channel )
743 static block_t *BlockString( const char *psz )
745 block_t *p = block_Alloc( strlen(psz) );
747 memcpy( p->p_buffer, psz, p->i_buffer );
751 block_t *scan_GetM3U( scan_t *p_scan )
753 vlc_object_t *p_obj = p_scan->p_obj;
754 block_t *p_playlist = NULL;
756 if( p_scan->i_service <= 0 )
760 qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
763 p_playlist = BlockString( "#EXTM3U\n\n" );/* */
765 for( int i = 0; i < p_scan->i_service; i++ )
767 scan_service_t *s = p_scan->pp_service[i];
769 if( s->type == SERVICE_UNKNOWN )
771 /* We should only select service that have been described by SDT */
772 msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
776 const char *psz_type;
779 case SERVICE_DIGITAL_TELEVISION: psz_type = "Digital television"; break;
780 case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
781 case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
782 case SERVICE_DIGITAL_RADIO: psz_type = "Digital radio"; break;
784 psz_type = "Unknown";
787 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",
788 s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
789 s->i_network_id, s->i_nit_version, s->i_sdt_version,
790 s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
793 if( asprintf( &psz, "#EXTINF:,,%s\n"
794 "#EXTVLCOPT:program=%d\n"
795 "dvb://frequency=%d:bandwidth=%d\n"
797 s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
799 s->cfg.i_frequency, s->cfg.i_bandwidth ) < 0 )
803 block_t *p_block = BlockString( psz );
805 block_ChainAppend( &p_playlist, p_block );
809 return p_playlist ? block_ChainGather( p_playlist ) : NULL;
812 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
814 if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
816 block_Release( p_block );
821 const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
825 p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
828 dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
830 else if( i_pid == 0x11 )
833 p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
836 dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
838 else if( i_pid == p_scan->i_nit_pid )
840 #ifdef DVBPSI_USE_NIT
842 p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
845 dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
849 block_Release( p_block );
851 return p_scan->p_pat && p_scan->p_sdt &&
852 #ifdef DVBPSI_USE_NIT
859 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
861 p_session->i_snr = i_snr;