Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Sun, 1 Apr 2012 21:48:36 +0000 (23:48 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 1 Apr 2012 22:17:02 +0000 (00:17 +0200)
* qatar/master:
  vsrc_buffer: allow buffering arbitrary number of frames.
  vf_scale: avoid a pointless memcpy in no-op conversion.
  avfiltergraph: try to reduce format conversions in filters.
  avfiltergraph: add an AVClass to AVFilterGraph on next major bump.
  id3v2: fix skipping extended header in id3v2.4

Conflicts:
libavfilter/vf_scale.c
libavfilter/vsrc_buffer.c
libavformat/id3v2.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavfilter/avfiltergraph.c
libavfilter/avfiltergraph.h
libavfilter/version.h
libavfilter/vf_scale.c
libavfilter/vsrc_buffer.c
libavformat/id3v2.c

@@@ -245,22 -209,54 +259,65 @@@ static void pick_format(AVFilterLink *l
  
      link->in_formats->format_count = 1;
      link->format = link->in_formats->formats[0];
 -
      avfilter_formats_unref(&link->in_formats);
      avfilter_formats_unref(&link->out_formats);
 +
 +    if (link->type == AVMEDIA_TYPE_AUDIO) {
 +        link->in_chlayouts->format_count = 1;
 +        link->channel_layout = link->in_chlayouts->formats[0];
 +        avfilter_formats_unref(&link->in_chlayouts);
 +        avfilter_formats_unref(&link->out_chlayouts);
 +
 +        link->in_packing->format_count = 1;
 +        link->planar = link->in_packing->formats[0] == AVFILTER_PLANAR;
 +        avfilter_formats_unref(&link->in_packing);
 +        avfilter_formats_unref(&link->out_packing);
 +    }
  }
  
+ static int reduce_formats_on_filter(AVFilterContext *filter)
+ {
+     int i, j, k, ret = 0;
+     for (i = 0; i < filter->input_count; i++) {
+         AVFilterLink *link = filter->inputs[i];
+         int         format = link->out_formats->formats[0];
+         if (link->out_formats->format_count != 1)
+             continue;
+         for (j = 0; j < filter->output_count; j++) {
+             AVFilterLink *out_link = filter->outputs[j];
+             AVFilterFormats  *fmts = out_link->in_formats;
+             if (link->type != out_link->type ||
+                 out_link->in_formats->format_count == 1)
+                 continue;
+             for (k = 0; k < out_link->in_formats->format_count; k++)
+                 if (fmts->formats[k] == format) {
+                     fmts->formats[0]   = format;
+                     fmts->format_count = 1;
+                     ret = 1;
+                     break;
+                 }
+         }
+     }
+     return ret;
+ }
+ static void reduce_formats(AVFilterGraph *graph)
+ {
+     int i, reduced;
+     do {
+         reduced = 0;
+         for (i = 0; i < graph->filter_count; i++)
+             reduced |= reduce_formats_on_filter(graph->filters[i]);
+     } while (reduced);
+ }
  static void pick_formats(AVFilterGraph *graph)
  {
      int i, j;
Simple merge
Simple merge
@@@ -214,33 -213,25 +214,38 @@@ static int config_props(AVFilterLink *o
  
      if (scale->sws)
          sws_freeContext(scale->sws);
-     scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
-                                 outlink->w, outlink->h, outfmt,
-                                 scale->flags, NULL, NULL, NULL);
-     if (scale->isws[0])
-         sws_freeContext(scale->isws[0]);
-     scale->isws[0] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
-                                     outlink->w, outlink->h/2, outfmt,
+     if (inlink->w == outlink->w && inlink->h == outlink->h &&
+         inlink->format == outlink->format)
+         scale->sws = NULL;
+     else {
+         scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
 -                                    outlink->w, outlink->h, outlink->format,
++                                    outlink->w, outlink->h, outfmt,
                                      scale->flags, NULL, NULL, NULL);
-     if (scale->isws[1])
-         sws_freeContext(scale->isws[1]);
-     scale->isws[1] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
-                                     outlink->w, outlink->h/2, outfmt,
-                                     scale->flags, NULL, NULL, NULL);
-     if (!scale->sws || !scale->isws[0] || !scale->isws[1])
-         return AVERROR(EINVAL);
 -        if (!scale->sws)
++        if (scale->isws[0])
++            sws_freeContext(scale->isws[0]);
++        scale->isws[0] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
++                                        outlink->w, outlink->h/2, outfmt,
++                                        scale->flags, NULL, NULL, NULL);
++        if (scale->isws[1])
++            sws_freeContext(scale->isws[1]);
++        scale->isws[1] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
++                                        outlink->w, outlink->h/2, outfmt,
++                                        scale->flags, NULL, NULL, NULL);
++        if (!scale->sws || !scale->isws[0] || !scale->isws[1])
+             return AVERROR(EINVAL);
+     }
  
 -
 -    if (inlink->sample_aspect_ratio.num)
 -        outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
 -                                                             outlink->w*inlink->h},
 -                                                inlink->sample_aspect_ratio);
 -    else
 +    if (inlink->sample_aspect_ratio.num){
 +        outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
 +    } else
          outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
  
 +    av_log(ctx, AV_LOG_INFO, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",
 +           inlink ->w, inlink ->h, av_pix_fmt_descriptors[ inlink->format].name,
 +           inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
 +           outlink->w, outlink->h, av_pix_fmt_descriptors[outlink->format].name,
 +           outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
 +           scale->flags);
      return 0;
  
  fail:
@@@ -306,7 -274,14 +316,12 @@@ static void draw_slice(AVFilterLink *li
  {
      ScaleContext *scale = link->dst->priv;
      int out_h;
 -    AVFilterBufferRef *cur_pic = link->cur_buf;
 -    const uint8_t *data[4];
  
+     if (!scale->sws) {
+         avfilter_draw_slice(link->dst->outputs[0], y, h, slice_dir);
+         return;
+     }
      if (scale->slice_y == 0 && slice_dir == -1)
          scale->slice_y = link->dst->outputs[0]->h;
  
   */
  
  #include "avfilter.h"
 +#include "internal.h"
 +#include "avcodec.h"
  #include "buffersrc.h"
  #include "vsrc_buffer.h"
+ #include "libavutil/fifo.h"
  #include "libavutil/imgutils.h"
  
  typedef struct {
-     AVFilterBufferRef *picref;
-     AVFilterContext   *scale;
++    AVFilterContext  *scale;
+     AVFifoBuffer     *fifo;
      int               h, w;
      enum PixelFormat  pix_fmt;
      AVRational        time_base;     ///< time_base to set in the output link
          return AVERROR(EINVAL);\
      }
  
 -int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame,
 -                             int64_t pts, AVRational pixel_aspect)
 +int av_vsrc_buffer_add_video_buffer_ref(AVFilterContext *buffer_filter,
 +                                        AVFilterBufferRef *picref, int flags)
  {
      BufferSourceContext *c = buffer_filter->priv;
 +    AVFilterLink *outlink = buffer_filter->outputs[0];
+     AVFilterBufferRef *buf;
      int ret;
  
-     if (c->picref) {
++    if (av_fifo_size(c->fifo)) {
 +        if (flags & AV_VSRC_BUF_FLAG_OVERWRITE) {
-             avfilter_unref_buffer(c->picref);
-             c->picref = NULL;
-         } else {
-             av_log(buffer_filter, AV_LOG_ERROR,
-                    "Buffering several frames is not supported. "
-                    "Please consume all available frames before adding a new one.\n");
-             return AVERROR(EINVAL);
++            //FIXME not implemented
 +        }
 +    }
+     if (!av_fifo_space(c->fifo) &&
+         (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
+                                          sizeof(buf))) < 0)
+         return ret;
  
 -    CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format);
 +    if (picref->video->w != c->w || picref->video->h != c->h || picref->format != c->pix_fmt) {
 +        AVFilterContext *scale = buffer_filter->outputs[0]->dst;
 +        AVFilterLink *link;
 +        char scale_param[1024];
 +
 +        av_log(buffer_filter, AV_LOG_INFO,
 +               "Buffer video input changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
 +               c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name,
 +               picref->video->w, picref->video->h, av_pix_fmt_descriptors[picref->format].name);
 +
 +        if (!scale || strcmp(scale->filter->name, "scale")) {
 +            AVFilter *f = avfilter_get_by_name("scale");
 +
 +            av_log(buffer_filter, AV_LOG_INFO, "Inserting scaler filter\n");
 +            if ((ret = avfilter_open(&scale, f, "Input equalizer")) < 0)
 +                return ret;
 +
 +            c->scale = scale;
  
 -    buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
 -                                    c->w, c->h);
 -    av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize,
 -                  c->pix_fmt, c->w, c->h);
 +            snprintf(scale_param, sizeof(scale_param)-1, "%d:%d:%s", c->w, c->h, c->sws_param);
 +            if ((ret = avfilter_init_filter(scale, scale_param, NULL)) < 0) {
 +                return ret;
 +            }
 +
 +            if ((ret = avfilter_insert_filter(buffer_filter->outputs[0], scale, 0, 0)) < 0) {
 +                return ret;
 +            }
 +            scale->outputs[0]->time_base = scale->inputs[0]->time_base;
 +
 +            scale->outputs[0]->format= c->pix_fmt;
 +        } else if (!strcmp(scale->filter->name, "scale")) {
 +            snprintf(scale_param, sizeof(scale_param)-1, "%d:%d:%s",
 +                     scale->outputs[0]->w, scale->outputs[0]->h, c->sws_param);
 +            scale->filter->init(scale, scale_param, NULL);
 +        }
 +
 +        c->pix_fmt = scale->inputs[0]->format = picref->format;
 +        c->w       = scale->inputs[0]->w      = picref->video->w;
 +        c->h       = scale->inputs[0]->h      = picref->video->h;
 +
 +        link = scale->outputs[0];
 +        if ((ret =  link->srcpad->config_props(link)) < 0)
 +            return ret;
 +    }
  
-     c->picref = avfilter_get_video_buffer(outlink, AV_PERM_WRITE,
-                                           picref->video->w, picref->video->h);
-     av_image_copy(c->picref->data, c->picref->linesize,
 -    avfilter_copy_frame_props(buf, frame);
 -    buf->pts                    = pts;
 -    buf->video->pixel_aspect    = pixel_aspect;
++    buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE,
++                                    picref->video->w, picref->video->h);
++    av_image_copy(buf->data, buf->linesize,
 +                  (void*)picref->data, picref->linesize,
 +                  picref->format, picref->video->w, picref->video->h);
-     avfilter_copy_buffer_ref_props(c->picref, picref);
++    avfilter_copy_buffer_ref_props(buf, picref);
+     if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
+         avfilter_unref_buffer(buf);
+         return ret;
+     }
  
      return 0;
  }
  int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
  {
      BufferSourceContext *c = s->priv;
+     int ret;
  
-     if (c->picref) {
-         av_log(s, AV_LOG_ERROR,
-                "Buffering several frames is not supported. "
-                "Please consume all available frames before adding a new one.\n"
-             );
-         return AVERROR(EINVAL);
-     }
+     if (!av_fifo_space(c->fifo) &&
+         (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
+                                          sizeof(buf))) < 0)
+         return ret;
  
 -    CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
 +//     CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
  
-     c->picref = buf;
+     if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0)
+         return ret;
  
      return 0;
  }
@@@ -162,35 -96,41 +166,42 @@@ static av_cold int init(AVFilterContex
  {
      BufferSourceContext *c = ctx->priv;
      char pix_fmt_str[128];
 -    int n = 0;
 +    int ret, n = 0;
 +    *c->sws_param = 0;
  
      if (!args ||
 -        (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str,
 +        (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d:%255c", &c->w, &c->h, pix_fmt_str,
                      &c->time_base.num, &c->time_base.den,
 -                    &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) {
 -        av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args);
 +                    &c->sample_aspect_ratio.num, &c->sample_aspect_ratio.den, c->sws_param)) < 7) {
 +        av_log(ctx, AV_LOG_ERROR, "Expected at least 7 arguments, but only %d found in '%s'\n", n, args);
          return AVERROR(EINVAL);
      }
 -    if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == PIX_FMT_NONE) {
 -        char *tail;
 -        c->pix_fmt = strtol(pix_fmt_str, &tail, 10);
 -        if (*tail || c->pix_fmt < 0 || c->pix_fmt >= PIX_FMT_NB) {
 -            av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str);
 -            return AVERROR(EINVAL);
 -        }
 -    }
 +
 +    if ((ret = ff_parse_pixel_format(&c->pix_fmt, pix_fmt_str, ctx)) < 0)
 +        return ret;
  
 -    av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name);
+     if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*))))
+         return AVERROR(ENOMEM);
 +    av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s tb:%d/%d sar:%d/%d sws_param:%s\n",
 +           c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name,
 +           c->time_base.num, c->time_base.den,
 +           c->sample_aspect_ratio.num, c->sample_aspect_ratio.den, c->sws_param);
      return 0;
  }
  
  static av_cold void uninit(AVFilterContext *ctx)
  {
      BufferSourceContext *s = ctx->priv;
-     if (s->picref)
-         avfilter_unref_buffer(s->picref);
-     s->picref = NULL;
+     while (av_fifo_size(s->fifo)) {
+         AVFilterBufferRef *buf;
+         av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL);
+         avfilter_unref_buffer(buf);
+     }
+     av_fifo_free(s->fifo);
+     s->fifo = NULL;
 +    avfilter_free(s->scale);
 +    s->scale = NULL;
  }
  
  static int query_formats(AVFilterContext *ctx)
@@@ -217,18 -157,19 +228,19 @@@ static int config_props(AVFilterLink *l
  static int request_frame(AVFilterLink *link)
  {
      BufferSourceContext *c = link->src->priv;
+     AVFilterBufferRef *buf;
  
-     if (!c->picref) {
+     if (!av_fifo_size(c->fifo)) {
 -        av_log(link->src, AV_LOG_ERROR,
 +        av_log(link->src, AV_LOG_WARNING,
                 "request_frame() called with no available frame!\n");
 -        //return -1;
 +        return AVERROR(EINVAL);
      }
+     av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL);
  
-     avfilter_start_frame(link, avfilter_ref_buffer(c->picref, ~0));
+     avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0));
      avfilter_draw_slice(link, 0, link->h, 1);
      avfilter_end_frame(link);
-     avfilter_unref_buffer(c->picref);
-     c->picref = NULL;
+     avfilter_unref_buffer(buf);
  
      return 0;
  }
@@@ -577,21 -561,16 +577,21 @@@ static void ff_id3v2_parse(AVFormatCont
  
      unsync = flags & 0x80;
  
-     /* Extended header present, just skip over it */
-     if (isv34 && flags & 0x40) {
-         int size = get_size(s->pb, 4);
-         if (size < 6) {
-             reason = "extended header too short.";
+     if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */
+         int extlen = get_size(s->pb, 4);
+         if (version == 4)
+             extlen -= 4;     // in v2.4 the length includes the length field we just read
+         if (extlen < 0) {
+             reason = "invalid extended header length";
              goto error;
          }
-         len -= size;
+         avio_skip(s->pb, extlen);
++        len -= extlen + 4;
 +        if (len < 0) {
 +            reason = "extended header too long.";
 +            goto error;
 +        }
-         /* already seeked past size, skip the reset */
-         size -= 4;
-         avio_skip(s->pb, size);
      }
  
      while (len >= taghdrlen) {