Commit 614d9b45 authored by Christophe Massiot's avatar Christophe Massiot

add option to shift segment start

parent 2240f942
...@@ -5,6 +5,7 @@ Changes between 2.1 and 2.2: ...@@ -5,6 +5,7 @@ Changes between 2.1 and 2.2:
* Various portability fixes * Various portability fixes
* Fix off-by-one error in directory input * Fix off-by-one error in directory input
* Don't bail out on missing segments * Don't bail out on missing segments
* Add option to shift segment start
Changes between 2.0 and 2.1: Changes between 2.0 and 2.1:
---------------------------- ----------------------------
......
...@@ -162,6 +162,11 @@ therefore possible to pass absolute (positive) dates to -k. ...@@ -162,6 +162,11 @@ therefore possible to pass absolute (positive) dates to -k.
There is no built-in expiration of files in multicat; to avoid filling up the There is no built-in expiration of files in multicat; to avoid filling up the
partition, it is necessary to run multicat_expire.sh every hour. partition, it is necessary to run multicat_expire.sh every hour.
The duration of the segments may be specified with -r. It is also advised to
add an offset with -O (typically a per-stream random number of up to the
segment duration minus one) to avoid having all multicat processes rotate
files exactly at the same time, resulting in a surge in CPU usage and disk I/O.
Using OffseTS Using OffseTS
============= =============
......
/***************************************************************************** /*****************************************************************************
* multicat.c: netcat-equivalent for multicast * multicat.c: netcat-equivalent for multicast
***************************************************************************** *****************************************************************************
* Copyright (C) 2009, 2011-2012, 2015 VideoLAN * Copyright (C) 2009, 2011-2012, 2015-2016 VideoLAN
* $Id$ * $Id$
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
...@@ -85,6 +85,7 @@ static bool b_input_udp = false, b_output_udp = false; ...@@ -85,6 +85,7 @@ static bool b_input_udp = false, b_output_udp = false;
static size_t i_asked_payload_size = DEFAULT_PAYLOAD_SIZE; static size_t i_asked_payload_size = DEFAULT_PAYLOAD_SIZE;
static size_t i_rtp_header_size = RTP_HEADER_SIZE; static size_t i_rtp_header_size = RTP_HEADER_SIZE;
static uint64_t i_rotate_size = DEFAULT_ROTATE_SIZE; static uint64_t i_rotate_size = DEFAULT_ROTATE_SIZE;
static uint64_t i_rotate_offset = DEFAULT_ROTATE_OFFSET;
static uint64_t i_duration = 0; static uint64_t i_duration = 0;
static struct udprawpkt pktheader; static struct udprawpkt pktheader;
static bool b_raw_packets = false; static bool b_raw_packets = false;
...@@ -109,7 +110,7 @@ static void (*pf_ExitWrite)(void); ...@@ -109,7 +110,7 @@ static void (*pf_ExitWrite)(void);
static void usage(void) static void usage(void)
{ {
msg_Raw( NULL, "Usage: multicat [-i <RT priority>] [-l <syslogtag>] [-t <ttl>] [-X] [-T <file name>] [-f] [-p <PCR PID>] [-C] [-P] [-s <chunks>] [-n <chunks>] [-k <start time>] [-d <duration>] [-a] [-r <file duration>] [-S <SSRC IP>] [-u] [-U] [-m <payload size>] [-R <RTP header size>] [-w] <input item> <output item>" ); msg_Raw( NULL, "Usage: multicat [-i <RT priority>] [-l <syslogtag>] [-t <ttl>] [-X] [-T <file name>] [-f] [-p <PCR PID>] [-C] [-P] [-s <chunks>] [-n <chunks>] [-k <start time>] [-d <duration>] [-a] [-r <file duration>] [-O <rotate offset>] [-S <SSRC IP>] [-u] [-U] [-m <payload size>] [-R <RTP header size>] [-w] <input item> <output item>" );
msg_Raw( NULL, " item format: <file path | device path | FIFO path | directory path | network host>" ); msg_Raw( NULL, " item format: <file path | device path | FIFO path | directory path | network host>" );
msg_Raw( NULL, " host format: [<connect addr>[:<connect port>]][@[<bind addr][:<bind port>]]" ); msg_Raw( NULL, " host format: [<connect addr>[:<connect port>]][@[<bind addr][:<bind port>]]" );
msg_Raw( NULL, " -X: also pass-through all packets to stdout" ); msg_Raw( NULL, " -X: also pass-through all packets to stdout" );
...@@ -124,6 +125,7 @@ static void usage(void) ...@@ -124,6 +125,7 @@ static void usage(void)
msg_Raw( NULL, " -d: exit after definite time (in 27 MHz units)" ); msg_Raw( NULL, " -d: exit after definite time (in 27 MHz units)" );
msg_Raw( NULL, " -a: append to existing destination file (risky)" ); msg_Raw( NULL, " -a: append to existing destination file (risky)" );
msg_Raw( NULL, " -r: in directory mode, rotate file after this duration (default: 97200000000 ticks = 1 hour)" ); msg_Raw( NULL, " -r: in directory mode, rotate file after this duration (default: 97200000000 ticks = 1 hour)" );
msg_Raw( NULL, " -O: in directory mode, rotate file after duration + this offset (default: 0 tick = calendar hour)" );
msg_Raw( NULL, " -S: overwrite or create RTP SSRC" ); msg_Raw( NULL, " -S: overwrite or create RTP SSRC" );
msg_Raw( NULL, " -u: source has no RTP header" ); msg_Raw( NULL, " -u: source has no RTP header" );
msg_Raw( NULL, " -U: destination has no RTP header" ); msg_Raw( NULL, " -U: destination has no RTP header" );
...@@ -637,7 +639,8 @@ static ssize_t dir_Read( void *p_buf, size_t i_len ) ...@@ -637,7 +639,8 @@ static ssize_t dir_Read( void *p_buf, size_t i_len )
true, i_input_dir_len, &p_input_aux ); true, i_input_dir_len, &p_input_aux );
if ( i_input_fd > 0 ) break; if ( i_input_fd > 0 ) break;
if ( i_input_dir_file * i_rotate_size > i_first_stc + i_duration ) if ( i_input_dir_file * i_rotate_size + i_rotate_offset >
i_first_stc + i_duration )
{ {
msg_Err( NULL, "end of files reached" ); msg_Err( NULL, "end of files reached" );
b_die = 1; b_die = 1;
...@@ -695,7 +698,7 @@ static int dir_InitRead( const char *psz_arg, size_t i_len, ...@@ -695,7 +698,7 @@ static int dir_InitRead( const char *psz_arg, size_t i_len,
psz_input_dir_name = strdup( psz_arg ); psz_input_dir_name = strdup( psz_arg );
i_input_dir_len = i_len; i_input_dir_len = i_len;
i_input_dir_file = GetDirFile( i_rotate_size, i_pos ); i_input_dir_file = GetDirFile( i_rotate_size, i_rotate_offset, i_pos );
for ( ; ; ) for ( ; ; )
{ {
...@@ -704,7 +707,8 @@ static int dir_InitRead( const char *psz_arg, size_t i_len, ...@@ -704,7 +707,8 @@ static int dir_InitRead( const char *psz_arg, size_t i_len,
i_input_dir_len ); i_input_dir_len );
if ( i_nb_skipped_chunks >= 0 ) break; if ( i_nb_skipped_chunks >= 0 ) break;
if ( i_input_dir_file * i_rotate_size > i_stc + i_duration ) if ( i_input_dir_file * i_rotate_size + i_rotate_offset >
i_stc + i_duration )
{ {
msg_Err( NULL, "position not found" ); msg_Err( NULL, "position not found" );
return -1; return -1;
...@@ -734,7 +738,7 @@ static uint64_t i_output_dir_file; ...@@ -734,7 +738,7 @@ static uint64_t i_output_dir_file;
static ssize_t dir_Write( const void *p_buf, size_t i_len ) static ssize_t dir_Write( const void *p_buf, size_t i_len )
{ {
uint64_t i_dir_file = GetDirFile( i_rotate_size, i_stc ); uint64_t i_dir_file = GetDirFile( i_rotate_size, i_rotate_offset, i_stc );
if ( !i_output_fd || i_dir_file != i_output_dir_file ) if ( !i_output_fd || i_dir_file != i_output_dir_file )
{ {
if ( i_output_fd ) if ( i_output_fd )
...@@ -946,7 +950,7 @@ int main( int i_argc, char **pp_argv ) ...@@ -946,7 +950,7 @@ int main( int i_argc, char **pp_argv )
sigset_t set; sigset_t set;
/* Parse options */ /* Parse options */
while ( (c = getopt( i_argc, pp_argv, "i:l:t:XT:fp:CPs:n:k:d:ar:S:uUm:R:wh" )) != -1 ) while ( (c = getopt( i_argc, pp_argv, "i:l:t:XT:fp:CPs:n:k:d:ar:O:S:uUm:R:wh" )) != -1 )
{ {
switch ( c ) switch ( c )
{ {
...@@ -1014,6 +1018,10 @@ int main( int i_argc, char **pp_argv ) ...@@ -1014,6 +1018,10 @@ int main( int i_argc, char **pp_argv )
i_rotate_size = strtoull( optarg, NULL, 0 ); i_rotate_size = strtoull( optarg, NULL, 0 );
break; break;
case 'O':
i_rotate_offset = strtoull( optarg, NULL, 0 );
break;
case 'S': case 'S':
{ {
struct in_addr maddr; struct in_addr maddr;
......
/***************************************************************************** /*****************************************************************************
* multicat_validate.c: validate position in directory input * multicat_validate.c: validate position in directory input
***************************************************************************** *****************************************************************************
* Copyright (C) 2009, 2011, 2015 VideoLAN * Copyright (C) 2009, 2011, 2015-2016 VideoLAN
* $Id$ * $Id$
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
* Local declarations * Local declarations
*****************************************************************************/ *****************************************************************************/
static uint64_t i_rotate_size = DEFAULT_ROTATE_SIZE; static uint64_t i_rotate_size = DEFAULT_ROTATE_SIZE;
static uint64_t i_rotate_offset = DEFAULT_ROTATE_OFFSET;
static int64_t i_tolerance = DEFAULT_TOLERANCE; static int64_t i_tolerance = DEFAULT_TOLERANCE;
static size_t i_asked_payload_size = DEFAULT_PAYLOAD_SIZE; static size_t i_asked_payload_size = DEFAULT_PAYLOAD_SIZE;
static int64_t i_delay = 0; static int64_t i_delay = 0;
...@@ -50,9 +51,10 @@ static bool b_status = false; ...@@ -50,9 +51,10 @@ static bool b_status = false;
static void usage(void) static void usage(void)
{ {
msg_Raw( NULL, "Usage: multicat_validate [-l <syslogtag>] [-k <start time>] [-r <file duration>] [-W <tolerance>] [-m <payload size>] <input directory>" ); msg_Raw( NULL, "Usage: multicat_validate [-l <syslogtag>] [-k <start time>] [-r <file duration>] [-O <rotate offset>] [-W <tolerance>] [-m <payload size>] <input directory>" );
msg_Raw( NULL, " -k: start at the given position (in 27 MHz units, negative = from the end)" ); msg_Raw( NULL, " -k: start at the given position (in 27 MHz units, negative = from the end)" );
msg_Raw( NULL, " -r: in directory mode, rotate file after this duration (default: 97200000000 ticks = 1 hour)" ); msg_Raw( NULL, " -r: in directory mode, rotate file after this duration (default: 97200000000 ticks = 1 hour)" );
msg_Raw( NULL, " -O: in directory mode, rotate file after duration + this offset (default: 0 tick = calendar hour)" );
msg_Raw( NULL, " -W: maximum tolerated wait time before the forthcoming packet (by default: 27000000 ticks = 1 second)" ); msg_Raw( NULL, " -W: maximum tolerated wait time before the forthcoming packet (by default: 27000000 ticks = 1 second)" );
msg_Raw( NULL, " -m: size of the payload chunk, excluding optional RTP header (default 1316)" ); msg_Raw( NULL, " -m: size of the payload chunk, excluding optional RTP header (default 1316)" );
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
...@@ -106,7 +108,7 @@ int main( int i_argc, char **pp_argv ) ...@@ -106,7 +108,7 @@ int main( int i_argc, char **pp_argv )
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
while ( (c = getopt( i_argc, pp_argv, "l:k:r:W:m:h" )) != -1 ) while ( (c = getopt( i_argc, pp_argv, "l:k:r:O:W:m:h" )) != -1 )
{ {
switch ( c ) switch ( c )
{ {
...@@ -122,6 +124,10 @@ int main( int i_argc, char **pp_argv ) ...@@ -122,6 +124,10 @@ int main( int i_argc, char **pp_argv )
i_rotate_size = strtoull( optarg, NULL, 0 ); i_rotate_size = strtoull( optarg, NULL, 0 );
break; break;
case 'O':
i_rotate_offset = strtoull( optarg, NULL, 0 );
break;
case 'W': case 'W':
i_tolerance = strtoull( optarg, NULL, 0 ); i_tolerance = strtoull( optarg, NULL, 0 );
break; break;
...@@ -155,7 +161,7 @@ int main( int i_argc, char **pp_argv ) ...@@ -155,7 +161,7 @@ int main( int i_argc, char **pp_argv )
i_delay = real_Date() - i_stc; i_delay = real_Date() - i_stc;
} }
i_dir_file = GetDirFile( i_rotate_size, i_stc ); i_dir_file = GetDirFile( i_rotate_size, i_rotate_offset, i_stc );
i_nb_skipped_chunks = LookupDirAuxFile( psz_dir_name, i_dir_file, i_stc, i_nb_skipped_chunks = LookupDirAuxFile( psz_dir_name, i_dir_file, i_stc,
i_asked_payload_size ); i_asked_payload_size );
if ( i_nb_skipped_chunks < 0 ) if ( i_nb_skipped_chunks < 0 )
......
/***************************************************************************** /*****************************************************************************
* util.c: Utils for the multicat suite * util.c: Utils for the multicat suite
***************************************************************************** *****************************************************************************
* Copyright (C) 2004, 2009, 2011, 2015 VideoLAN * Copyright (C) 2004, 2009, 2011, 2015-2016 VideoLAN
* $Id$ * $Id$
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
...@@ -1179,14 +1179,15 @@ void CheckFileSizes( const char *psz_file, const char *psz_aux_file, ...@@ -1179,14 +1179,15 @@ void CheckFileSizes( const char *psz_file, const char *psz_aux_file,
/***************************************************************************** /*****************************************************************************
* GetDirFile: return the prefix of the file according to the STC * GetDirFile: return the prefix of the file according to the STC
*****************************************************************************/ *****************************************************************************/
uint64_t GetDirFile( uint64_t i_rotate_size, int64_t i_wanted ) uint64_t GetDirFile( uint64_t i_rotate_size, uint64_t i_rotate_offset,
int64_t i_wanted )
{ {
if ( i_wanted <= 0 ) if ( i_wanted <= 0 )
i_wanted += real_Date(); i_wanted += real_Date();
if ( i_wanted <= 0 ) if ( i_wanted <= 0 )
return 0; return 0;
return i_wanted / i_rotate_size; return (i_wanted - i_rotate_offset) / i_rotate_size;
} }
/***************************************************************************** /*****************************************************************************
......
/***************************************************************************** /*****************************************************************************
* util.h: Utils for the multicat suite * util.h: Utils for the multicat suite
***************************************************************************** *****************************************************************************
* Copyright (C) 2009, 2011, 2014-2015 VideoLAN * Copyright (C) 2009, 2011, 2014-2016 VideoLAN
* $Id$ * $Id$
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define DEFAULT_PORT 1234 #define DEFAULT_PORT 1234
#define DEFAULT_PAYLOAD_SIZE 1316 #define DEFAULT_PAYLOAD_SIZE 1316
#define DEFAULT_ROTATE_SIZE UINT64_C(97200000000) #define DEFAULT_ROTATE_SIZE UINT64_C(97200000000)
#define DEFAULT_ROTATE_OFFSET UINT64_C(0)
#define TS_SIZE 188 #define TS_SIZE 188
#define RTP_HEADER_SIZE 12 #define RTP_HEADER_SIZE 12
...@@ -102,7 +103,8 @@ FILE *OpenAuxFile( const char *psz_arg, bool b_read, bool b_append ); ...@@ -102,7 +103,8 @@ FILE *OpenAuxFile( const char *psz_arg, bool b_read, bool b_append );
off_t LookupAuxFile( const char *psz_arg, int64_t i_wanted, bool b_absolute ); off_t LookupAuxFile( const char *psz_arg, int64_t i_wanted, bool b_absolute );
void CheckFileSizes( const char *psz_file, const char *psz_aux_file, void CheckFileSizes( const char *psz_file, const char *psz_aux_file,
size_t i_payload_size ); size_t i_payload_size );
uint64_t GetDirFile( uint64_t i_rotate_size, int64_t i_wanted ); uint64_t GetDirFile( uint64_t i_rotate_size, uint64_t i_rotate_offset,
int64_t i_wanted );
int OpenDirFile( const char *psz_dir_path, uint64_t i_file, bool b_read, int OpenDirFile( const char *psz_dir_path, uint64_t i_file, bool b_read,
size_t i_payload_size, FILE **pp_aux_file ); size_t i_payload_size, FILE **pp_aux_file );
off_t LookupDirAuxFile( const char *psz_dir_path, uint64_t i_file, off_t LookupDirAuxFile( const char *psz_dir_path, uint64_t i_file,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment