[FFmpeg-devel] UDP constant bitrate feature (cbr)

Pavel Meshkov pmeshkov at kwikflixtv.com
Wed Nov 11 20:08:15 CET 2015


Trying to reattach patch

11.11.2015 22:01, Pavel Meshkov пишет:
> We added UDP output constant bitrate functionality.
> Please review patch.
>
> P.S.: It's first patch we send. Please notify me if something made wrong.
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

-------------- next part --------------
From 5d870287a26746dcb0c738b54fd62230285a49af Mon Sep 17 00:00:00 2001
From: Pavel Meshkov <pmeshkov at kwikflixtv.com>
Date: Sun, 8 Nov 2015 04:12:25 +0000
Subject: [PATCH] Added "cbr" and "cbr_burst" options for udp output. Related
 Trac ticket 4155

---
 doc/protocols.texi | 24 ++++++++++++++++++++++--
 libavformat/udp.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 7c6b9d4..f2fb9dc 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1293,6 +1293,19 @@ Explicitly allow or disallow UDP broadcasting.

 Note that broadcasting may not work properly on networks having
 a broadcast storm protection.
+
+ at item cbr=@var{size}
+Set output constant bitrate size in bites.
+
+Bitrate estimation starts from first packet. It means that accuracy rises in time.
+If a lot of late packets will comes they will be sent emmidiatly. To avoid this
+behaiour see at @code{cbr_burst} option.
+
+ at item cbr_burst=@var{size}
+Set output constant bitrate maximum burst in bites. Set max speed
+between two UDP packets.
+
+Recommended value is @code{cbr + 5%}
 @end table

 @subsection Examples
@@ -1306,9 +1319,16 @@ ffmpeg -i @var{input} -f @var{format} udp://@var{hostname}:@var{port}

 @item
 Use @command{ffmpeg} to stream in mpegts format over UDP using 188
-sized UDP packets, using a large input buffer:
+sized UDP packets, using a large input buffer (pkt_size is 188*7=1316):
+ at example
+ffmpeg -i @var{input} -f mpegts udp://@var{hostname}:@var{port}?pkt_size=1316&buffer_size=65535
+ at end example
+
+ at item
+Use @command{ffmpeg} to stream in mpegts format over UDP using 188
+sized UDP packets, using a large input buffer and constant bitrate output with 5% bitrate burst:
 @example
-ffmpeg -i @var{input} -f mpegts udp://@var{hostname}:@var{port}?pkt_size=188&buffer_size=65535
+ffmpeg -i @var{input} -f mpegts udp://@var{hostname}:@var{port}?pkt_size=188&buffer_size=65535&cbr=2000000&cbr_burst=2100000
 @end example

 @item
diff --git a/libavformat/udp.c b/libavformat/udp.c
index 1bda5af..80c346a 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -76,6 +76,8 @@ typedef struct UDPContext {
     const AVClass *class;
     int udp_fd;
     int ttl;
+    int cbr;
+    int cbr_burst;
     int udplite_coverage;
     int buffer_size;
     int pkt_size;
@@ -88,6 +90,10 @@ typedef struct UDPContext {
     int dest_addr_len;
     int is_connected;

+    int64_t total_packet_size;
+    int64_t time_start;
+    int64_t time_last_packet;
+
     /* Circular Buffer variables for use in UDP receive code */
     int circular_buffer_size;
     AVFifoBuffer *fifo;
@@ -117,6 +123,8 @@ static const AVOption options[] = {
     { "localaddr",      "Local address",                                   OFFSET(localaddr),      AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
     { "udplite_coverage", "choose UDPLite head size which should be validated by checksum", OFFSET(udplite_coverage), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
     { "pkt_size",       "Maximum UDP packet size",                         OFFSET(pkt_size),       AV_OPT_TYPE_INT,    { .i64 = 1472 },  -1, INT_MAX, .flags = D|E },
+    { "cbr",            "Force CBR (in bites)",                            OFFSET(cbr),            AV_OPT_TYPE_INT,    { .i64 = 0 },     -1, INT_MAX, E },
+    { "cbr_burst",      "CBR burst (in bites). Must be greater than 'cbr'", OFFSET(cbr_burst),      AV_OPT_TYPE_INT,    { .i64 = 0 },     -1, INT_MAX, E },
     { "reuse",          "explicitly allow reusing UDP sockets",            OFFSET(reuse_socket),   AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, 1,       D|E },
     { "reuse_socket",   "explicitly allow reusing UDP sockets",            OFFSET(reuse_socket),   AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, 1,       .flags = D|E },
     { "broadcast", "explicitly allow or disallow broadcast destination",   OFFSET(is_broadcast),   AV_OPT_TYPE_INT,    { .i64 = 0  },     0, 1,       E },
@@ -150,7 +158,6 @@ static void log_net_error(void *ctx, int level, const char* prefix)
     av_strerror(ff_neterrno(), errbuf, sizeof(errbuf));
     av_log(ctx, level, "%s: %s\n", prefix, errbuf);
 }
-
 static int udp_set_multicast_ttl(int sockfd, int mcastTTL,
                                  struct sockaddr *addr)
 {
@@ -178,7 +185,6 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,struct soc
 #ifdef IP_ADD_MEMBERSHIP
     if (addr->sa_family == AF_INET) {
         struct ip_mreq mreq;
-
         mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
         if (local_addr)
             mreq.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr;
@@ -626,6 +632,22 @@ static int udp_open(URLContext *h, const char *uri, int flags)
         if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
             s->pkt_size = strtol(buf, NULL, 10);
         }
+        if (av_find_info_tag(buf, sizeof(buf), "cbr", p)) {
+            s->cbr = strtol(buf, NULL, 10);
+        }
+        if (av_find_info_tag(buf, sizeof(buf), "cbr_burst", p)) {
+            s->cbr_burst = strtol(buf, NULL, 10);
+            if (s->cbr > s->cbr_burst) {
+                av_log(h, AV_LOG_ERROR,
+                    "'cbr_burst' value must be greater than 'cbr'\n");
+                goto fail;
+            }
+            if (s->cbr == 0) {
+                av_log(h, AV_LOG_WARNING,
+                    "'cbr' option is required for 'cbr_burst'. "
+                    "'cbr_burst' will be ignored\n");
+            }
+        }
         if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
             s->buffer_size = strtol(buf, NULL, 10);
         }
@@ -669,6 +691,9 @@ static int udp_open(URLContext *h, const char *uri, int flags)
     }
     h->rw_timeout = s->timeout;

+    /* set start total_packet_size for cbr */
+    s->total_packet_size = 0;
+
     /* fill the dest addr */
     av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);

@@ -935,6 +960,26 @@ static int udp_write(URLContext *h, const uint8_t *buf, int size)
             return ret;
     }

+    if (s->cbr > 0) {
+        if (s->total_packet_size == 0) {
+            s->time_start = av_gettime();
+            s->time_last_packet = 0;
+        }
+
+        s->total_packet_size += size;
+
+        if((s->cbr_burst > 0) && (s->time_last_packet > 0)) {
+            while (((int64_t)size * 8 * 1000000) > ( (int64_t)s->cbr_burst * (av_gettime() - s->time_last_packet)) ) {
+                av_usleep(10);
+            }
+        }
+
+        /* 8 is to convert to bits, 1000000 is 1 second in microseconds (usec) */
+        while ((s->total_packet_size * 8 * 1000000) > ((int64_t)s->cbr * (av_gettime() - s->time_start))) {
+            av_usleep(10);
+        }
+    }
+
     if (!s->is_connected) {
         ret = sendto (s->udp_fd, buf, size, 0,
                       (struct sockaddr *) &s->dest_addr,
@@ -942,6 +987,9 @@ static int udp_write(URLContext *h, const uint8_t *buf, int size)
     } else
         ret = send(s->udp_fd, buf, size, 0);

+    if ( s->cbr_burst > 0 )
+        s->time_last_packet = av_gettime();
+
     return ret < 0 ? ff_neterrno() : ret;
 }

--
1.9.1



More information about the ffmpeg-devel mailing list