]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/udp.c
Merge commit '33ac77e850efdfd0e8835950c3d947baffd4df45'
[ffmpeg] / libavformat / udp.c
index 531e25466b5394dd318a3a8cd2ae8dbcee5f281d..8699c1c119c2e58c75b0aec01eaf73138e1b3a88 100644 (file)
@@ -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,6 +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 = 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);
@@ -566,6 +573,7 @@ static void *circular_buffer_task_tx( void *_URLContext)
         int len;
         const uint8_t *p;
         uint8_t tmp[4];
+        int64_t timestamp;
 
         len=av_fifo_size(s->fifo);
 
@@ -589,6 +597,26 @@ static void *circular_buffer_task_tx( void *_URLContext)
         pthread_mutex_unlock(&s->mutex);
         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate);
 
+        if (s->bitrate) {
+            timestamp = av_gettime_relative();
+            if (timestamp < target_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 {
+                if (timestamp - burst_interval > target_timestamp) {
+                    start_timestamp = timestamp - burst_interval;
+                    sent_bits = 0;
+                }
+            }
+            sent_bits += len * 8;
+            target_timestamp = start_timestamp + sent_bits * 1000000 / s->bitrate;
+        }
+
         p = s->tmp;
         while (len) {
             int ret;
@@ -613,8 +641,6 @@ static void *circular_buffer_task_tx( void *_URLContext)
             }
         }
 
-        av_usleep(s->packet_gap);
-
         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate);
         pthread_mutex_lock(&s->mutex);
     }
@@ -733,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));
         }
@@ -925,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 */