1 /*****************************************************************************
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 *****************************************************************************/
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
49 #include <bitstream/dvb/si.h>
50 #include <bitstream/ietf/rtp.h>
54 /*****************************************************************************
56 *****************************************************************************/
57 struct ev_loop
*event_loop
;
58 output_t
**pp_outputs
= NULL
;
61 bool b_passthrough
= false;
62 static const char *psz_conf_file
= NULL
;
63 char *psz_srv_socket
= NULL
;
64 static int i_priority
= -1;
68 char *psz_delsys
= NULL
;
70 char *psz_lnb_type
= "universal";
73 int i_srate
= 27500000;
77 int i_uncommitted
= 0;
81 char *psz_modulation
= NULL
;
84 char *psz_mis_pls_mode
= "ROOT";
85 int i_mis_pls_mode
= 0;
86 int i_mis_pls_code
= 0;
90 int i_transmission
= -1;
92 mtime_t i_frontend_timeout_duration
= DEFAULT_FRONTEND_TIMEOUT
;
93 mtime_t i_quit_timeout_duration
= 0;
94 int b_budget_mode
= 0;
96 int b_select_pmts
= 0;
97 int b_random_tsid
= 0;
98 char *psz_udp_src
= NULL
;
99 int i_asi_adapter
= 0;
100 const char *psz_native_charset
= "UTF-8//IGNORE";
101 print_type_t i_print_type
= PRINT_TEXT
;
102 bool b_print_enabled
= false;
104 mtime_t i_print_period
= 0;
105 mtime_t i_es_timeout
= 0;
107 int i_verbose
= DEFAULT_VERBOSITY
;
109 char *psz_syslog_ident
= NULL
;
111 bool b_enable_emm
= false;
112 bool b_enable_ecm
= false;
114 uint8_t pi_ssrc_global
[4] = { 0, 0, 0, 0 };
115 static bool b_udp_global
= false;
116 static bool b_dvb_global
= false;
117 static bool b_epg_global
= false;
118 static mtime_t i_latency_global
= DEFAULT_OUTPUT_LATENCY
;
119 static mtime_t i_retention_global
= DEFAULT_MAX_RETENTION
;
120 static int i_ttl_global
= 64;
122 static const char *psz_dvb_charset
= "UTF-8//IGNORE";
123 static iconv_t conf_iconv
= (iconv_t
)-1;
124 static uint16_t i_network_id
= 0xffff;
125 static dvb_string_t network_name
;
126 static dvb_string_t provider_name
;
128 /* TPS Input log filename */
129 char * psz_mrtg_file
= NULL
;
132 bool b_do_remap
= false;
133 uint16_t pi_newpids
[ N_MAP_PIDS
]; /* pmt, audio, video, spu */
135 void (*pf_Open
)( void ) = NULL
;
136 void (*pf_Reset
)( void ) = NULL
;
137 int (*pf_SetFilter
)( uint16_t i_pid
) = NULL
;
138 void (*pf_UnsetFilter
)( int i_fd
, uint16_t i_pid
) = NULL
;
140 /*****************************************************************************
141 * Configuration files
142 *****************************************************************************/
143 void config_Init( output_config_t
*p_config
)
145 memset( p_config
, 0, sizeof(output_config_t
) );
147 p_config
->psz_displayname
= NULL
;
148 p_config
->i_network_id
= i_network_id
;
149 dvb_string_init(&p_config
->network_name
);
150 dvb_string_init(&p_config
->service_name
);
151 dvb_string_init(&p_config
->provider_name
);
152 p_config
->psz_srcaddr
= NULL
;
154 p_config
->i_family
= AF_UNSPEC
;
155 p_config
->connect_addr
.ss_family
= AF_UNSPEC
;
156 p_config
->bind_addr
.ss_family
= AF_UNSPEC
;
157 p_config
->i_if_index_v6
= -1;
158 p_config
->i_srcport
= 0;
160 p_config
->pi_pids
= NULL
;
161 p_config
->b_passthrough
= false;
162 p_config
->b_do_remap
= false;
164 for ( i
= 0; i
< N_MAP_PIDS
; i
++ ) {
165 p_config
->pi_confpids
[i
] = UNUSED_PID
;
169 void config_Free( output_config_t
*p_config
)
171 free( p_config
->psz_displayname
);
172 dvb_string_clean( &p_config
->network_name
);
173 dvb_string_clean( &p_config
->service_name
);
174 dvb_string_clean( &p_config
->provider_name
);
175 free( p_config
->pi_pids
);
176 free( p_config
->psz_srcaddr
);
179 static void config_Defaults( output_config_t
*p_config
)
181 config_Init( p_config
);
183 p_config
->i_config
= (b_udp_global
? OUTPUT_UDP
: 0) |
184 (b_dvb_global
? OUTPUT_DVB
: 0) |
185 (b_epg_global
? OUTPUT_EPG
: 0);
186 p_config
->i_max_retention
= i_retention_global
;
187 p_config
->i_output_latency
= i_latency_global
;
188 p_config
->i_tsid
= -1;
189 p_config
->i_ttl
= i_ttl_global
;
190 memcpy( p_config
->pi_ssrc
, pi_ssrc_global
, 4 * sizeof(uint8_t) );
191 dvb_string_copy(&p_config
->network_name
, &network_name
);
192 dvb_string_copy(&p_config
->provider_name
, &provider_name
);
195 char *config_stropt( const char *psz_string
)
198 if ( !psz_string
|| strlen( psz_string
) == 0 )
200 ret
= tmp
= strdup( psz_string
);
213 static uint8_t *config_striconv( const char *psz_string
,
214 const char *psz_charset
, size_t *pi_length
)
216 char *psz_input
= config_stropt(psz_string
);
217 *pi_length
= strlen(psz_input
);
219 /* do not convert ASCII strings */
220 const char *c
= psz_string
;
225 return (uint8_t *)psz_input
;
227 if ( !strcasecmp( psz_native_charset
, psz_charset
) )
228 return (uint8_t *)psz_input
;
231 if ( conf_iconv
== (iconv_t
)-1 )
233 conf_iconv
= iconv_open( psz_charset
, psz_native_charset
);
234 if ( conf_iconv
== (iconv_t
)-1 )
235 return (uint8_t *)psz_input
;
238 char *psz_tmp
= psz_input
;
239 size_t i_input
= *pi_length
;
240 size_t i_output
= i_input
* 6;
241 size_t i_available
= i_output
;
242 char *p_output
= malloc( i_output
);
244 if ( iconv( conf_iconv
, &psz_tmp
, &i_input
, &p
, &i_available
) == -1 )
248 return (uint8_t *)psz_input
;
252 *pi_length
= i_output
- i_available
;
253 return (uint8_t *)p_output
;
256 "unable to convert from %s to %s (iconv is not available)",
257 psz_native_charset
, psz_charset
);
258 return (uint8_t *)psz_input
;
262 static void config_strdvb( dvb_string_t
*p_dvb_string
, const char *psz_string
,
263 const char *psz_charset
)
265 if (psz_string
== NULL
)
267 dvb_string_init(p_dvb_string
);
270 dvb_string_clean(p_dvb_string
);
273 uint8_t *p_iconv
= config_striconv(psz_string
, psz_charset
, &i_iconv
);
274 p_dvb_string
->p
= dvb_string_set(p_iconv
, i_iconv
, psz_charset
,
279 static bool config_ParseHost( output_config_t
*p_config
, char *psz_string
)
281 struct addrinfo
*p_ai
;
284 p_config
->psz_displayname
= strdup( psz_string
);
286 p_ai
= ParseNodeService( psz_string
, &psz_string
, DEFAULT_PORT
);
287 if ( p_ai
== NULL
) return false;
288 memcpy( &p_config
->connect_addr
, p_ai
->ai_addr
, p_ai
->ai_addrlen
);
289 freeaddrinfo( p_ai
);
291 p_config
->i_family
= p_config
->connect_addr
.ss_family
;
292 if ( p_config
->i_family
== AF_UNSPEC
) return false;
294 if ( psz_string
== NULL
|| !*psz_string
) goto end
;
296 if ( *psz_string
== '@' )
299 p_ai
= ParseNodeService( psz_string
, &psz_string
, 0 );
300 if ( p_ai
== NULL
|| p_ai
->ai_family
!= p_config
->i_family
)
301 msg_Warn( NULL
, "invalid bind address" );
303 memcpy( &p_config
->bind_addr
, p_ai
->ai_addr
, p_ai
->ai_addrlen
);
304 freeaddrinfo( p_ai
);
307 const char *psz_charset
= psz_dvb_charset
;
308 const char *psz_network_name
= NULL
;
309 const char *psz_service_name
= NULL
;
310 const char *psz_provider_name
= NULL
;
312 while ( (psz_string
= strchr( psz_string
, '/' )) != NULL
)
314 *psz_string
++ = '\0';
316 #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) ))
317 #define ARG_OPTION( option ) (psz_string + strlen(option))
319 if ( IS_OPTION("udp") )
320 p_config
->i_config
|= OUTPUT_UDP
;
321 else if ( IS_OPTION("dvb") )
322 p_config
->i_config
|= OUTPUT_DVB
;
323 else if ( IS_OPTION("epg") )
324 p_config
->i_config
|= OUTPUT_EPG
;
325 else if ( IS_OPTION("tsid=") )
326 p_config
->i_tsid
= strtol( ARG_OPTION("tsid="), NULL
, 0 );
327 else if ( IS_OPTION("retention=") )
328 p_config
->i_max_retention
= strtoll( ARG_OPTION("retention="),
330 else if ( IS_OPTION("latency=") )
331 p_config
->i_output_latency
= strtoll( ARG_OPTION("latency="),
333 else if ( IS_OPTION("ttl=") )
334 p_config
->i_ttl
= strtol( ARG_OPTION("ttl="), NULL
, 0 );
335 else if ( IS_OPTION("tos=") )
336 p_config
->i_tos
= strtol( ARG_OPTION("tos="), NULL
, 0 );
337 else if ( IS_OPTION("mtu=") )
338 p_config
->i_mtu
= strtol( ARG_OPTION("mtu="), NULL
, 0 );
339 else if ( IS_OPTION("ifindex=") )
340 p_config
->i_if_index_v6
= strtol( ARG_OPTION("ifindex="), NULL
, 0 );
341 else if ( IS_OPTION("networkid=") )
342 p_config
->i_network_id
= strtol( ARG_OPTION("networkid="), NULL
, 0 );
343 else if ( IS_OPTION("onid=") )
344 p_config
->i_onid
= strtol( ARG_OPTION("onid="), NULL
, 0 );
345 else if ( IS_OPTION("charset=") )
346 psz_charset
= ARG_OPTION("charset=");
347 else if ( IS_OPTION("networkname=") )
348 psz_network_name
= ARG_OPTION("networkname=");
349 else if ( IS_OPTION("srvname=") )
350 psz_service_name
= ARG_OPTION("srvname=");
351 else if ( IS_OPTION("srvprovider=") )
352 psz_provider_name
= ARG_OPTION("srvprovider=");
353 else if ( IS_OPTION("srcaddr=") )
355 if ( p_config
->i_family
!= AF_INET
) {
356 msg_Err( NULL
, "RAW sockets currently implemented for ipv4 only");
359 free( p_config
->psz_srcaddr
);
360 p_config
->psz_srcaddr
= config_stropt( ARG_OPTION("srcaddr=") );
361 p_config
->i_config
|= OUTPUT_RAW
;
363 else if ( IS_OPTION("srcport=") )
364 p_config
->i_srcport
= strtol( ARG_OPTION("srcport="), NULL
, 0 );
365 else if ( IS_OPTION("ssrc=") )
367 in_addr_t i_addr
= inet_addr( ARG_OPTION("ssrc=") );
368 memcpy( p_config
->pi_ssrc
, &i_addr
, 4 * sizeof(uint8_t) );
370 else if ( IS_OPTION("pidmap=") )
373 char *saveptr
= NULL
;
376 for (i
= 0, str1
= config_stropt( (ARG_OPTION("pidmap="))); i
< N_MAP_PIDS
; i
++, str1
= NULL
)
378 tok
= strtok_r(str1
, ",", &saveptr
);
381 i_newpid
= strtoul(tok
, NULL
, 0);
382 p_config
->pi_confpids
[i
] = i_newpid
;
384 p_config
->b_do_remap
= true;
386 else if ( IS_OPTION("newsid=") )
387 p_config
->i_new_sid
= strtol( ARG_OPTION("newsid="), NULL
, 0 );
389 msg_Warn( NULL
, "unrecognized option %s", psz_string
);
395 if (psz_network_name
!= NULL
)
396 config_strdvb( &p_config
->network_name
, psz_network_name
, psz_charset
);
397 if (psz_service_name
!= NULL
)
398 config_strdvb( &p_config
->service_name
, psz_service_name
, psz_charset
);
399 if (psz_provider_name
!= NULL
)
400 config_strdvb( &p_config
->provider_name
, psz_provider_name
,
404 i_mtu
= p_config
->i_family
== AF_INET6
? DEFAULT_IPV6_MTU
:
407 if ( !p_config
->i_mtu
)
408 p_config
->i_mtu
= i_mtu
;
409 else if ( p_config
->i_mtu
< TS_SIZE
+ RTP_HEADER_SIZE
)
411 msg_Warn( NULL
, "invalid MTU %d, setting %d", p_config
->i_mtu
, i_mtu
);
412 p_config
->i_mtu
= i_mtu
;
418 static void config_Print( output_config_t
*p_config
)
420 if ( p_config
->b_passthrough
)
422 msg_Dbg( NULL
, "conf: %s config=0x%"PRIx64
" sid=*",
423 p_config
->psz_displayname
, p_config
->i_config
);
427 const char *psz_base
= "conf: %s config=0x%"PRIx64
" sid=%hu pids[%d]=";
428 size_t i_len
= strlen(psz_base
) + 6 * p_config
->i_nb_pids
+ 1;
429 char psz_format
[i_len
];
430 int i
, j
= strlen(psz_base
);
432 strcpy( psz_format
, psz_base
);
433 for ( i
= 0; i
< p_config
->i_nb_pids
; i
++ )
434 j
+= sprintf( psz_format
+ j
, "%u,", p_config
->pi_pids
[i
] );
435 psz_format
[j
- 1] = '\0';
437 msg_Dbg( NULL
, psz_format
, p_config
->psz_displayname
, p_config
->i_config
,
438 p_config
->i_sid
, p_config
->i_nb_pids
);
441 void config_ReadFile(void)
447 if ( psz_conf_file
== NULL
)
449 msg_Err( NULL
, "no config file" );
453 if ( (p_file
= fopen( psz_conf_file
, "r" )) == NULL
)
455 msg_Err( NULL
, "can't fopen config file %s", psz_conf_file
);
459 while ( fgets( psz_line
, sizeof(psz_line
), p_file
) != NULL
)
461 output_config_t config
;
463 char *psz_token
, *psz_parser
;
465 psz_parser
= strchr( psz_line
, '#' );
466 if ( psz_parser
!= NULL
)
467 *psz_parser
-- = '\0';
468 while ( psz_parser
>= psz_line
&& isblank( *psz_parser
) )
469 *psz_parser
-- = '\0';
470 if ( psz_line
[0] == '\0' )
473 config_Defaults( &config
);
475 psz_token
= strtok_r( psz_line
, "\t\n ", &psz_parser
);
476 if ( psz_token
== NULL
|| !config_ParseHost( &config
, psz_token
))
478 config_Free( &config
);
482 psz_token
= strtok_r( NULL
, "\t\n ", &psz_parser
);
483 if ( psz_token
== NULL
)
485 config_Free( &config
);
488 if( atoi( psz_token
) == 1 )
489 config
.i_config
|= OUTPUT_WATCH
;
491 config
.i_config
&= ~OUTPUT_WATCH
;
493 psz_token
= strtok_r( NULL
, "\t\n ", &psz_parser
);
494 if ( psz_token
== NULL
)
496 config_Free( &config
);
500 if ( psz_token
[0] == '*' )
502 config
.b_passthrough
= true;
506 config
.i_sid
= strtol(psz_token
, NULL
, 0);
508 psz_token
= strtok_r( NULL
, "\t\n ", &psz_parser
);
509 if ( psz_token
!= NULL
)
514 psz_token
= strtok_r( psz_token
, ",", &psz_parser
);
515 if ( psz_token
== NULL
)
517 config
.pi_pids
= realloc( config
.pi_pids
,
518 (config
.i_nb_pids
+ 1) * sizeof(uint16_t) );
519 config
.pi_pids
[config
.i_nb_pids
++] = strtol(psz_token
, NULL
, 0);
525 config_Print( &config
);
527 p_output
= output_Find( &config
);
529 if ( p_output
== NULL
)
530 p_output
= output_Create( &config
);
532 if ( p_output
!= NULL
)
534 free( p_output
->config
.psz_displayname
);
535 p_output
->config
.psz_displayname
= strdup( config
.psz_displayname
);
537 config
.i_config
|= OUTPUT_VALID
| OUTPUT_STILL_PRESENT
;
538 output_Change( p_output
, &config
);
539 demux_Change( p_output
, &config
);
542 config_Free( &config
);
547 for ( i
= 0; i
< i_nb_outputs
; i
++ )
549 output_t
*p_output
= pp_outputs
[i
];
550 output_config_t config
;
552 config_Init( &config
);
554 if ( (p_output
->config
.i_config
& OUTPUT_VALID
) &&
555 !(p_output
->config
.i_config
& OUTPUT_STILL_PRESENT
) )
557 msg_Dbg( NULL
, "closing %s", p_output
->config
.psz_displayname
);
558 demux_Change( p_output
, &config
);
559 output_Close( p_output
);
562 p_output
->config
.i_config
&= ~OUTPUT_STILL_PRESENT
;
563 config_Free( &config
);
567 /*****************************************************************************
569 *****************************************************************************/
570 static void signal_watcher_init(struct ev_signal
*w
, struct ev_loop
*loop
,
571 void (*cb
)(struct ev_loop
*, struct ev_signal
*, int),
574 ev_signal_init(w
, cb
, signum
);
575 ev_signal_start(loop
, w
);
579 static void sighandler(struct ev_loop
*loop
, struct ev_signal
*w
, int revents
)
586 msg_Info( NULL
, "Shutdown was requested." );
587 ev_break(loop
, EVBREAK_ALL
);
591 msg_Info( NULL
, "Configuration reload was requested." );
597 /*****************************************************************************
599 *****************************************************************************/
600 static void quit_cb(struct ev_loop
*loop
, struct ev_timer
*w
, int revents
)
602 ev_break(loop
, EVBREAK_ALL
);
605 /*****************************************************************************
607 *****************************************************************************/
608 static void DisplayVersion()
610 msg_Raw( NULL
, "DVBlast %s (%s)", VERSION
, VERSION_EXTRA
);
613 /*****************************************************************************
615 *****************************************************************************/
619 msg_Raw( NULL
, "Usage: dvblast [-q] [-c <config file>] [-r <remote socket>] [-t <ttl>] [-o <SSRC IP>] "
620 "[-i <RT priority>] "
621 #ifdef HAVE_ASI_SUPPORT
624 #ifdef HAVE_DVB_SUPPORT
625 "[-a <adapter>] [-n <frontend number>] [-S <diseqc>] [-k <uncommitted port>]"
627 "[-s <symbol rate>] [-v <0|13|18>] [-p] [-b <bandwidth>] [-I <inversion>] "
628 "[-F <fec inner>] [-m <modulation] [-R <rolloff>] [-P <pilot>] [-K <fec lp>] "
629 "[-G <guard interval>] [-H <hierarchy>] [-X <transmission>] [-O <lock timeout>] "
631 "[-D [<src host>[:<src port>]@]<src mcast>[:<port>][/<opts>]*] "
632 "[-u] [-w] [-U] [-L <latency>] [-E <retention>] [-d <dest IP>[<:port>][/<opts>]*] [-3] "
633 "[-z] [-C [-e] [-M <network name>] [-N <network ID>]] [-T] [-j <system charset>] "
634 "[-W] [-Y] [-l] [-g <logger ident>] [-Z <mrtg file>] [-V] [-h] [-B <provider_name>] "
635 "[-1 <mis_id>] [-2 <size>] [-5 <DVBS|DVBS2|DVBC_ANNEX_A|DVBC_ANNEX_B|DVBT|DVBT2|ATSC|ISDBT>] -y <ca_dev_number> "
636 "[-J <DVB charset>] [-Q <quit timeout>] [-0 pid_mapping] [-x <text|xml>]"
637 "[-6 <print period>] [-7 <ES timeout>]" );
639 msg_Raw( NULL
, "Input:" );
640 #ifdef HAVE_ASI_SUPPORT
641 msg_Raw( NULL
, " -A --asi-adapter read packets from an ASI adapter (0-n)" );
643 #ifdef HAVE_DVB_SUPPORT
644 msg_Raw( NULL
, " -a --adapter read packets from a Linux-DVB adapter (typically 0-n)" );
645 msg_Raw( NULL
, " -b --bandwidth frontend bandwidth" );
647 msg_Raw( NULL
, " -D --rtp-input read packets from a multicast address instead of a DVB card" );
648 #ifdef HAVE_DVB_SUPPORT
649 msg_Raw( NULL
, " -5 --delsys delivery system" );
650 msg_Raw( NULL
, " DVBS|DVBS2|DVBC_ANNEX_A|DVBT|DVBT2|ATSC|ISDBT|DVBC_ANNEX_B(ATSC-C/QAMB) (default guessed)");
651 msg_Raw( NULL
, " -f --frequency frontend frequency" );
652 msg_Raw( NULL
, " -8 --lnb-type <type> Set LNB type')" );
653 msg_Raw( NULL
, " universal old-sky (default: universal)");
654 msg_Raw( NULL
, " -9 --dvb-plp-id <number> Switch PLP of the DVB-T2 transmission (default: 0)" );
655 msg_Raw( NULL
, " -F --fec-inner Forward Error Correction (FEC Inner)");
656 msg_Raw( NULL
, " DVB-S2 0|12|23|34|35|56|78|89|910|999 (default auto: 999)");
657 msg_Raw( NULL
, " -I --inversion Inversion (-1 auto, 0 off, 1 on)" );
658 msg_Raw( NULL
, " -m --modulation Modulation type" );
659 msg_Raw( NULL
, " DVB-C qpsk|qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
660 msg_Raw( NULL
, " DVB-T qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
661 msg_Raw( NULL
, " DVB-S2 qpsk|psk_8|apsk_16|apsk_32 (default legacy DVB-S)" );
662 msg_Raw( NULL
, " -n --frontend-number <frontend number>" );
663 msg_Raw( NULL
, " -p --force-pulse force 22kHz pulses for high-band selection (DVB-S)" );
664 msg_Raw( NULL
, " -P --pilot DVB-S2 Pilot (-1 auto, 0 off, 1 on)" );
665 msg_Raw( NULL
, " -R --rolloff DVB-S2 Rolloff value" );
666 msg_Raw( NULL
, " DVB-S2 35=0.35|25=0.25|20=0.20|0=AUTO (default: 35)" );
667 msg_Raw( NULL
, " -1 --multistream-id Set stream ID (0-2147483648, default: 0)." );
668 msg_Raw( NULL
, " --multistream-id-pls-mode Set multistream PLS mode (ROOT, GOLD, COMBO, default: ROOT)" );
669 msg_Raw( NULL
, " --multistream-id-pls-code Set multistream PLS code (0-262143, default: 0)" );
670 msg_Raw( NULL
, " --multistream-id-is-id Set multistream IS id (0-255, default: 0)" );
671 msg_Raw( NULL
, " -K --fec-lp DVB-T low priority FEC (default auto)" );
672 msg_Raw( NULL
, " -G --guard DVB-T guard interval" );
673 msg_Raw( NULL
, " DVB-T 32 (1/32)|16 (1/16)|8 (1/8)|4 (1/4)|-1 (auto, default)" );
674 msg_Raw( NULL
, " -H --hierarchy DVB-T hierarchy (0, 1, 2, 4 or -1 auto, default)" );
675 msg_Raw( NULL
, " -X --transmission DVB-T transmission (2, 4, 8 or -1 auto, default)" );
676 msg_Raw( NULL
, " -s --symbol-rate" );
677 msg_Raw( NULL
, " -S --diseqc satellite number for diseqc (0: no diseqc, 1-4, A or B)" );
678 msg_Raw( NULL
, " -k --uncommitted port number for uncommitted DiSEqC switch (0: no uncommitted DiSEqC switch, 1-16)" );
679 msg_Raw( NULL
, " -u --budget-mode turn on budget mode (no hardware PID filtering)" );
680 msg_Raw( NULL
, " -v --voltage voltage to apply to the LNB (QPSK)" );
681 msg_Raw( NULL
, " -w --select-pmts set a PID filter on all PMTs (auto on, when config file is used)" );
682 msg_Raw( NULL
, " -O --lock-timeout timeout for the lock operation (in ms)" );
683 msg_Raw( NULL
, " -y --ca-number <ca_device_number>" );
684 msg_Raw( NULL
, " -2 --dvr-buf-size <size> set the size of the DVR TS buffer in bytes (default: %d)", i_dvr_buffer_size
);
687 msg_Raw( NULL
, "Output:" );
688 msg_Raw( NULL
, " -c --config-file <config file>" );
689 msg_Raw( NULL
, " -C --dvb-compliance pass through or build the mandatory DVB tables" );
690 msg_Raw( NULL
, " -d --duplicate duplicate all received packets to a given destination" );
691 msg_Raw( NULL
, " -3 --passthrough duplicate all received packets to stdout" );
692 msg_Raw( NULL
, " -W --emm-passthrough pass through EMM data (CA system data)" );
693 msg_Raw( NULL
, " -Y --ecm-passthrough pass through ECM data (CA program data)" );
694 msg_Raw( NULL
, " -e --epg-passthrough pass through DVB EIT schedule tables" );
695 msg_Raw( NULL
, " -E --retention maximum retention allowed between input and output (default: 40 ms)" );
696 msg_Raw( NULL
, " -L --latency maximum latency allowed between input and output (default: 100 ms)" );
697 msg_Raw( NULL
, " -M --network-name DVB network name to declare in the NIT" );
698 msg_Raw( NULL
, " -N --network-id DVB network ID to declare in the NIT" );
699 msg_Raw( NULL
, " -B --provider-name Service provider name to declare in the SDT" );
700 msg_Raw( NULL
, " -o --rtp-output <SSRC IP>" );
701 msg_Raw( NULL
, " -t --ttl <ttl> TTL of the output stream" );
702 msg_Raw( NULL
, " -T --unique-ts-id generate random unique TS ID for each output" );
703 msg_Raw( NULL
, " -U --udp use raw UDP rather than RTP (required by some IPTV set top boxes)" );
704 msg_Raw( NULL
, " -z --any-type pass through all ESs from the PMT, of any type" );
705 msg_Raw( NULL
, " -0 --pidmap <pmt_pid,audio_pid,video_pid,spu_pid>");
707 msg_Raw( NULL
, "Misc:" );
708 msg_Raw( NULL
, " -h --help display this full help" );
709 msg_Raw( NULL
, " -i --priority <RT priority>" );
710 msg_Raw( NULL
, " -j --system-charset character set used for printing messages (default UTF-8//IGNORE)" );
711 msg_Raw( NULL
, " -J --dvb-charset character set used in output DVB tables (default UTF-8//IGNORE)" );
712 msg_Raw( NULL
, " -l --logger use syslog for logging messages instead of stderr" );
713 msg_Raw( NULL
, " -g --logger-ident program name that will be used in syslog messages" );
714 msg_Raw( NULL
, " -x --print print interesting events on stdout in a given format" );
715 msg_Raw( NULL
, " -q --quiet be quiet (less verbosity, repeat or use number for even quieter)" );
716 msg_Raw( NULL
, " -Q --quit-timeout when locked, quit after this delay (in ms), or after the first lock timeout" );
717 msg_Raw( NULL
, " -6 --print-period periodicity at which we print bitrate and errors (in ms)" );
718 msg_Raw( NULL
, " -7 --es-timeout time of inactivy before which a PID is reported down (in ms)" );
719 msg_Raw( NULL
, " -r --remote-socket <remote socket>" );
720 msg_Raw( NULL
, " -Z --mrtg-file <file> Log input packets and errors into mrtg-file" );
721 msg_Raw( NULL
, " -V --version only display the version" );
725 int main( int i_argc
, char **pp_argv
)
727 const char *psz_network_name
= "DVBlast - videolan.org";
728 const char *psz_provider_name
= NULL
;
729 char *psz_dup_config
= NULL
;
730 struct sched_param param
;
733 int b_enable_syslog
= 0;
734 struct ev_signal sigint_watcher
, sigterm_watcher
, sighup_watcher
;
735 struct ev_timer quit_watcher
;
743 * The only short options left are: 4
746 static const struct option long_options
[] =
748 { "config-file", required_argument
, NULL
, 'c' },
749 { "remote-socket", required_argument
, NULL
, 'r' },
750 { "ttl", required_argument
, NULL
, 't' },
751 { "rtp-output", required_argument
, NULL
, 'o' },
752 { "priority", required_argument
, NULL
, 'i' },
753 { "adapter", required_argument
, NULL
, 'a' },
754 { "frontend-number", required_argument
, NULL
, 'n' },
755 { "delsys", required_argument
, NULL
, '5' },
756 { "dvb-plp-id", required_argument
, NULL
, '9' },
757 { "frequency", required_argument
, NULL
, 'f' },
758 { "lnb-type", required_argument
, NULL
, '8' },
759 { "fec-inner", required_argument
, NULL
, 'F' },
760 { "rolloff", required_argument
, NULL
, 'R' },
761 { "symbol-rate", required_argument
, NULL
, 's' },
762 { "diseqc", required_argument
, NULL
, 'S' },
763 { "uncommitted", required_argument
, NULL
, 'k' },
764 { "voltage", required_argument
, NULL
, 'v' },
765 { "force-pulse", no_argument
, NULL
, 'p' },
766 { "bandwidth", required_argument
, NULL
, 'b' },
767 { "inversion", required_argument
, NULL
, 'I' },
768 { "modulation", required_argument
, NULL
, 'm' },
769 { "pilot", required_argument
, NULL
, 'P' },
770 { "multistream-id", required_argument
, NULL
, '1' },
771 { "multistream-id-pls-mode", required_argument
, NULL
, 0x100001 },
772 { "multistream-id-pls-code", required_argument
, NULL
, 0x100002 },
773 { "multistream-id-is-id" , required_argument
, NULL
, 0x100003 },
774 { "fec-lp", required_argument
, NULL
, 'K' },
775 { "guard", required_argument
, NULL
, 'G' },
776 { "hierarchy", required_argument
, NULL
, 'H' },
777 { "transmission", required_argument
, NULL
, 'X' },
778 { "lock-timeout", required_argument
, NULL
, 'O' },
779 { "budget-mode", no_argument
, NULL
, 'u' },
780 { "select-pmts", no_argument
, NULL
, 'w' },
781 { "udp", no_argument
, NULL
, 'U' },
782 { "unique-ts-id", no_argument
, NULL
, 'T' },
783 { "latency", required_argument
, NULL
, 'L' },
784 { "retention", required_argument
, NULL
, 'E' },
785 { "duplicate", required_argument
, NULL
, 'd' },
786 { "passthrough", no_argument
, NULL
, '3' },
787 { "rtp-input", required_argument
, NULL
, 'D' },
788 { "asi-adapter", required_argument
, NULL
, 'A' },
789 { "any-type", no_argument
, NULL
, 'z' },
790 { "dvb-compliance", no_argument
, NULL
, 'C' },
791 { "emm-passthrough", no_argument
, NULL
, 'W' },
792 { "ecm-passthrough", no_argument
, NULL
, 'Y' },
793 { "epg-passthrough", no_argument
, NULL
, 'e' },
794 { "network-name", no_argument
, NULL
, 'M' },
795 { "network-id", no_argument
, NULL
, 'N' },
796 { "system-charset", required_argument
, NULL
, 'j' },
797 { "dvb-charset", required_argument
, NULL
, 'J' },
798 { "provider-name", required_argument
, NULL
, 'B' },
799 { "logger", no_argument
, NULL
, 'l' },
800 { "logger-ident", required_argument
, NULL
, 'g' },
801 { "print", required_argument
, NULL
, 'x' },
802 { "quit-timeout", required_argument
, NULL
, 'Q' },
803 { "print-period", required_argument
, NULL
, '6' },
804 { "es-timeout", required_argument
, NULL
, '7' },
805 { "quiet", no_argument
, NULL
, 'q' },
806 { "help", no_argument
, NULL
, 'h' },
807 { "version", no_argument
, NULL
, 'V' },
808 { "mrtg-file", required_argument
, NULL
, 'Z' },
809 { "ca-number", required_argument
, NULL
, 'y' },
810 { "pidmap", required_argument
, NULL
, '0' },
811 { "dvr-buf-size", required_argument
, NULL
, '2' },
815 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:A:lg:zCWYeM:N:j:J:B:x:Q:6:7:hVZ:y:0:1:2:9:", long_options
, NULL
)) != -1 )
822 if ( *optarg
== 'q' ) /* e.g. -qqq */
825 while ( *optarg
== 'q' )
833 i_verbose
-= atoi( optarg
); /* e.g. -q2 */
838 i_verbose
--; /* -q */
843 psz_conf_file
= optarg
;
845 * When configuration file is used it is reasonable to assume that
846 * services may be added/removed. If b_select_pmts is not set dvblast
847 * is unable to start streaming newly added services in the config.
853 psz_srv_socket
= optarg
;
857 i_ttl_global
= strtol( optarg
, NULL
, 0 );
862 struct in_addr maddr
;
863 if ( !inet_aton( optarg
, &maddr
) )
865 memcpy( pi_ssrc_global
, &maddr
.s_addr
, 4 * sizeof(uint8_t) );
870 i_priority
= strtol( optarg
, NULL
, 0 );
874 i_adapter
= strtol( optarg
, NULL
, 0 );
878 i_fenum
= strtol( optarg
, NULL
, 0 );
882 i_canum
= strtol( optarg
, NULL
, 0 );
889 dvb_plp_id
= strtol( optarg
, NULL
, 0 );
892 if (optarg
&& optarg
[0] != '-')
893 i_frequency
= strtol( optarg
, NULL
, 0 );
894 if ( pf_Open
!= NULL
)
896 #ifdef HAVE_DVB_SUPPORT
898 pf_Reset
= dvb_Reset
;
899 pf_SetFilter
= dvb_SetFilter
;
900 pf_UnsetFilter
= dvb_UnsetFilter
;
902 msg_Err( NULL
, "DVBlast is compiled without DVB support.");
908 psz_lnb_type
= optarg
;
912 i_fec
= strtol( optarg
, NULL
, 0 );
916 i_rolloff
= strtol( optarg
, NULL
, 0 );
920 i_srate
= strtol( optarg
, NULL
, 0 );
924 i_satnum
= strtol( optarg
, NULL
, 16 );
928 i_uncommitted
= strtol( optarg
, NULL
, 10 );
932 i_voltage
= strtol( optarg
, NULL
, 0 );
940 i_bandwidth
= strtol( optarg
, NULL
, 0 );
944 i_inversion
= strtol( optarg
, NULL
, 0 );
948 psz_modulation
= optarg
;
952 i_pilot
= strtol( optarg
, NULL
, 0 );
956 i_mis
= strtol( optarg
, NULL
, 0 );
959 case 0x100001: // --multistream-id-pls-mode
960 psz_mis_pls_mode
= optarg
;
961 if ( streq( psz_mis_pls_mode
, "ROOT" ) ) {
963 } else if ( streq( psz_mis_pls_mode
, "GOLD" ) ) {
965 } else if ( streq( psz_mis_pls_mode
, "COMBO" ) ) {
968 msg_Err(NULL
, "Invalid --multistream-id-pls-mode '%s', valid options are: ROOT GOLD COMBO", optarg
);
973 case 0x100002: // --multistream-id-pls-code
974 i_mis_pls_code
= strtol( optarg
, NULL
, 0 );
975 if ( i_mis_pls_code
< 0 || i_mis_pls_code
> 262143 ) {
976 msg_Err(NULL
, "ERROR: Invalid --multistream-id-pls-code '%s', valid options are: 0-262143", optarg
);
981 case 0x100003: // --multistream-id-is-id
982 i_mis_is_id
= strtol( optarg
, NULL
, 0 );
983 if ( i_mis_is_id
< 0 || i_mis_is_id
> 255 ) {
984 msg_Err(NULL
, "ERROR: Invalid --multistream-id-is-id '%s', valid options are: 0-255", optarg
);
990 i_fec_lp
= strtol( optarg
, NULL
, 0 );
994 i_guard
= strtol( optarg
, NULL
, 0 );
998 i_transmission
= strtol( optarg
, NULL
, 0 );
1002 i_frontend_timeout_duration
= strtoll( optarg
, NULL
, 0 ) * 1000;
1006 i_hierarchy
= strtol( optarg
, NULL
, 0 );
1014 b_select_pmts
= !b_select_pmts
;
1018 b_udp_global
= true;
1022 i_latency_global
= strtoll( optarg
, NULL
, 0 ) * 1000;
1026 i_retention_global
= strtoll( optarg
, NULL
, 0 ) * 1000;
1030 psz_dup_config
= optarg
;
1034 b_passthrough
= true;
1039 psz_udp_src
= optarg
;
1040 if ( pf_Open
!= NULL
)
1043 pf_Reset
= udp_Reset
;
1044 pf_SetFilter
= udp_SetFilter
;
1045 pf_UnsetFilter
= udp_UnsetFilter
;
1049 #ifdef HAVE_ASI_SUPPORT
1050 if ( pf_Open
!= NULL
)
1052 if ( strncmp(optarg
, "deltacast:", 10) == 0)
1054 #ifdef HAVE_ASI_DELTACAST_SUPPORT
1055 i_asi_adapter
= strtol( optarg
+10, NULL
, 0 );
1056 pf_Open
= asi_deltacast_Open
;
1057 pf_Reset
= asi_deltacast_Reset
;
1058 pf_SetFilter
= asi_deltacast_SetFilter
;
1059 pf_UnsetFilter
= asi_deltacast_UnsetFilter
;
1061 msg_Err( NULL
, "DVBlast is compiled without Deltacast ASI support.");
1067 i_asi_adapter
= strtol( optarg
, NULL
, 0 );
1069 pf_Reset
= asi_Reset
;
1070 pf_SetFilter
= asi_SetFilter
;
1071 pf_UnsetFilter
= asi_UnsetFilter
;
1074 msg_Err( NULL
, "DVBlast is compiled without ASI support.");
1084 b_dvb_global
= true;
1088 b_enable_emm
= true;
1092 b_enable_ecm
= true;
1096 b_epg_global
= true;
1100 psz_network_name
= optarg
;
1104 i_network_id
= strtoul( optarg
, NULL
, 0 );
1112 psz_native_charset
= optarg
;
1116 psz_dvb_charset
= optarg
;
1120 psz_provider_name
= optarg
;
1124 b_enable_syslog
= 1;
1128 psz_syslog_ident
= optarg
;
1132 b_print_enabled
= true;
1133 if ( !strcmp(optarg
, "text") )
1134 i_print_type
= PRINT_TEXT
;
1135 else if ( !strcmp(optarg
, "xml") )
1136 i_print_type
= PRINT_XML
;
1139 b_print_enabled
= false;
1140 msg_Warn( NULL
, "unrecognized print type %s", optarg
);
1145 i_quit_timeout_duration
= strtoll( optarg
, NULL
, 0 ) * 1000;
1149 i_print_period
= strtoll( optarg
, NULL
, 0 ) * 1000;
1153 i_es_timeout
= strtoll( optarg
, NULL
, 0 ) * 1000;
1162 psz_mrtg_file
= optarg
;
1166 /* We expect a comma separated list of numbers.
1167 Put them into the pi_newpids array as they appear */
1169 char *saveptr
= NULL
;
1172 for (i
= 0, str1
= optarg
; i
< N_MAP_PIDS
; i
++, str1
= NULL
)
1174 tok
= strtok_r(str1
, ",", &saveptr
);
1177 i_newpid
= strtoul(tok
, NULL
, 0);
1179 msg_Err( NULL
, "Invalid pidmap string" );
1182 pi_newpids
[i
] = i_newpid
;
1187 #ifdef HAVE_DVB_SUPPORT
1189 i_dvr_buffer_size
= strtol( optarg
, NULL
, 0 );
1190 if (!i_dvr_buffer_size
)
1191 usage(); // it exits
1192 /* roundup to packet size */
1193 i_dvr_buffer_size
+= TS_SIZE
- 1;
1194 i_dvr_buffer_size
/= TS_SIZE
;
1195 i_dvr_buffer_size
*= TS_SIZE
;
1203 if ( optind
< i_argc
|| pf_Open
== NULL
)
1206 if ( b_enable_syslog
)
1207 msg_Connect( psz_syslog_ident
? psz_syslog_ident
: pp_argv
[0] );
1209 if ( b_print_enabled
)
1211 /* Make std* line-buffered */
1212 setvbuf(print_fh
, NULL
, _IOLBF
, 0);
1218 msg_Warn( NULL
, "restarting" );
1220 switch (i_print_type
)
1223 fprintf(print_fh
, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1224 fprintf(print_fh
, "<TS>\n");
1232 msg_Warn( NULL
, "raw UDP output is deprecated. Please consider using RTP." );
1233 msg_Warn( NULL
, "for DVB-IP compliance you should use RTP." );
1236 if ( b_epg_global
&& !b_dvb_global
)
1238 msg_Dbg( NULL
, "turning on DVB compliance, required by EPG information" );
1239 b_dvb_global
= true;
1242 if ((event_loop
= ev_default_loop(0)) == NULL
)
1244 msg_Err( NULL
, "unable to initialize libev" );
1248 memset( &output_dup
, 0, sizeof(output_dup
) );
1249 if ( psz_dup_config
!= NULL
)
1251 output_config_t config
;
1253 config_Defaults( &config
);
1254 if ( !config_ParseHost( &config
, psz_dup_config
) )
1255 msg_Err( NULL
, "Invalid target address for -d switch" );
1258 output_Init( &output_dup
, &config
);
1259 output_Change( &output_dup
, &config
);
1262 config_Free( &config
);
1265 config_strdvb( &network_name
, psz_network_name
, psz_dvb_charset
);
1266 config_strdvb( &provider_name
, psz_provider_name
, psz_dvb_charset
);
1268 /* Set signal handlers */
1269 signal_watcher_init(&sigint_watcher
, event_loop
, sighandler
, SIGINT
);
1270 signal_watcher_init(&sigterm_watcher
, event_loop
, sighandler
, SIGTERM
);
1271 signal_watcher_init(&sighup_watcher
, event_loop
, sighandler
, SIGHUP
);
1273 srand( time(NULL
) * getpid() );
1275 if ( i_mis_pls_mode
|| i_mis_pls_code
|| i_mis_is_id
)
1277 i_mis
= calc_multistream_id( i_mis_pls_mode
, i_mis_pls_code
, i_mis_is_id
);
1278 msg_Info( NULL
, "Calculating multistream-id using pls-mode: %s (%d) pls-code: %d is-id: %d. Resulting multistream-id: %d (0x%x)",
1279 psz_mis_pls_mode
, i_mis_pls_mode
, i_mis_pls_code
, i_mis_is_id
, i_mis
, i_mis
);
1283 i_mis_pls_mode
= (i_mis
>> 26) & 0x03;
1284 i_mis_pls_code
= (i_mis
>> 8) & 0x3ffff;
1285 i_mis_is_id
= i_mis
& 0xff;
1287 i_mis_pls_mode
== 0 ? "ROOT" :
1288 i_mis_pls_mode
== 1 ? "GOLD" :
1289 i_mis_pls_mode
== 2 ? "COMBO" : "UNKNOWN";
1291 msg_Info( NULL
, "Calculated multistream pls-mode: %s (%d) pls-code: %d is-id: %d from multistream-id: %d (0x%x)",
1292 psz_mis_pls_mode
, i_mis_pls_mode
, i_mis_pls_code
, i_mis_is_id
, i_mis
, i_mis
);
1297 // init the mrtg logfile
1298 mrtgInit(psz_mrtg_file
);
1300 if ( i_priority
> 0 )
1302 memset( ¶m
, 0, sizeof(struct sched_param
) );
1303 param
.sched_priority
= i_priority
;
1304 if ( (i_error
= pthread_setschedparam( pthread_self(), SCHED_RR
,
1307 msg_Warn( NULL
, "couldn't set thread priority: %s",
1308 strerror(i_error
) );
1314 if ( psz_srv_socket
!= NULL
)
1317 if ( i_quit_timeout_duration
)
1319 ev_timer_init(&quit_watcher
, quit_cb
,
1320 i_quit_timeout_duration
/ 1000000., 0);
1321 ev_timer_start(event_loop
, &quit_watcher
);
1326 ev_run(event_loop
, 0);
1329 outputs_Close( i_nb_outputs
);
1331 dvb_string_clean( &network_name
);
1332 dvb_string_clean( &provider_name
);
1333 if ( conf_iconv
!= (iconv_t
)-1 )
1334 iconv_close( conf_iconv
);
1336 switch (i_print_type
)
1339 fprintf(print_fh
, "</TS>\n");
1345 if ( b_enable_syslog
)
1350 ev_loop_destroy(event_loop
);
1352 return EXIT_SUCCESS
;