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>
52 /*****************************************************************************
54 *****************************************************************************/
55 struct ev_loop
*event_loop
;
56 output_t
**pp_outputs
= NULL
;
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;
66 char *psz_delsys
= NULL
;
68 char *psz_lnb_type
= "universal";
71 int i_srate
= 27500000;
75 int i_uncommitted
= 0;
79 char *psz_modulation
= NULL
;
82 char *psz_mis_pls_mode
= "ROOT";
83 int i_mis_pls_mode
= 0;
84 int i_mis_pls_code
= 0;
88 int i_transmission
= -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;
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;
101 mtime_t i_print_period
= 0;
102 mtime_t i_es_timeout
= 0;
104 int i_verbose
= DEFAULT_VERBOSITY
;
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
;
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;
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
)
189 if ( !psz_string
|| strlen( psz_string
) == 0 )
191 ret
= tmp
= strdup( psz_string
);
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
;
216 return (uint8_t *)psz_input
;
218 if ( !strcasecmp( psz_native_charset
, psz_charset
) )
219 return (uint8_t *)psz_input
;
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
);
235 if ( iconv( conf_iconv
, &psz_tmp
, &i_input
, &p
, &i_available
) == (size_t)-1 )
239 return (uint8_t *)psz_input
;
243 *pi_length
= i_output
- i_available
;
244 return (uint8_t *)p_output
;
247 "unable to convert from %s to %s (iconv is not available)",
248 psz_native_charset
, psz_charset
);
249 return (uint8_t *)psz_input
;
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
);
261 dvb_string_clean(p_dvb_string
);
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
,
270 static bool config_ParseHost( output_config_t
*p_config
, char *psz_string
)
272 struct addrinfo
*p_ai
;
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
== '@' )
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" );
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="),
321 else if ( IS_OPTION("latency=") )
322 p_config
->i_output_latency
= strtoll( ARG_OPTION("latency="),
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");
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=") )
364 char *saveptr
= NULL
;
367 for (i
= 0, str1
= config_stropt( (ARG_OPTION("pidmap="))); i
< N_MAP_PIDS
; i
++, str1
= NULL
)
369 tok
= strtok_r(str1
, ",", &saveptr
);
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 );
380 msg_Warn( NULL
, "unrecognized option %s", psz_string
);
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
,
395 i_mtu
= p_config
->i_family
== AF_INET6
? DEFAULT_IPV6_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
;
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
);
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)
438 if ( psz_conf_file
== NULL
)
440 msg_Err( NULL
, "no config file" );
444 if ( (p_file
= fopen( psz_conf_file
, "r" )) == NULL
)
446 msg_Err( NULL
, "can't fopen config file %s", psz_conf_file
);
450 while ( fgets( psz_line
, sizeof(psz_line
), p_file
) != NULL
)
452 output_config_t config
;
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' )
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
);
473 psz_token
= strtok_r( NULL
, "\t\n ", &psz_parser
);
474 if ( psz_token
== NULL
)
476 config_Free( &config
);
479 if( atoi( psz_token
) == 1 )
480 config
.i_config
|= OUTPUT_WATCH
;
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
);
491 if ( psz_token
[0] == '*' )
493 config
.b_passthrough
= true;
497 config
.i_sid
= strtol(psz_token
, NULL
, 0);
499 psz_token
= strtok_r( NULL
, "\t\n ", &psz_parser
);
500 if ( psz_token
!= NULL
)
505 psz_token
= strtok_r( psz_token
, ",", &psz_parser
);
506 if ( psz_token
== NULL
)
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);
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
);
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 /*****************************************************************************
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),
565 ev_signal_init(w
, cb
, signum
);
566 ev_signal_start(loop
, w
);
570 static void sighandler(struct ev_loop
*loop
, struct ev_signal
*w
, int revents
)
577 msg_Info( NULL
, "Shutdown was requested." );
578 ev_break(loop
, EVBREAK_ALL
);
582 msg_Info( NULL
, "Configuration reload was requested." );
588 /*****************************************************************************
590 *****************************************************************************/
591 static void quit_cb(struct ev_loop
*loop
, struct ev_timer
*w
, int revents
)
593 ev_break(loop
, EVBREAK_ALL
);
596 /*****************************************************************************
598 *****************************************************************************/
599 static void DisplayVersion()
601 msg_Raw( NULL
, "DVBlast %s (%s)", VERSION
, VERSION_EXTRA
);
604 /*****************************************************************************
606 *****************************************************************************/
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>]"
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>] "
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" );
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
);
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" );
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
;
717 int b_enable_syslog
= 0;
718 struct ev_signal sigint_watcher
, sigterm_watcher
, sighup_watcher
;
719 struct ev_timer quit_watcher
;
727 * The only short options left are: 4
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' },
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 )
804 if ( *optarg
== 'q' ) /* e.g. -qqq */
807 while ( *optarg
== 'q' )
815 i_verbose
-= atoi( optarg
); /* e.g. -q2 */
820 i_verbose
--; /* -q */
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.
835 psz_srv_socket
= optarg
;
839 i_ttl_global
= strtol( optarg
, NULL
, 0 );
844 struct in_addr maddr
;
845 if ( !inet_aton( optarg
, &maddr
) )
847 memcpy( pi_ssrc_global
, &maddr
.s_addr
, 4 * sizeof(uint8_t) );
852 i_priority
= strtol( optarg
, NULL
, 0 );
856 i_adapter
= strtol( optarg
, NULL
, 0 );
860 i_fenum
= strtol( optarg
, NULL
, 0 );
864 i_canum
= strtol( optarg
, NULL
, 0 );
871 dvb_plp_id
= strtol( optarg
, NULL
, 0 );
874 if (optarg
&& optarg
[0] != '-')
875 i_frequency
= strtol( optarg
, NULL
, 0 );
876 if ( pf_Open
!= NULL
)
878 #ifdef HAVE_DVB_SUPPORT
880 pf_Reset
= dvb_Reset
;
881 pf_SetFilter
= dvb_SetFilter
;
882 pf_UnsetFilter
= dvb_UnsetFilter
;
884 msg_Err( NULL
, "DVBlast is compiled without DVB support.");
890 psz_lnb_type
= optarg
;
894 i_fec
= strtol( optarg
, NULL
, 0 );
898 i_rolloff
= strtol( optarg
, NULL
, 0 );
902 i_srate
= strtol( optarg
, NULL
, 0 );
906 i_satnum
= strtol( optarg
, NULL
, 16 );
910 i_uncommitted
= strtol( optarg
, NULL
, 10 );
914 i_voltage
= strtol( optarg
, NULL
, 0 );
922 i_bandwidth
= strtol( optarg
, NULL
, 0 );
926 i_inversion
= strtol( optarg
, NULL
, 0 );
930 psz_modulation
= optarg
;
934 i_pilot
= strtol( optarg
, NULL
, 0 );
938 i_mis
= strtol( optarg
, NULL
, 0 );
941 case 0x100001: // --multistream-id-pls-mode
942 psz_mis_pls_mode
= optarg
;
943 if ( streq( psz_mis_pls_mode
, "ROOT" ) ) {
945 } else if ( streq( psz_mis_pls_mode
, "GOLD" ) ) {
947 } else if ( streq( psz_mis_pls_mode
, "COMBO" ) ) {
950 msg_Err(NULL
, "Invalid --multistream-id-pls-mode '%s', valid options are: ROOT GOLD COMBO", optarg
);
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
);
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
);
972 i_fec_lp
= strtol( optarg
, NULL
, 0 );
976 i_guard
= strtol( optarg
, NULL
, 0 );
980 i_transmission
= strtol( optarg
, NULL
, 0 );
984 i_frontend_timeout_duration
= strtoll( optarg
, NULL
, 0 ) * 1000;
988 i_hierarchy
= strtol( optarg
, NULL
, 0 );
996 b_select_pmts
= !b_select_pmts
;
1000 b_udp_global
= true;
1004 i_latency_global
= strtoll( optarg
, NULL
, 0 ) * 1000;
1008 i_retention_global
= strtoll( optarg
, NULL
, 0 ) * 1000;
1012 psz_dup_config
= optarg
;
1016 b_passthrough
= true;
1021 psz_udp_src
= optarg
;
1022 if ( pf_Open
!= NULL
)
1025 pf_Reset
= udp_Reset
;
1026 pf_SetFilter
= udp_SetFilter
;
1027 pf_UnsetFilter
= udp_UnsetFilter
;
1035 b_dvb_global
= true;
1039 b_epg_global
= true;
1043 psz_network_name
= optarg
;
1047 i_network_id
= strtoul( optarg
, NULL
, 0 );
1055 psz_native_charset
= optarg
;
1059 psz_dvb_charset
= optarg
;
1063 psz_provider_name
= optarg
;
1067 b_enable_syslog
= 1;
1071 psz_syslog_ident
= optarg
;
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
;
1082 b_print_enabled
= false;
1083 msg_Warn( NULL
, "unrecognized print type %s", optarg
);
1088 i_quit_timeout_duration
= strtoll( optarg
, NULL
, 0 ) * 1000;
1092 i_print_period
= strtoll( optarg
, NULL
, 0 ) * 1000;
1096 i_es_timeout
= strtoll( optarg
, NULL
, 0 ) * 1000;
1105 /* We expect a comma separated list of numbers.
1106 Put them into the pi_newpids array as they appear */
1108 char *saveptr
= NULL
;
1111 for (i
= 0, str1
= optarg
; i
< N_MAP_PIDS
; i
++, str1
= NULL
)
1113 tok
= strtok_r(str1
, ",", &saveptr
);
1116 i_newpid
= strtoul(tok
, NULL
, 0);
1118 msg_Err( NULL
, "Invalid pidmap string" );
1121 pi_newpids
[i
] = i_newpid
;
1126 #ifdef HAVE_DVB_SUPPORT
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
;
1142 if ( optind
< i_argc
|| pf_Open
== NULL
)
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);
1157 msg_Warn( NULL
, "restarting" );
1159 switch (i_print_type
)
1162 fprintf(print_fh
, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1163 fprintf(print_fh
, "<TS>\n");
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" );
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" );
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
);
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;
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
);
1236 if ( i_priority
> 0 )
1238 memset( ¶m
, 0, sizeof(struct sched_param
) );
1239 param
.sched_priority
= i_priority
;
1240 if ( (i_error
= pthread_setschedparam( pthread_self(), SCHED_RR
,
1243 msg_Warn( NULL
, "couldn't set thread priority: %s",
1244 strerror(i_error
) );
1250 if ( psz_srv_socket
!= NULL
)
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
);
1262 ev_run(event_loop
, 0);
1264 outputs_Close( i_nb_outputs
);
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
)
1274 fprintf(print_fh
, "</TS>\n");
1280 if ( b_enable_syslog
)
1285 ev_loop_destroy(event_loop
);
1287 return EXIT_SUCCESS
;