From: John Peterson <[email protected]>
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
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel