On Sat, 19 Jul 2014 19:21:47 -0400
siret...@gmail.com wrote:

> 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)

I'd say no. Useful for debugging sometimes (or is there a real
usecase???), but does it really have to be in the main repo? Also, this
should be implemented as nested protocol, not somehow hacking it into
aviobuf.c.
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to