From cc16229d914aa0eea827599f9df7716bb2afa36b Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Fri, 10 Jun 2016 02:32:21 +0200 Subject: [PATCH] avformat/udp: replace packet_gap with bitrate option We haven't had a stable release since the packet_gap addition, so probably it is worth reworking the option to something that makes more sense to the end user. Also add burst_bits option to specify maximum length of bit bursts. Signed-off-by: Marton Balint --- doc/protocols.texi | 9 ++++++-- libavformat/udp.c | 51 ++++++++++++++++++++++++++++--------------- libavformat/version.h | 2 +- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/doc/protocols.texi b/doc/protocols.texi index a9c9d0c462..72b39145ec 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -1285,8 +1285,13 @@ Set the UDP maximum socket buffer size in bytes. This is used to set either the receive or send buffer size, depending on what the socket is used for. Default is 64KB. See also @var{fifo_size}. -@item packet_gap=@var{seconds} -Delay between packets +@item bitrate=@var{bitrate} +If set to nonzero, the output will have the specified constant bitrate if the +input has enough packets to sustain it. + +@item burst_bits=@var{bits} +When using @var{bitrate} this specifies the maximum number of bits in +packet bursts. @item localport=@var{port} Override the local UDP port to bind with. diff --git a/libavformat/udp.c b/libavformat/udp.c index f2446c62ed..8699c1c119 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -93,7 +93,8 @@ typedef struct UDPContext { int circular_buffer_size; AVFifoBuffer *fifo; int circular_buffer_error; - int64_t packet_gap; /* delay between transmitted packets */ + int64_t bitrate; /* number of bits to send per second */ + int64_t burst_bits; int close_req; #if HAVE_PTHREAD_CANCEL pthread_t circular_buffer_thread; @@ -115,7 +116,8 @@ typedef struct UDPContext { #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "buffer_size", "System data size (in bytes)", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, - { "packet_gap", "Delay between packets", OFFSET(packet_gap), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, .flags = E }, + { "bitrate", "Bits to send per second", OFFSET(bitrate), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, .flags = E }, + { "burst_bits", "Max length of bursts in bits (when using bitrate)", OFFSET(burst_bits), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, .flags = E }, { "localport", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D|E }, { "local_port", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "localaddr", "Local address", OFFSET(localaddr), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, @@ -552,7 +554,11 @@ static void *circular_buffer_task_tx( void *_URLContext) URLContext *h = _URLContext; UDPContext *s = h->priv_data; int old_cancelstate; - int64_t target_timestamp = 0; + int64_t target_timestamp = av_gettime_relative(); + int64_t start_timestamp = av_gettime_relative(); + int64_t sent_bits = 0; + int64_t burst_interval = s->bitrate ? (s->burst_bits * 1000000 / s->bitrate) : 0; + int64_t max_delay = s->bitrate ? ((int64_t)h->max_packet_size * 8 * 1000000 / s->bitrate + 1) : 0; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate); pthread_mutex_lock(&s->mutex); @@ -591,15 +597,24 @@ static void *circular_buffer_task_tx( void *_URLContext) pthread_mutex_unlock(&s->mutex); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate); - if (s->packet_gap) { + if (s->bitrate) { timestamp = av_gettime_relative(); if (timestamp < target_timestamp) { - target_timestamp = FFMIN(target_timestamp, timestamp + s->packet_gap); - av_usleep(target_timestamp - timestamp); + int64_t delay = target_timestamp - timestamp; + if (delay > max_delay) { + delay = max_delay; + start_timestamp = timestamp + delay; + sent_bits = 0; + } + av_usleep(delay); } else { - target_timestamp = timestamp; + if (timestamp - burst_interval > target_timestamp) { + start_timestamp = timestamp - burst_interval; + sent_bits = 0; + } } - target_timestamp += s->packet_gap; + sent_bits += len * 8; + target_timestamp = start_timestamp + sent_bits * 1000000 / s->bitrate; } p = s->tmp; @@ -744,16 +759,16 @@ static int udp_open(URLContext *h, const char *uri, int flags) "'circular_buffer_size' option was set but it is not supported " "on this build (pthread support is required)\n"); } - if (av_find_info_tag(buf, sizeof(buf), "packet_gap", p)) { - if (av_parse_time(&s->packet_gap, buf, 1)<0) { - av_log(h, AV_LOG_ERROR, "Can't parse 'packet_gap'"); - goto fail; - } + if (av_find_info_tag(buf, sizeof(buf), "bitrate", p)) { + s->bitrate = strtoll(buf, NULL, 10); if (!HAVE_PTHREAD_CANCEL) av_log(h, AV_LOG_WARNING, - "'packet_gap' option was set but it is not supported " + "'bitrate' option was set but it is not supported " "on this build (pthread support is required)\n"); } + if (av_find_info_tag(buf, sizeof(buf), "burst_bits", p)) { + s->burst_bits = strtoll(buf, NULL, 10); + } if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } @@ -936,15 +951,15 @@ static int udp_open(URLContext *h, const char *uri, int flags) /* Create thread in case of: 1. Input and circular_buffer_size is set - 2. Output and packet_gap and circular_buffer_size is set + 2. Output and bitrate and circular_buffer_size is set */ - if (is_output && s->packet_gap && !s->circular_buffer_size) { + if (is_output && s->bitrate && !s->circular_buffer_size) { /* Warn user in case of 'circular_buffer_size' is not set */ - av_log(h, AV_LOG_WARNING,"'packet_gap' option was set but 'circular_buffer_size' is not, but required\n"); + av_log(h, AV_LOG_WARNING,"'bitrate' option was set but 'circular_buffer_size' is not, but required\n"); } - if ((!is_output && s->circular_buffer_size) || (is_output && s->packet_gap && s->circular_buffer_size)) { + if ((!is_output && s->circular_buffer_size) || (is_output && s->bitrate && s->circular_buffer_size)) { int ret; /* start the task going */ diff --git a/libavformat/version.h b/libavformat/version.h index 3dc79ff774..ce650d583f 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -33,7 +33,7 @@ // Also please add any ticket numbers that you belive might regress here #define LIBAVFORMAT_VERSION_MAJOR 57 #define LIBAVFORMAT_VERSION_MINOR 38 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MICRO 102 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \