From cc16229d914aa0eea827599f9df7716bb2afa36b Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Fri, 10 Jun 2016 02:32:21 +0200 Subject: 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 --- libavformat/udp.c | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'libavformat/udp.c') 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 */ -- cgit v1.2.3