Remove excessive debug, extend search for start
[dvblastpn.git] / dvblast.c
blob4dcf1f0c152bda76228368f14322e98d6db73fa3
1 /*****************************************************************************
2 * dvblast.c
3 *****************************************************************************
4 * Copyright (C) 2004, 2008-2011, 2015 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Andy Gatward <a.j.gatward@reading.ac.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <inttypes.h>
29 #include <stdbool.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <pthread.h>
33 #include <netdb.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <signal.h>
38 #include <getopt.h>
39 #include <errno.h>
41 #include <ev.h>
43 #include "dvblast.h"
45 #ifdef HAVE_ICONV
46 #include <iconv.h>
47 #endif
49 #include <bitstream/dvb/si.h>
50 #include <bitstream/ietf/rtp.h>
52 /*****************************************************************************
53 * Local declarations
54 *****************************************************************************/
55 struct ev_loop *event_loop;
56 output_t **pp_outputs = NULL;
57 int i_nb_outputs = 0;
58 output_t output_dup;
59 bool b_passthrough = false;
60 static const char *psz_conf_file = NULL;
61 char *psz_srv_socket = NULL;
62 static int i_priority = -1;
63 int i_adapter = 0;
64 int i_fenum = 0;
65 int i_canum = 0;
66 char *psz_delsys = NULL;
67 int i_frequency = 0;
68 char *psz_lnb_type = "universal";
69 int dvb_plp_id = 0;
70 int i_inversion = -1;
71 int i_srate = 27500000;
72 int i_fec = 999;
73 int i_rolloff = 35;
74 int i_satnum = 0;
75 int i_uncommitted = 0;
76 int i_voltage = 13;
77 int b_tone = 0;
78 int i_bandwidth = 8;
79 char *psz_modulation = NULL;
80 int i_pilot = -1;
81 int i_mis = 0;
82 char *psz_mis_pls_mode = "ROOT";
83 int i_mis_pls_mode = 0;
84 int i_mis_pls_code = 0;
85 int i_mis_is_id = 0;
86 int i_fec_lp = 999;
87 int i_guard = -1;
88 int i_transmission = -1;
89 int i_hierarchy = -1;
90 mtime_t i_frontend_timeout_duration = DEFAULT_FRONTEND_TIMEOUT;
91 mtime_t i_quit_timeout_duration = 0;
92 int b_budget_mode = 0;
93 int b_any_type = 0;
94 int b_select_pmts = 0;
95 int b_random_tsid = 0;
96 char *psz_udp_src = NULL;
97 const char *psz_native_charset = "UTF-8//IGNORE";
98 print_type_t i_print_type = PRINT_TEXT;
99 bool b_print_enabled = false;
100 FILE *print_fh;
101 mtime_t i_print_period = 0;
102 mtime_t i_es_timeout = 0;
104 int i_verbose = DEFAULT_VERBOSITY;
105 int i_syslog = 0;
106 char *psz_syslog_ident = NULL;
108 uint8_t pi_ssrc_global[4] = { 0, 0, 0, 0 };
109 static bool b_udp_global = false;
110 static bool b_dvb_global = false;
111 static bool b_epg_global = false;
112 static mtime_t i_latency_global = DEFAULT_OUTPUT_LATENCY;
113 static mtime_t i_retention_global = DEFAULT_MAX_RETENTION;
114 static int i_ttl_global = 64;
116 static const char *psz_dvb_charset = "UTF-8//IGNORE";
117 static iconv_t conf_iconv = (iconv_t)-1;
118 static uint16_t i_network_id = 0xffff;
119 static dvb_string_t network_name;
120 static dvb_string_t provider_name;
122 /* PID mapping */
123 bool b_do_remap = false;
124 uint16_t pi_newpids[ N_MAP_PIDS ]; /* pmt, audio, video, spu */
126 void (*pf_Open)( void ) = NULL;
127 void (*pf_Reset)( void ) = NULL;
128 int (*pf_SetFilter)( uint16_t i_pid ) = NULL;
129 void (*pf_UnsetFilter)( int i_fd, uint16_t i_pid ) = NULL;
131 /*****************************************************************************
132 * Configuration files
133 *****************************************************************************/
134 void config_Init( output_config_t *p_config )
136 memset( p_config, 0, sizeof(output_config_t) );
138 p_config->psz_displayname = NULL;
139 p_config->i_network_id = i_network_id;
140 dvb_string_init(&p_config->network_name);
141 dvb_string_init(&p_config->service_name);
142 dvb_string_init(&p_config->provider_name);
143 p_config->psz_srcaddr = NULL;
145 p_config->i_family = AF_UNSPEC;
146 p_config->connect_addr.ss_family = AF_UNSPEC;
147 p_config->bind_addr.ss_family = AF_UNSPEC;
148 p_config->i_if_index_v6 = -1;
149 p_config->i_srcport = 0;
151 p_config->pi_pids = NULL;
152 p_config->b_passthrough = false;
153 p_config->b_do_remap = false;
154 unsigned int i;
155 for ( i = 0; i < N_MAP_PIDS; i++ ) {
156 p_config->pi_confpids[i] = UNUSED_PID;
160 void config_Free( output_config_t *p_config )
162 free( p_config->psz_displayname );
163 dvb_string_clean( &p_config->network_name );
164 dvb_string_clean( &p_config->service_name );
165 dvb_string_clean( &p_config->provider_name );
166 free( p_config->pi_pids );
167 free( p_config->psz_srcaddr );
170 static void config_Defaults( output_config_t *p_config )
172 config_Init( p_config );
174 p_config->i_config = (b_udp_global ? OUTPUT_UDP : 0) |
175 (b_dvb_global ? OUTPUT_DVB : 0) |
176 (b_epg_global ? OUTPUT_EPG : 0);
177 p_config->i_max_retention = i_retention_global;
178 p_config->i_output_latency = i_latency_global;
179 p_config->i_tsid = -1;
180 p_config->i_ttl = i_ttl_global;
181 memcpy( p_config->pi_ssrc, pi_ssrc_global, 4 * sizeof(uint8_t) );
182 dvb_string_copy(&p_config->network_name, &network_name);
183 dvb_string_copy(&p_config->provider_name, &provider_name);
186 char *config_stropt( const char *psz_string )
188 char *ret, *tmp;
189 if ( !psz_string || strlen( psz_string ) == 0 )
190 return NULL;
191 ret = tmp = strdup( psz_string );
192 while (*tmp) {
193 if (*tmp == '_')
194 *tmp = ' ';
195 if (*tmp == '/') {
196 *tmp = '\0';
197 break;
199 tmp++;
201 return ret;
204 static uint8_t *config_striconv( const char *psz_string,
205 const char *psz_charset, size_t *pi_length )
207 char *psz_input = config_stropt(psz_string);
208 *pi_length = strlen(psz_input);
210 /* do not convert ASCII strings */
211 const char *c = psz_string;
212 while (*c)
213 if (!isascii(*c++))
214 break;
215 if (!*c)
216 return (uint8_t *)psz_input;
218 if ( !strcasecmp( psz_native_charset, psz_charset ) )
219 return (uint8_t *)psz_input;
221 #ifdef HAVE_ICONV
222 if ( conf_iconv == (iconv_t)-1 )
224 conf_iconv = iconv_open( psz_charset, psz_native_charset );
225 if ( conf_iconv == (iconv_t)-1 )
226 return (uint8_t *)psz_input;
229 char *psz_tmp = psz_input;
230 size_t i_input = *pi_length;
231 size_t i_output = i_input * 6;
232 size_t i_available = i_output;
233 char *p_output = malloc( i_output );
234 char *p = p_output;
235 if ( iconv( conf_iconv, &psz_tmp, &i_input, &p, &i_available ) == (size_t)-1 )
237 free( p_output );
239 return (uint8_t *)psz_input;
242 free(psz_input);
243 *pi_length = i_output - i_available;
244 return (uint8_t *)p_output;
245 #else
246 msg_Warn( NULL,
247 "unable to convert from %s to %s (iconv is not available)",
248 psz_native_charset, psz_charset );
249 return (uint8_t *)psz_input;
250 #endif
253 static void config_strdvb( dvb_string_t *p_dvb_string, const char *psz_string,
254 const char *psz_charset )
256 if (psz_string == NULL)
258 dvb_string_init(p_dvb_string);
259 return;
261 dvb_string_clean(p_dvb_string);
263 size_t i_iconv;
264 uint8_t *p_iconv = config_striconv(psz_string, psz_charset, &i_iconv);
265 p_dvb_string->p = dvb_string_set(p_iconv, i_iconv, psz_charset,
266 &p_dvb_string->i);
267 free(p_iconv);
270 static bool config_ParseHost( output_config_t *p_config, char *psz_string )
272 struct addrinfo *p_ai;
273 int i_mtu;
275 p_config->psz_displayname = strdup( psz_string );
277 p_ai = ParseNodeService( psz_string, &psz_string, DEFAULT_PORT );
278 if ( p_ai == NULL ) return false;
279 memcpy( &p_config->connect_addr, p_ai->ai_addr, p_ai->ai_addrlen );
280 freeaddrinfo( p_ai );
282 p_config->i_family = p_config->connect_addr.ss_family;
283 if ( p_config->i_family == AF_UNSPEC ) return false;
285 if ( psz_string == NULL || !*psz_string ) goto end;
287 if ( *psz_string == '@' )
289 psz_string++;
290 p_ai = ParseNodeService( psz_string, &psz_string, 0 );
291 if ( p_ai == NULL || p_ai->ai_family != p_config->i_family )
292 msg_Warn( NULL, "invalid bind address" );
293 else
294 memcpy( &p_config->bind_addr, p_ai->ai_addr, p_ai->ai_addrlen );
295 freeaddrinfo( p_ai );
298 const char *psz_charset = psz_dvb_charset;
299 const char *psz_network_name = NULL;
300 const char *psz_service_name = NULL;
301 const char *psz_provider_name = NULL;
303 while ( (psz_string = strchr( psz_string, '/' )) != NULL )
305 *psz_string++ = '\0';
307 #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) ))
308 #define ARG_OPTION( option ) (psz_string + strlen(option))
310 if ( IS_OPTION("udp") )
311 p_config->i_config |= OUTPUT_UDP;
312 else if ( IS_OPTION("dvb") )
313 p_config->i_config |= OUTPUT_DVB;
314 else if ( IS_OPTION("epg") )
315 p_config->i_config |= OUTPUT_EPG;
316 else if ( IS_OPTION("tsid=") )
317 p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 );
318 else if ( IS_OPTION("retention=") )
319 p_config->i_max_retention = strtoll( ARG_OPTION("retention="),
320 NULL, 0 ) * 1000;
321 else if ( IS_OPTION("latency=") )
322 p_config->i_output_latency = strtoll( ARG_OPTION("latency="),
323 NULL, 0 ) * 1000;
324 else if ( IS_OPTION("ttl=") )
325 p_config->i_ttl = strtol( ARG_OPTION("ttl="), NULL, 0 );
326 else if ( IS_OPTION("tos=") )
327 p_config->i_tos = strtol( ARG_OPTION("tos="), NULL, 0 );
328 else if ( IS_OPTION("mtu=") )
329 p_config->i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 );
330 else if ( IS_OPTION("ifindex=") )
331 p_config->i_if_index_v6 = strtol( ARG_OPTION("ifindex="), NULL, 0 );
332 else if ( IS_OPTION("networkid=") )
333 p_config->i_network_id = strtol( ARG_OPTION("networkid="), NULL, 0 );
334 else if ( IS_OPTION("onid=") )
335 p_config->i_onid = strtol( ARG_OPTION("onid="), NULL, 0 );
336 else if ( IS_OPTION("charset=") )
337 psz_charset = ARG_OPTION("charset=");
338 else if ( IS_OPTION("networkname=") )
339 psz_network_name = ARG_OPTION("networkname=");
340 else if ( IS_OPTION("srvname=") )
341 psz_service_name = ARG_OPTION("srvname=");
342 else if ( IS_OPTION("srvprovider=") )
343 psz_provider_name = ARG_OPTION("srvprovider=");
344 else if ( IS_OPTION("srcaddr=") )
346 if ( p_config->i_family != AF_INET ) {
347 msg_Err( NULL, "RAW sockets currently implemented for ipv4 only");
348 return false;
350 free( p_config->psz_srcaddr );
351 p_config->psz_srcaddr = config_stropt( ARG_OPTION("srcaddr=") );
352 p_config->i_config |= OUTPUT_RAW;
354 else if ( IS_OPTION("srcport=") )
355 p_config->i_srcport = strtol( ARG_OPTION("srcport="), NULL, 0 );
356 else if ( IS_OPTION("ssrc=") )
358 in_addr_t i_addr = inet_addr( ARG_OPTION("ssrc=") );
359 memcpy( p_config->pi_ssrc, &i_addr, 4 * sizeof(uint8_t) );
361 else if ( IS_OPTION("pidmap=") )
363 char *str1;
364 char *saveptr = NULL;
365 char *tok = NULL;
366 int i, i_newpid;
367 for (i = 0, str1 = config_stropt( (ARG_OPTION("pidmap="))); i < N_MAP_PIDS; i++, str1 = NULL)
369 tok = strtok_r(str1, ",", &saveptr);
370 if ( !tok )
371 break;
372 i_newpid = strtoul(tok, NULL, 0);
373 p_config->pi_confpids[i] = i_newpid;
375 p_config->b_do_remap = true;
377 else if ( IS_OPTION("newsid=") )
378 p_config->i_new_sid = strtol( ARG_OPTION("newsid="), NULL, 0 );
379 else
380 msg_Warn( NULL, "unrecognized option %s", psz_string );
382 #undef IS_OPTION
383 #undef ARG_OPTION
386 if (psz_network_name != NULL)
387 config_strdvb( &p_config->network_name, psz_network_name, psz_charset );
388 if (psz_service_name != NULL)
389 config_strdvb( &p_config->service_name, psz_service_name, psz_charset );
390 if (psz_provider_name != NULL)
391 config_strdvb( &p_config->provider_name, psz_provider_name,
392 psz_charset );
394 end:
395 i_mtu = p_config->i_family == AF_INET6 ? DEFAULT_IPV6_MTU :
396 DEFAULT_IPV4_MTU;
398 if ( !p_config->i_mtu )
399 p_config->i_mtu = i_mtu;
400 else if ( p_config->i_mtu < TS_SIZE + RTP_HEADER_SIZE )
402 msg_Warn( NULL, "invalid MTU %d, setting %d", p_config->i_mtu, i_mtu );
403 p_config->i_mtu = i_mtu;
406 return true;
409 static void config_Print( output_config_t *p_config )
411 if ( p_config->b_passthrough )
413 msg_Dbg( NULL, "conf: %s config=0x%"PRIx64" sid=*",
414 p_config->psz_displayname, p_config->i_config);
415 return;
418 const char *psz_base = "conf: %s config=0x%"PRIx64" sid=%hu pids[%d]=";
419 size_t i_len = strlen(psz_base) + 6 * p_config->i_nb_pids + 1;
420 char psz_format[i_len];
421 int i, j = strlen(psz_base);
423 strcpy( psz_format, psz_base );
424 for ( i = 0; i < p_config->i_nb_pids; i++ )
425 j += sprintf( psz_format + j, "%u,", p_config->pi_pids[i] );
426 psz_format[j - 1] = '\0';
428 msg_Dbg( NULL, psz_format, p_config->psz_displayname, p_config->i_config,
429 p_config->i_sid, p_config->i_nb_pids );
432 void config_ReadFile(void)
434 FILE *p_file;
435 char psz_line[2048];
436 int i;
438 if ( psz_conf_file == NULL )
440 msg_Err( NULL, "no config file" );
441 return;
444 if ( (p_file = fopen( psz_conf_file, "r" )) == NULL )
446 msg_Err( NULL, "can't fopen config file %s", psz_conf_file );
447 return;
450 while ( fgets( psz_line, sizeof(psz_line), p_file ) != NULL )
452 output_config_t config;
453 output_t *p_output;
454 char *psz_token, *psz_parser;
456 psz_parser = strchr( psz_line, '#' );
457 if ( psz_parser != NULL )
458 *psz_parser-- = '\0';
459 while ( psz_parser >= psz_line && isblank( *psz_parser ) )
460 *psz_parser-- = '\0';
461 if ( psz_line[0] == '\0' )
462 continue;
464 config_Defaults( &config );
466 psz_token = strtok_r( psz_line, "\t\n ", &psz_parser );
467 if ( psz_token == NULL || !config_ParseHost( &config, psz_token ))
469 config_Free( &config );
470 continue;
473 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
474 if ( psz_token == NULL )
476 config_Free( &config );
477 continue;
479 if( atoi( psz_token ) == 1 )
480 config.i_config |= OUTPUT_WATCH;
481 else
482 config.i_config &= ~OUTPUT_WATCH;
484 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
485 if ( psz_token == NULL )
487 config_Free( &config );
488 continue;
491 if ( psz_token[0] == '*' )
493 config.b_passthrough = true;
495 else
497 config.i_sid = strtol(psz_token, NULL, 0);
499 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
500 if ( psz_token != NULL )
502 psz_parser = NULL;
503 for ( ; ; )
505 psz_token = strtok_r( psz_token, ",", &psz_parser );
506 if ( psz_token == NULL )
507 break;
508 config.pi_pids = realloc( config.pi_pids,
509 (config.i_nb_pids + 1) * sizeof(uint16_t) );
510 config.pi_pids[config.i_nb_pids++] = strtol(psz_token, NULL, 0);
511 psz_token = NULL;
516 config_Print( &config );
518 p_output = output_Find( &config );
520 if ( p_output == NULL )
521 p_output = output_Create( &config );
523 if ( p_output != NULL )
525 free( p_output->config.psz_displayname );
526 p_output->config.psz_displayname = strdup( config.psz_displayname );
528 config.i_config |= OUTPUT_VALID | OUTPUT_STILL_PRESENT;
529 output_Change( p_output, &config );
530 demux_Change( p_output, &config );
533 config_Free( &config );
536 fclose( p_file );
538 for ( i = 0; i < i_nb_outputs; i++ )
540 output_t *p_output = pp_outputs[i];
541 output_config_t config;
543 config_Init( &config );
545 if ( (p_output->config.i_config & OUTPUT_VALID) &&
546 !(p_output->config.i_config & OUTPUT_STILL_PRESENT) )
548 msg_Dbg( NULL, "closing %s", p_output->config.psz_displayname );
549 demux_Change( p_output, &config );
550 output_Close( p_output );
553 p_output->config.i_config &= ~OUTPUT_STILL_PRESENT;
554 config_Free( &config );
558 /*****************************************************************************
559 * Signal Handler
560 *****************************************************************************/
561 static void signal_watcher_init(struct ev_signal *w, struct ev_loop *loop,
562 void (*cb)(struct ev_loop*, struct ev_signal*, int),
563 int signum)
565 ev_signal_init(w, cb, signum);
566 ev_signal_start(loop, w);
567 ev_unref(loop);
570 static void sighandler(struct ev_loop *loop, struct ev_signal *w, int revents)
572 switch (w->signum)
574 case SIGINT:
575 case SIGTERM:
576 default:
577 msg_Info( NULL, "Shutdown was requested." );
578 ev_break(loop, EVBREAK_ALL);
579 break;
581 case SIGHUP:
582 msg_Info( NULL, "Configuration reload was requested." );
583 config_ReadFile();
584 break;
588 /*****************************************************************************
589 * Quit timeout
590 *****************************************************************************/
591 static void quit_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
593 ev_break(loop, EVBREAK_ALL);
596 /*****************************************************************************
597 * Version
598 *****************************************************************************/
599 static void DisplayVersion()
601 msg_Raw( NULL, "DVBlast %s (%s)", VERSION, VERSION_EXTRA );
604 /*****************************************************************************
605 * Entry point
606 *****************************************************************************/
607 void usage()
609 DisplayVersion();
610 msg_Raw( NULL, "Usage: dvblast [-q] [-c <config file>] [-r <remote socket>] [-t <ttl>] [-o <SSRC IP>] "
611 "[-i <RT priority>] "
612 #ifdef HAVE_DVB_SUPPORT
613 "[-a <adapter>] [-n <frontend number>] [-S <diseqc>] [-k <uncommitted port>]"
614 "[-f <frequency>]"
615 "[-s <symbol rate>] [-v <0|13|18>] [-p] [-b <bandwidth>] [-I <inversion>] "
616 "[-F <fec inner>] [-m <modulation] [-R <rolloff>] [-P <pilot>] [-K <fec lp>] "
617 "[-G <guard interval>] [-H <hierarchy>] [-X <transmission>] [-O <lock timeout>] "
618 #endif
619 "[-D [<src host>[:<src port>]@]<src mcast>[:<port>][/<opts>]*] "
620 "[-u] [-w] [-U] [-L <latency>] [-E <retention>] [-d <dest IP>[<:port>][/<opts>]*] [-3] "
621 "[-z] [-C [-e] [-M <network name>] [-N <network ID>]] [-T] [-j <system charset>] "
622 "[-W] [-Y] [-l] [-g <logger ident>] [-V] [-h] [-B <provider_name>] "
623 "[-1 <mis_id>] [-2 <size>] [-5 <DVBS|DVBS2|DVBC_ANNEX_A|DVBC_ANNEX_B|DVBT|DVBT2|ATSC|ISDBT>] "
624 "[-J <DVB charset>] [-Q <quit timeout>] [-0 pid_mapping] [-x <text|xml>]"
625 "[-6 <print period>] [-7 <ES timeout>]" );
627 msg_Raw( NULL, "Input:" );
628 #ifdef HAVE_DVB_SUPPORT
629 msg_Raw( NULL, " -a --adapter read packets from a Linux-DVB adapter (typically 0-n)" );
630 msg_Raw( NULL, " -b --bandwidth frontend bandwidth" );
631 #endif
632 msg_Raw( NULL, " -D --rtp-input read packets from a multicast address instead of a DVB card" );
633 #ifdef HAVE_DVB_SUPPORT
634 msg_Raw( NULL, " -5 --delsys delivery system" );
635 msg_Raw( NULL, " DVBS|DVBS2|DVBC_ANNEX_A|DVBT|DVBT2|ATSC|ISDBT|DVBC_ANNEX_B(ATSC-C/QAMB) (default guessed)");
636 msg_Raw( NULL, " -f --frequency frontend frequency" );
637 msg_Raw( NULL, " -8 --lnb-type <type> Set LNB type')" );
638 msg_Raw( NULL, " universal old-sky (default: universal)");
639 msg_Raw( NULL, " -9 --dvb-plp-id <number> Switch PLP of the DVB-T2 transmission (default: 0)" );
640 msg_Raw( NULL, " -F --fec-inner Forward Error Correction (FEC Inner)");
641 msg_Raw( NULL, " DVB-S2 0|12|23|34|35|56|78|89|910|999 (default auto: 999)");
642 msg_Raw( NULL, " -I --inversion Inversion (-1 auto, 0 off, 1 on)" );
643 msg_Raw( NULL, " -m --modulation Modulation type" );
644 msg_Raw( NULL, " DVB-C qpsk|qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
645 msg_Raw( NULL, " DVB-T qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
646 msg_Raw( NULL, " DVB-S2 qpsk|psk_8|apsk_16|apsk_32 (default legacy DVB-S)" );
647 msg_Raw( NULL, " -n --frontend-number <frontend number>" );
648 msg_Raw( NULL, " -p --force-pulse force 22kHz pulses for high-band selection (DVB-S)" );
649 msg_Raw( NULL, " -P --pilot DVB-S2 Pilot (-1 auto, 0 off, 1 on)" );
650 msg_Raw( NULL, " -R --rolloff DVB-S2 Rolloff value" );
651 msg_Raw( NULL, " DVB-S2 35=0.35|25=0.25|20=0.20|0=AUTO (default: 35)" );
652 msg_Raw( NULL, " -1 --multistream-id Set stream ID (0-2147483648, default: 0)." );
653 msg_Raw( NULL, " --multistream-id-pls-mode Set multistream PLS mode (ROOT, GOLD, COMBO, default: ROOT)" );
654 msg_Raw( NULL, " --multistream-id-pls-code Set multistream PLS code (0-262143, default: 0)" );
655 msg_Raw( NULL, " --multistream-id-is-id Set multistream IS id (0-255, default: 0)" );
656 msg_Raw( NULL, " -K --fec-lp DVB-T low priority FEC (default auto)" );
657 msg_Raw( NULL, " -G --guard DVB-T guard interval" );
658 msg_Raw( NULL, " DVB-T 32 (1/32)|16 (1/16)|8 (1/8)|4 (1/4)|-1 (auto, default)" );
659 msg_Raw( NULL, " -H --hierarchy DVB-T hierarchy (0, 1, 2, 4 or -1 auto, default)" );
660 msg_Raw( NULL, " -X --transmission DVB-T transmission (2, 4, 8 or -1 auto, default)" );
661 msg_Raw( NULL, " -s --symbol-rate" );
662 msg_Raw( NULL, " -S --diseqc satellite number for diseqc (0: no diseqc, 1-4, A or B)" );
663 msg_Raw( NULL, " -k --uncommitted port number for uncommitted DiSEqC switch (0: no uncommitted DiSEqC switch, 1-16)" );
664 msg_Raw( NULL, " -u --budget-mode turn on budget mode (no hardware PID filtering)" );
665 msg_Raw( NULL, " -v --voltage voltage to apply to the LNB (QPSK)" );
666 msg_Raw( NULL, " -w --select-pmts set a PID filter on all PMTs (auto on, when config file is used)" );
667 msg_Raw( NULL, " -O --lock-timeout timeout for the lock operation (in ms)" );
668 msg_Raw( NULL, " -y --ca-number <ca_device_number>" );
669 msg_Raw( NULL, " -2 --dvr-buf-size <size> set the size of the DVR TS buffer in bytes (default: %d)", i_dvr_buffer_size);
670 #endif
672 msg_Raw( NULL, "Output:" );
673 msg_Raw( NULL, " -c --config-file <config file>" );
674 msg_Raw( NULL, " -C --dvb-compliance pass through or build the mandatory DVB tables" );
675 msg_Raw( NULL, " -d --duplicate duplicate all received packets to a given destination" );
676 msg_Raw( NULL, " -3 --passthrough duplicate all received packets to stdout" );
677 msg_Raw( NULL, " -W --emm-passthrough pass through EMM data (CA system data)" );
678 msg_Raw( NULL, " -Y --ecm-passthrough pass through ECM data (CA program data)" );
679 msg_Raw( NULL, " -e --epg-passthrough pass through DVB EIT schedule tables" );
680 msg_Raw( NULL, " -E --retention maximum retention allowed between input and output (default: 40 ms)" );
681 msg_Raw( NULL, " -L --latency maximum latency allowed between input and output (default: 100 ms)" );
682 msg_Raw( NULL, " -M --network-name DVB network name to declare in the NIT" );
683 msg_Raw( NULL, " -N --network-id DVB network ID to declare in the NIT" );
684 msg_Raw( NULL, " -B --provider-name Service provider name to declare in the SDT" );
685 msg_Raw( NULL, " -o --rtp-output <SSRC IP>" );
686 msg_Raw( NULL, " -t --ttl <ttl> TTL of the output stream" );
687 msg_Raw( NULL, " -T --unique-ts-id generate random unique TS ID for each output" );
688 msg_Raw( NULL, " -U --udp use raw UDP rather than RTP (required by some IPTV set top boxes)" );
689 msg_Raw( NULL, " -z --any-type pass through all ESs from the PMT, of any type" );
690 msg_Raw( NULL, " -0 --pidmap <pmt_pid,audio_pid,video_pid,spu_pid>");
692 msg_Raw( NULL, "Misc:" );
693 msg_Raw( NULL, " -h --help display this full help" );
694 msg_Raw( NULL, " -i --priority <RT priority>" );
695 msg_Raw( NULL, " -j --system-charset character set used for printing messages (default UTF-8//IGNORE)" );
696 msg_Raw( NULL, " -J --dvb-charset character set used in output DVB tables (default UTF-8//IGNORE)" );
697 msg_Raw( NULL, " -l --logger use syslog for logging messages instead of stderr" );
698 msg_Raw( NULL, " -g --logger-ident program name that will be used in syslog messages" );
699 msg_Raw( NULL, " -x --print print interesting events on stdout in a given format" );
700 msg_Raw( NULL, " -q --quiet be quiet (less verbosity, repeat or use number for even quieter)" );
701 msg_Raw( NULL, " -Q --quit-timeout when locked, quit after this delay (in ms), or after the first lock timeout" );
702 msg_Raw( NULL, " -6 --print-period periodicity at which we print bitrate and errors (in ms)" );
703 msg_Raw( NULL, " -7 --es-timeout time of inactivy before which a PID is reported down (in ms)" );
704 msg_Raw( NULL, " -r --remote-socket <remote socket>" );
705 msg_Raw( NULL, " -V --version only display the version" );
706 exit(1);
709 int main( int i_argc, char **pp_argv )
711 const char *psz_network_name = "DVBlast - videolan.org";
712 const char *psz_provider_name = NULL;
713 char *psz_dup_config = NULL;
714 struct sched_param param;
715 int i_error;
716 int c;
717 int b_enable_syslog = 0;
718 struct ev_signal sigint_watcher, sigterm_watcher, sighup_watcher;
719 struct ev_timer quit_watcher;
721 print_fh = stdout;
723 if ( i_argc == 1 )
724 usage();
727 * The only short options left are: 4
728 * Use them wisely.
730 static const struct option long_options[] =
732 { "config-file", required_argument, NULL, 'c' },
733 { "remote-socket", required_argument, NULL, 'r' },
734 { "ttl", required_argument, NULL, 't' },
735 { "rtp-output", required_argument, NULL, 'o' },
736 { "priority", required_argument, NULL, 'i' },
737 { "adapter", required_argument, NULL, 'a' },
738 { "frontend-number", required_argument, NULL, 'n' },
739 { "delsys", required_argument, NULL, '5' },
740 { "dvb-plp-id", required_argument, NULL, '9' },
741 { "frequency", required_argument, NULL, 'f' },
742 { "lnb-type", required_argument, NULL, '8' },
743 { "fec-inner", required_argument, NULL, 'F' },
744 { "rolloff", required_argument, NULL, 'R' },
745 { "symbol-rate", required_argument, NULL, 's' },
746 { "diseqc", required_argument, NULL, 'S' },
747 { "uncommitted", required_argument, NULL, 'k' },
748 { "voltage", required_argument, NULL, 'v' },
749 { "force-pulse", no_argument, NULL, 'p' },
750 { "bandwidth", required_argument, NULL, 'b' },
751 { "inversion", required_argument, NULL, 'I' },
752 { "modulation", required_argument, NULL, 'm' },
753 { "pilot", required_argument, NULL, 'P' },
754 { "multistream-id", required_argument, NULL, '1' },
755 { "multistream-id-pls-mode", required_argument, NULL, 0x100001 },
756 { "multistream-id-pls-code", required_argument, NULL, 0x100002 },
757 { "multistream-id-is-id" , required_argument, NULL, 0x100003 },
758 { "fec-lp", required_argument, NULL, 'K' },
759 { "guard", required_argument, NULL, 'G' },
760 { "hierarchy", required_argument, NULL, 'H' },
761 { "transmission", required_argument, NULL, 'X' },
762 { "lock-timeout", required_argument, NULL, 'O' },
763 { "budget-mode", no_argument, NULL, 'u' },
764 { "select-pmts", no_argument, NULL, 'w' },
765 { "udp", no_argument, NULL, 'U' },
766 { "unique-ts-id", no_argument, NULL, 'T' },
767 { "latency", required_argument, NULL, 'L' },
768 { "retention", required_argument, NULL, 'E' },
769 { "duplicate", required_argument, NULL, 'd' },
770 { "passthrough", no_argument, NULL, '3' },
771 { "rtp-input", required_argument, NULL, 'D' },
772 { "any-type", no_argument, NULL, 'z' },
773 { "dvb-compliance", no_argument, NULL, 'C' },
774 { "emm-passthrough", no_argument, NULL, 'W' },
775 { "ecm-passthrough", no_argument, NULL, 'Y' },
776 { "epg-passthrough", no_argument, NULL, 'e' },
777 { "network-name", no_argument, NULL, 'M' },
778 { "network-id", no_argument, NULL, 'N' },
779 { "system-charset", required_argument, NULL, 'j' },
780 { "dvb-charset", required_argument, NULL, 'J' },
781 { "provider-name", required_argument, NULL, 'B' },
782 { "logger", no_argument, NULL, 'l' },
783 { "logger-ident", required_argument, NULL, 'g' },
784 { "print", required_argument, NULL, 'x' },
785 { "quit-timeout", required_argument, NULL, 'Q' },
786 { "print-period", required_argument, NULL, '6' },
787 { "es-timeout", required_argument, NULL, '7' },
788 { "quiet", no_argument, NULL, 'q' },
789 { "help", no_argument, NULL, 'h' },
790 { "version", no_argument, NULL, 'V' },
791 { "ca-number", required_argument, NULL, 'y' },
792 { "pidmap", required_argument, NULL, '0' },
793 { "dvr-buf-size", required_argument, NULL, '2' },
794 { 0, 0, 0, 0 }
797 while ( (c = getopt_long(i_argc, pp_argv, "q::c:r:t:o:i:a:n:5:f:F:R:s:S:k:v:pb:I:m:P:K:G:H:X:O:uwUTL:E:d:3D:lg:zCWYeM:N:j:J:B:x:Q:6:7:hVy:0:1:2:9:", long_options, NULL)) != -1 )
799 switch ( c )
801 case 'q':
802 if ( optarg )
804 if ( *optarg == 'q' ) /* e.g. -qqq */
806 i_verbose--;
807 while ( *optarg == 'q' )
809 i_verbose--;
810 optarg++;
813 else
815 i_verbose -= atoi( optarg ); /* e.g. -q2 */
818 else
820 i_verbose--; /* -q */
822 break;
824 case 'c':
825 psz_conf_file = optarg;
827 * When configuration file is used it is reasonable to assume that
828 * services may be added/removed. If b_select_pmts is not set dvblast
829 * is unable to start streaming newly added services in the config.
831 b_select_pmts = 1;
832 break;
834 case 'r':
835 psz_srv_socket = optarg;
836 break;
838 case 't':
839 i_ttl_global = strtol( optarg, NULL, 0 );
840 break;
842 case 'o':
844 struct in_addr maddr;
845 if ( !inet_aton( optarg, &maddr ) )
846 usage();
847 memcpy( pi_ssrc_global, &maddr.s_addr, 4 * sizeof(uint8_t) );
848 break;
851 case 'i':
852 i_priority = strtol( optarg, NULL, 0 );
853 break;
855 case 'a':
856 i_adapter = strtol( optarg, NULL, 0 );
857 break;
859 case 'n':
860 i_fenum = strtol( optarg, NULL, 0 );
861 break;
863 case 'y':
864 i_canum = strtol( optarg, NULL, 0 );
865 break;
867 case '5':
868 psz_delsys = optarg;
869 break;
870 case '9':
871 dvb_plp_id = strtol( optarg, NULL, 0 );
872 break;
873 case 'f':
874 if (optarg && optarg[0] != '-')
875 i_frequency = strtol( optarg, NULL, 0 );
876 if ( pf_Open != NULL )
877 usage();
878 #ifdef HAVE_DVB_SUPPORT
879 pf_Open = dvb_Open;
880 pf_Reset = dvb_Reset;
881 pf_SetFilter = dvb_SetFilter;
882 pf_UnsetFilter = dvb_UnsetFilter;
883 #else
884 msg_Err( NULL, "DVBlast is compiled without DVB support.");
885 exit(1);
886 #endif
887 break;
889 case '8':
890 psz_lnb_type = optarg;
891 break;
893 case 'F':
894 i_fec = strtol( optarg, NULL, 0 );
895 break;
897 case 'R':
898 i_rolloff = strtol( optarg, NULL, 0 );
899 break;
901 case 's':
902 i_srate = strtol( optarg, NULL, 0 );
903 break;
905 case 'S':
906 i_satnum = strtol( optarg, NULL, 16 );
907 break;
909 case 'k':
910 i_uncommitted = strtol( optarg, NULL, 10 );
911 break;
913 case 'v':
914 i_voltage = strtol( optarg, NULL, 0 );
915 break;
917 case 'p':
918 b_tone = 1;
919 break;
921 case 'b':
922 i_bandwidth = strtol( optarg, NULL, 0 );
923 break;
925 case 'I':
926 i_inversion = strtol( optarg, NULL, 0 );
927 break;
929 case 'm':
930 psz_modulation = optarg;
931 break;
933 case 'P':
934 i_pilot = strtol( optarg, NULL, 0 );
935 break;
937 case '1':
938 i_mis = strtol( optarg, NULL, 0 );
939 break;
941 case 0x100001: // --multistream-id-pls-mode
942 psz_mis_pls_mode = optarg;
943 if ( streq( psz_mis_pls_mode, "ROOT" ) ) {
944 i_mis_pls_mode = 0;
945 } else if ( streq( psz_mis_pls_mode, "GOLD" ) ) {
946 i_mis_pls_mode = 1;
947 } else if ( streq( psz_mis_pls_mode, "COMBO" ) ) {
948 i_mis_pls_mode = 2;
949 } else {
950 msg_Err(NULL, "Invalid --multistream-id-pls-mode '%s', valid options are: ROOT GOLD COMBO", optarg);
951 exit(1);
953 break;
955 case 0x100002: // --multistream-id-pls-code
956 i_mis_pls_code = strtol( optarg, NULL, 0 );
957 if ( i_mis_pls_code < 0 || i_mis_pls_code > 262143 ) {
958 msg_Err(NULL, "ERROR: Invalid --multistream-id-pls-code '%s', valid options are: 0-262143", optarg);
959 exit(1);
961 break;
963 case 0x100003: // --multistream-id-is-id
964 i_mis_is_id = strtol( optarg, NULL, 0 );
965 if ( i_mis_is_id < 0 || i_mis_is_id > 255 ) {
966 msg_Err(NULL, "ERROR: Invalid --multistream-id-is-id '%s', valid options are: 0-255", optarg);
967 exit(1);
969 break;
971 case 'K':
972 i_fec_lp = strtol( optarg, NULL, 0 );
973 break;
975 case 'G':
976 i_guard = strtol( optarg, NULL, 0 );
977 break;
979 case 'X':
980 i_transmission = strtol( optarg, NULL, 0 );
981 break;
983 case 'O':
984 i_frontend_timeout_duration = strtoll( optarg, NULL, 0 ) * 1000;
985 break;
987 case 'H':
988 i_hierarchy = strtol( optarg, NULL, 0 );
989 break;
991 case 'u':
992 b_budget_mode = 1;
993 break;
995 case 'w':
996 b_select_pmts = !b_select_pmts;
997 break;
999 case 'U':
1000 b_udp_global = true;
1001 break;
1003 case 'L':
1004 i_latency_global = strtoll( optarg, NULL, 0 ) * 1000;
1005 break;
1007 case 'E':
1008 i_retention_global = strtoll( optarg, NULL, 0 ) * 1000;
1009 break;
1011 case 'd':
1012 psz_dup_config = optarg;
1013 break;
1015 case '3':
1016 b_passthrough = true;
1017 print_fh = stderr;
1018 break;
1020 case 'D':
1021 psz_udp_src = optarg;
1022 if ( pf_Open != NULL )
1023 usage();
1024 pf_Open = udp_Open;
1025 pf_Reset = udp_Reset;
1026 pf_SetFilter = udp_SetFilter;
1027 pf_UnsetFilter = udp_UnsetFilter;
1028 break;
1030 case 'z':
1031 b_any_type = 1;
1032 break;
1034 case 'C':
1035 b_dvb_global = true;
1036 break;
1038 case 'e':
1039 b_epg_global = true;
1040 break;
1042 case 'M':
1043 psz_network_name = optarg;
1044 break;
1046 case 'N':
1047 i_network_id = strtoul( optarg, NULL, 0 );
1048 break;
1050 case 'T':
1051 b_random_tsid = 1;
1052 break;
1054 case 'j':
1055 psz_native_charset = optarg;
1056 break;
1058 case 'J':
1059 psz_dvb_charset = optarg;
1060 break;
1062 case 'B':
1063 psz_provider_name = optarg;
1064 break;
1066 case 'l':
1067 b_enable_syslog = 1;
1068 break;
1070 case 'g':
1071 psz_syslog_ident = optarg;
1072 break;
1074 case 'x':
1075 b_print_enabled = true;
1076 if ( !strcmp(optarg, "text") )
1077 i_print_type = PRINT_TEXT;
1078 else if ( !strcmp(optarg, "xml") )
1079 i_print_type = PRINT_XML;
1080 else
1082 b_print_enabled = false;
1083 msg_Warn( NULL, "unrecognized print type %s", optarg );
1085 break;
1087 case 'Q':
1088 i_quit_timeout_duration = strtoll( optarg, NULL, 0 ) * 1000;
1089 break;
1091 case '6':
1092 i_print_period = strtoll( optarg, NULL, 0 ) * 1000;
1093 break;
1095 case '7':
1096 i_es_timeout = strtoll( optarg, NULL, 0 ) * 1000;
1097 break;
1099 case 'V':
1100 DisplayVersion();
1101 exit(0);
1102 break;
1104 case '0': {
1105 /* We expect a comma separated list of numbers.
1106 Put them into the pi_newpids array as they appear */
1107 char *str1;
1108 char *saveptr = NULL;
1109 char *tok = NULL;
1110 int i, i_newpid;
1111 for (i = 0, str1 = optarg; i < N_MAP_PIDS; i++, str1 = NULL)
1113 tok = strtok_r(str1, ",", &saveptr);
1114 if ( !tok )
1115 break;
1116 i_newpid = strtoul(tok, NULL, 0);
1117 if ( !i_newpid ) {
1118 msg_Err( NULL, "Invalid pidmap string" );
1119 usage();
1121 pi_newpids[i] = i_newpid;
1123 b_do_remap = true;
1124 break;
1126 #ifdef HAVE_DVB_SUPPORT
1127 case '2':
1128 i_dvr_buffer_size = strtol( optarg, NULL, 0 );
1129 if (!i_dvr_buffer_size)
1130 usage(); // it exits
1131 /* roundup to packet size */
1132 i_dvr_buffer_size += TS_SIZE - 1;
1133 i_dvr_buffer_size /= TS_SIZE;
1134 i_dvr_buffer_size *= TS_SIZE;
1135 break;
1136 #endif
1137 case 'h':
1138 default:
1139 usage();
1142 if ( optind < i_argc || pf_Open == NULL )
1143 usage();
1145 if ( b_enable_syslog )
1146 msg_Connect( psz_syslog_ident ? psz_syslog_ident : pp_argv[0] );
1148 if ( b_print_enabled )
1150 /* Make std* line-buffered */
1151 setvbuf(print_fh, NULL, _IOLBF, 0);
1154 if ( i_verbose )
1155 DisplayVersion();
1157 msg_Warn( NULL, "restarting" );
1159 switch (i_print_type)
1161 case PRINT_XML:
1162 fprintf(print_fh, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1163 fprintf(print_fh, "<TS>\n");
1164 break;
1165 default:
1166 break;
1169 if ( b_udp_global )
1171 msg_Warn( NULL, "raw UDP output is deprecated. Please consider using RTP." );
1172 msg_Warn( NULL, "for DVB-IP compliance you should use RTP." );
1175 if ( b_epg_global && !b_dvb_global )
1177 msg_Dbg( NULL, "turning on DVB compliance, required by EPG information" );
1178 b_dvb_global = true;
1181 if ((event_loop = ev_default_loop(0)) == NULL)
1183 msg_Err( NULL, "unable to initialize libev" );
1184 exit(EXIT_FAILURE);
1187 memset( &output_dup, 0, sizeof(output_dup) );
1188 if ( psz_dup_config != NULL )
1190 output_config_t config;
1192 config_Defaults( &config );
1193 if ( !config_ParseHost( &config, psz_dup_config ) )
1194 msg_Err( NULL, "Invalid target address for -d switch" );
1195 else
1197 output_Init( &output_dup, &config );
1198 output_Change( &output_dup, &config );
1201 config_Free( &config );
1204 config_strdvb( &network_name, psz_network_name, psz_dvb_charset );
1205 config_strdvb( &provider_name, psz_provider_name, psz_dvb_charset );
1207 /* Set signal handlers */
1208 signal_watcher_init(&sigint_watcher, event_loop, sighandler, SIGINT);
1209 signal_watcher_init(&sigterm_watcher, event_loop, sighandler, SIGTERM);
1210 signal_watcher_init(&sighup_watcher, event_loop, sighandler, SIGHUP);
1212 srand( time(NULL) * getpid() );
1214 if ( i_mis_pls_mode || i_mis_pls_code || i_mis_is_id )
1216 i_mis = calc_multistream_id( i_mis_pls_mode, i_mis_pls_code, i_mis_is_id );
1217 msg_Info( NULL, "Calculating multistream-id using pls-mode: %s (%d) pls-code: %d is-id: %d. Resulting multistream-id: %d (0x%x)",
1218 psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id, i_mis, i_mis );
1220 else if ( i_mis )
1222 i_mis_pls_mode = (i_mis >> 26) & 0x03;
1223 i_mis_pls_code = (i_mis >> 8) & 0x3ffff;
1224 i_mis_is_id = i_mis & 0xff;
1225 psz_mis_pls_mode =
1226 i_mis_pls_mode == 0 ? "ROOT" :
1227 i_mis_pls_mode == 1 ? "GOLD" :
1228 i_mis_pls_mode == 2 ? "COMBO" : "UNKNOWN";
1230 msg_Info( NULL, "Calculated multistream pls-mode: %s (%d) pls-code: %d is-id: %d from multistream-id: %d (0x%x)",
1231 psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id, i_mis, i_mis );
1234 demux_Open();
1236 if ( i_priority > 0 )
1238 memset( &param, 0, sizeof(struct sched_param) );
1239 param.sched_priority = i_priority;
1240 if ( (i_error = pthread_setschedparam( pthread_self(), SCHED_RR,
1241 &param )) )
1243 msg_Warn( NULL, "couldn't set thread priority: %s",
1244 strerror(i_error) );
1248 config_ReadFile();
1250 if ( psz_srv_socket != NULL )
1251 comm_Open();
1253 if ( i_quit_timeout_duration )
1255 ev_timer_init(&quit_watcher, quit_cb,
1256 i_quit_timeout_duration / 1000000., 0);
1257 ev_timer_start(event_loop, &quit_watcher);
1260 outputs_Init();
1262 ev_run(event_loop, 0);
1264 outputs_Close( i_nb_outputs );
1265 demux_Close();
1266 dvb_string_clean( &network_name );
1267 dvb_string_clean( &provider_name );
1268 if ( conf_iconv != (iconv_t)-1 )
1269 iconv_close( conf_iconv );
1271 switch (i_print_type)
1273 case PRINT_XML:
1274 fprintf(print_fh, "</TS>\n");
1275 break;
1276 default:
1277 break;
1280 if ( b_enable_syslog )
1281 msg_Disconnect();
1283 comm_Close();
1284 block_Vacuum();
1285 ev_loop_destroy(event_loop);
1287 return EXIT_SUCCESS;