From: John Peterson <john.peters...@hotmail.com>

Useful to simulate low performance input.
The minimum resolution is 1 Kib/s.

The input stream packet size setting can be used to test the performance
with different packet sizes at the maximum or simulated maximum input
rate.
---
 libavformat/avio.h    | 15 ++++++++++++
 libavformat/aviobuf.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/utils.c   |  5 +++-
 3 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/libavformat/avio.h b/libavformat/avio.h
index 3360e82..b16fd00 100644
--- a/libavformat/avio.h
+++ b/libavformat/avio.h
@@ -54,6 +54,19 @@ typedef struct AVIOInterruptCB {
 } AVIOInterruptCB;
 
 /**
+ * Input stream throttle queue.
+ */
+typedef struct traffic {
+    int64_t time;
+    int traf;
+} traffic;
+typedef struct traffic_queue {
+    int size;
+    int len;
+    traffic *data;
+} traffic_queue;
+
+/**
  * Bytestream IO Context.
  * New fields can be added to the end with minor version bumps.
  * Removal, reordering and changes to existing fields require a major
@@ -96,6 +109,8 @@ typedef struct AVIOContext {
     int eof_reached;        /**< true if eof reached */
     int write_flag;         /**< true if open for writing */
     int max_packet_size;
+    int throttle;           /**< command line argument throttle */
+    traffic_queue t_queue;  /**< traffic queue for throttle */
     unsigned long checksum;
     unsigned char *checksum_ptr;
     unsigned long (*update_checksum)(unsigned long checksum, const uint8_t 
*buf, unsigned int size);
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index cc79146..f957625 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -30,8 +30,10 @@
 #include "internal.h"
 #include "url.h"
 #include <stdarg.h>
+#include <unistd.h>
 
 #define IO_BUFFER_SIZE 32768
+#define INPUT_HISTORY_SIZE 10 // s
 
 /**
  * Do seeks within this distance ahead of the current buffer by skipping
@@ -51,7 +53,11 @@ static const AVClass *ffio_url_child_class_next(const 
AVClass *prev)
     return prev ? NULL : &ffurl_context_class;
 }
 
+#define OFFSET(x) offsetof(AVIOContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
 static const AVOption ffio_url_options[] = {
+    { "in_packet_size", "set max input packet size", OFFSET(max_packet_size), 
AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, D },
+    { "throttle", "set max input rate in Kib/s", OFFSET(throttle), 
AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, D },
     { NULL },
 };
 
@@ -359,6 +365,57 @@ void avio_wb24(AVIOContext *s, unsigned int val)
 
 /* Input stream */
 
+/* traffic history for input throttle */
+static void t_queue_push(traffic_queue *queue, int64_t time, int traf)
+{
+    traffic* data;
+    queue->len++;
+    data = av_realloc(queue->data, sizeof(traffic)*queue->len);
+    if (!data)
+        return;
+    queue->data = data;
+    queue->data[queue->len-1].time = time;
+    queue->data[queue->len-1].traf = traf;
+}
+
+static void t_queue_pop(traffic_queue *queue)
+{
+    int i;
+    for (i = 0; i < queue->len; i++)  {
+        if (queue->data[i].time < av_gettime()-INPUT_HISTORY_SIZE*1000000) {
+            memmove(queue->data + i, queue->data + i + 1, 
sizeof(traffic)*(queue->len - i - 1));
+            queue->len--;
+        }
+    }
+}
+
+/* input throttle */
+static int64_t avio_throttle_rate(traffic_queue *queue, int64_t time)
+{
+    int64_t sum = 0;
+    int i;
+    for (i = 0; i < queue->len; i++) {
+        if (queue->data[i].time > av_gettime()-time)
+            sum += queue->data[i].traf;
+    }
+    return (double)sum/((double)time/1000000.0); // B/s
+}
+
+static int avio_throttle(AVIOContext *s)
+{
+    if (!s->throttle) return 0;
+    t_queue_pop(&s->t_queue);
+    // measure speed at multiple intervals to create an even transfer rate
+    if (avio_throttle_rate(&s->t_queue, 0.001*1000000) > s->throttle*0x80
+        || avio_throttle_rate(&s->t_queue, 0.01*1000000) > s->throttle*0x80
+        || avio_throttle_rate(&s->t_queue, 0.1*1000000) > s->throttle*0x80
+        || avio_throttle_rate(&s->t_queue, 1*1000000) > s->throttle*0x80
+        || avio_throttle_rate(&s->t_queue, 10*1000000) > s->throttle*0x80
+        )
+    return 1;
+    return 0;
+}
+
 static void fill_buffer(AVIOContext *s)
 {
     uint8_t *dst        = !s->max_packet_size &&
@@ -405,6 +462,12 @@ static void fill_buffer(AVIOContext *s)
         s->pos += len;
         s->buf_ptr = dst;
         s->buf_end = dst + len;
+
+        // throttle
+        t_queue_push(&s->t_queue, av_gettime(), len);
+        while (s->throttle && avio_throttle(s)) {
+            usleep(0.1*1000000);
+        }
     }
 }
 
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 7a054af..2211b9c 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -427,8 +427,11 @@ int avformat_open_input(AVFormatContext **ps, const char 
*filename,
     }
 
     /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
-    if (s->pb)
+    if (s->pb) {
         ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
+        if ((ret = av_opt_set_dict(s->pb, &tmp)) < 0)
+            goto fail;
+    }
 
     if (s->iformat->read_header)
         if ((ret = s->iformat->read_header(s)) < 0)
-- 
1.9.1

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to