Merge commit '7bc1a883c9158bb6e383d86fc76bdf2541e9a9fe'
authorMichael Niedermayer <michaelni@gmx.at>
Thu, 11 Apr 2013 01:10:43 +0000 (03:10 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 11 Apr 2013 01:10:43 +0000 (03:10 +0200)
* commit '7bc1a883c9158bb6e383d86fc76bdf2541e9a9fe':
  vsrc_color: switch to an AVOptions-based system.

Conflicts:
doc/filters.texi
libavfilter/vsrc_color.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavfilter/avfilter.c
libavfilter/vsrc_testsrc.c

diff --combined libavfilter/avfilter.c
@@@ -2,24 -2,25 +2,24 @@@
   * filter layer
   * Copyright (c) 2007 Bobby Bingham
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
 -/* #define DEBUG */
 -
 +#include "libavutil/avassert.h"
  #include "libavutil/avstring.h"
  #include "libavutil/channel_layout.h"
  #include "libavutil/common.h"
  #include "avfilter.h"
  #include "formats.h"
  #include "internal.h"
 -#include "video.h"
 +#include "audio.h"
 +
 +static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame);
 +
 +void ff_tlog_ref(void *ctx, AVFrame *ref, int end)
 +{
 +    av_unused char buf[16];
 +    ff_tlog(ctx,
 +            "ref[%p buf:%p data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64,
 +            ref, ref->buf, ref->data[0],
 +            ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3],
 +            ref->pts, av_frame_get_pkt_pos(ref));
 +
 +    if (ref->width) {
 +        ff_tlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c",
 +                ref->sample_aspect_ratio.num, ref->sample_aspect_ratio.den,
 +                ref->width, ref->height,
 +                !ref->interlaced_frame     ? 'P' :         /* Progressive  */
 +                ref->top_field_first ? 'T' : 'B',    /* Top / Bottom */
 +                ref->key_frame,
 +                av_get_picture_type_char(ref->pict_type));
 +    }
 +    if (ref->nb_samples) {
 +        ff_tlog(ctx, " cl:%"PRId64"d n:%d r:%d",
 +                ref->channel_layout,
 +                ref->nb_samples,
 +                ref->sample_rate);
 +    }
 +
 +    ff_tlog(ctx, "]%s", end ? "\n" : "");
 +}
  
  unsigned avfilter_version(void) {
 +    av_assert0(LIBAVFILTER_VERSION_MICRO >= 100);
      return LIBAVFILTER_VERSION_INT;
  }
  
  const char *avfilter_configuration(void)
  {
 -    return LIBAV_CONFIGURATION;
 +    return FFMPEG_CONFIGURATION;
  }
  
  const char *avfilter_license(void)
  {
  #define LICENSE_PREFIX "libavfilter license: "
 -    return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
 +    return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
 +}
 +
 +void ff_command_queue_pop(AVFilterContext *filter)
 +{
 +    AVFilterCommand *c= filter->command_queue;
 +    av_freep(&c->arg);
 +    av_freep(&c->command);
 +    filter->command_queue= c->next;
 +    av_free(c);
  }
  
  void ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
@@@ -122,9 -83,8 +122,9 @@@ int avfilter_link(AVFilterContext *src
  
      if (src->output_pads[srcpad].type != dst->input_pads[dstpad].type) {
          av_log(src, AV_LOG_ERROR,
 -               "Media type mismatch between the '%s' filter output pad %d and the '%s' filter input pad %d\n",
 -               src->name, srcpad, dst->name, dstpad);
 +               "Media type mismatch between the '%s' filter output pad %d (%s) and the '%s' filter input pad %d (%s)\n",
 +               src->name, srcpad, (char *)av_x_if_null(av_get_media_type_string(src->output_pads[srcpad].type), "?"),
 +               dst->name, dstpad, (char *)av_x_if_null(av_get_media_type_string(dst-> input_pads[dstpad].type), "?"));
          return AVERROR(EINVAL);
      }
  
      link->srcpad  = &src->output_pads[srcpad];
      link->dstpad  = &dst->input_pads[dstpad];
      link->type    = src->output_pads[srcpad].type;
 -    assert(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
 +    av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
      link->format  = -1;
  
      return 0;
  }
  
 +void avfilter_link_free(AVFilterLink **link)
 +{
 +    if (!*link)
 +        return;
 +
 +    av_frame_free(&(*link)->partial_buf);
 +
 +    av_freep(link);
 +}
 +
 +int avfilter_link_get_channels(AVFilterLink *link)
 +{
 +    return link->channels;
 +}
 +
 +void avfilter_link_set_closed(AVFilterLink *link, int closed)
 +{
 +    link->closed = closed;
 +}
 +
  int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
                             unsigned filt_srcpad_idx, unsigned filt_dstpad_idx)
  {
      if (link->out_formats)
          ff_formats_changeref(&link->out_formats,
                                     &filt->outputs[filt_dstpad_idx]->out_formats);
 +
      if (link->out_samplerates)
          ff_formats_changeref(&link->out_samplerates,
                                     &filt->outputs[filt_dstpad_idx]->out_samplerates);
@@@ -208,13 -147,9 +208,13 @@@ int avfilter_config_links(AVFilterConte
  
      for (i = 0; i < filter->nb_inputs; i ++) {
          AVFilterLink *link = filter->inputs[i];
 +        AVFilterLink *inlink;
  
          if (!link) continue;
  
 +        inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL;
 +        link->current_pts = AV_NOPTS_VALUE;
 +
          switch (link->init_state) {
          case AVLINK_INIT:
              continue;
                  return ret;
              }
  
 -            if (link->time_base.num == 0 && link->time_base.den == 0)
 -                link->time_base = link->src && link->src->nb_inputs ?
 -                    link->src->inputs[0]->time_base : AV_TIME_BASE_Q;
 +            switch (link->type) {
 +            case AVMEDIA_TYPE_VIDEO:
 +                if (!link->time_base.num && !link->time_base.den)
 +                    link->time_base = inlink ? inlink->time_base : AV_TIME_BASE_Q;
  
 -            if (link->type == AVMEDIA_TYPE_VIDEO) {
                  if (!link->sample_aspect_ratio.num && !link->sample_aspect_ratio.den)
 -                    link->sample_aspect_ratio = link->src->nb_inputs ?
 -                        link->src->inputs[0]->sample_aspect_ratio : (AVRational){1,1};
 +                    link->sample_aspect_ratio = inlink ?
 +                        inlink->sample_aspect_ratio : (AVRational){1,1};
  
 -                if (link->src->nb_inputs) {
 +                if (inlink && !link->frame_rate.num && !link->frame_rate.den)
 +                    link->frame_rate = inlink->frame_rate;
 +
 +                if (inlink) {
                      if (!link->w)
 -                        link->w = link->src->inputs[0]->w;
 +                        link->w = inlink->w;
                      if (!link->h)
 -                        link->h = link->src->inputs[0]->h;
 +                        link->h = inlink->h;
                  } else if (!link->w || !link->h) {
                      av_log(link->src, AV_LOG_ERROR,
                             "Video source filters must set their output link's "
                             "width and height\n");
                      return AVERROR(EINVAL);
                  }
 +                break;
 +
 +            case AVMEDIA_TYPE_AUDIO:
 +                if (inlink) {
 +                    if (!link->time_base.num && !link->time_base.den)
 +                        link->time_base = inlink->time_base;
 +                }
 +
 +                if (!link->time_base.num && !link->time_base.den)
 +                    link->time_base = (AVRational) {1, link->sample_rate};
              }
  
              if ((config_link = link->dstpad->config_props))
      return 0;
  }
  
 -void ff_dlog_link(void *ctx, AVFilterLink *link, int end)
 +void ff_tlog_link(void *ctx, AVFilterLink *link, int end)
  {
      if (link->type == AVMEDIA_TYPE_VIDEO) {
 -        av_dlog(ctx,
 -                "link[%p s:%dx%d fmt:%-16s %-16s->%-16s]%s",
 +        ff_tlog(ctx,
 +                "link[%p s:%dx%d fmt:%s %s->%s]%s",
                  link, link->w, link->h,
                  av_get_pix_fmt_name(link->format),
                  link->src ? link->src->filter->name : "",
          char buf[128];
          av_get_channel_layout_string(buf, sizeof(buf), -1, link->channel_layout);
  
 -        av_dlog(ctx,
 -                "link[%p r:%d cl:%s fmt:%-16s %-16s->%-16s]%s",
 -                link, link->sample_rate, buf,
 +        ff_tlog(ctx,
 +                "link[%p r:%d cl:%s fmt:%s %s->%s]%s",
 +                link, (int)link->sample_rate, buf,
                  av_get_sample_fmt_name(link->format),
                  link->src ? link->src->filter->name : "",
                  link->dst ? link->dst->filter->name : "",
  
  int ff_request_frame(AVFilterLink *link)
  {
 -    FF_DPRINTF_START(NULL, request_frame); ff_dlog_link(NULL, link, 1);
 -
 -    if (link->srcpad->request_frame)
 -        return link->srcpad->request_frame(link);
 -    else if (link->src->inputs[0])
 -        return ff_request_frame(link->src->inputs[0]);
 -    else return -1;
 +    int ret = -1;
 +    FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1);
 +
 +    if (link->closed)
 +        return AVERROR_EOF;
 +    av_assert0(!link->frame_requested);
 +    link->frame_requested = 1;
 +    while (link->frame_requested) {
 +        if (link->srcpad->request_frame)
 +            ret = link->srcpad->request_frame(link);
 +        else if (link->src->inputs[0])
 +            ret = ff_request_frame(link->src->inputs[0]);
 +        if (ret == AVERROR_EOF && link->partial_buf) {
 +            AVFrame *pbuf = link->partial_buf;
 +            link->partial_buf = NULL;
 +            ret = ff_filter_frame_framed(link, pbuf);
 +        }
 +        if (ret < 0) {
 +            link->frame_requested = 0;
 +            if (ret == AVERROR_EOF)
 +                link->closed = 1;
 +        } else {
 +            av_assert0(!link->frame_requested ||
 +                       link->flags & FF_LINK_FLAG_REQUEST_LOOP);
 +        }
 +    }
 +    return ret;
  }
  
  int ff_poll_frame(AVFilterLink *link)
      return min;
  }
  
 -#define MAX_REGISTERED_AVFILTERS_NB 64
 +void ff_update_link_current_pts(AVFilterLink *link, int64_t pts)
 +{
 +    if (pts == AV_NOPTS_VALUE)
 +        return;
 +    link->current_pts = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q);
 +    /* TODO use duration */
 +    if (link->graph && link->age_index >= 0)
 +        ff_avfilter_graph_update_heap(link->graph, link);
 +}
 +
 +int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags)
 +{
 +    if(!strcmp(cmd, "ping")){
 +        av_strlcatf(res, res_len, "pong from:%s %s\n", filter->filter->name, filter->name);
 +        return 0;
 +    }else if(filter->filter->process_command) {
 +        return filter->filter->process_command(filter, cmd, arg, res, res_len, flags);
 +    }
 +    return AVERROR(ENOSYS);
 +}
 +
 +#define MAX_REGISTERED_AVFILTERS_NB 256
  
  static AVFilter *registered_avfilters[MAX_REGISTERED_AVFILTERS_NB + 1];
  
@@@ -405,21 -286,8 +405,21 @@@ AVFilter *avfilter_get_by_name(const ch
  
  int avfilter_register(AVFilter *filter)
  {
 -    if (next_registered_avfilter_idx == MAX_REGISTERED_AVFILTERS_NB)
 -        return -1;
 +    int i;
 +
 +    if (next_registered_avfilter_idx == MAX_REGISTERED_AVFILTERS_NB) {
 +        av_log(NULL, AV_LOG_ERROR,
 +               "Maximum number of registered filters %d reached, "
 +               "impossible to register filter with name '%s'\n",
 +               MAX_REGISTERED_AVFILTERS_NB, filter->name);
 +        return AVERROR(ENOMEM);
 +    }
 +
 +    for(i=0; filter->inputs && filter->inputs[i].name; i++) {
 +        const AVFilterPad *input = &filter->inputs[i];
 +        av_assert0(     !input->filter_frame
 +                    || (!input->start_frame && !input->end_frame));
 +    }
  
      registered_avfilters[next_registered_avfilter_idx++] = filter;
      return 0;
@@@ -447,54 -315,18 +447,54 @@@ static int pad_count(const AVFilterPad 
      return count;
  }
  
 -static const char *filter_name(void *p)
 +static const char *default_filter_name(void *filter_ctx)
 +{
 +    AVFilterContext *ctx = filter_ctx;
 +    return ctx->name ? ctx->name : ctx->filter->name;
 +}
 +
 +static void *filter_child_next(void *obj, void *prev)
 +{
 +    AVFilterContext *ctx = obj;
 +    if (!prev && ctx->filter && ctx->filter->priv_class)
 +        return ctx->priv;
 +    return NULL;
 +}
 +
 +static const AVClass *filter_child_class_next(const AVClass *prev)
  {
 -    AVFilterContext *filter = p;
 -    return filter->filter->name;
 +    AVFilter **filter_ptr = NULL;
 +
 +    /* find the filter that corresponds to prev */
 +    while (prev && *(filter_ptr = av_filter_next(filter_ptr)))
 +        if ((*filter_ptr)->priv_class == prev)
 +            break;
 +
 +    /* could not find filter corresponding to prev */
 +    if (prev && !(*filter_ptr))
 +        return NULL;
 +
 +    /* find next filter with specific options */
 +    while (*(filter_ptr = av_filter_next(filter_ptr)))
 +        if ((*filter_ptr)->priv_class)
 +            return (*filter_ptr)->priv_class;
 +    return NULL;
  }
  
  static const AVClass avfilter_class = {
      .class_name = "AVFilter",
 -    .item_name  = filter_name,
 +    .item_name  = default_filter_name,
      .version    = LIBAVUTIL_VERSION_INT,
 +    .category   = AV_CLASS_CATEGORY_FILTER,
 +    .child_next = filter_child_next,
 +    .child_class_next = filter_child_class_next,
  };
  
 +const AVClass *avfilter_get_class(void)
 +{
 +    return &avfilter_class;
 +}
 +
  int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name)
  {
      AVFilterContext *ret;
@@@ -567,9 -399,6 +567,9 @@@ void avfilter_free(AVFilterContext *fil
      int i;
      AVFilterLink *link;
  
 +    if (!filter)
 +        return;
 +
      if (filter->filter->uninit)
          filter->filter->uninit(filter);
  
              ff_channel_layouts_unref(&link->in_channel_layouts);
              ff_channel_layouts_unref(&link->out_channel_layouts);
          }
 -        av_freep(&link);
 +        avfilter_link_free(&link);
      }
      for (i = 0; i < filter->nb_outputs; i++) {
          if ((link = filter->outputs[i])) {
              ff_channel_layouts_unref(&link->in_channel_layouts);
              ff_channel_layouts_unref(&link->out_channel_layouts);
          }
 -        av_freep(&link);
 +        avfilter_link_free(&link);
      }
  
 -    if (filter->filter->priv_class)
 +    if (filter->filter->priv_class || filter->filter->shorthand)
          av_opt_free(filter->priv);
  
      av_freep(&filter->name);
      av_freep(&filter->inputs);
      av_freep(&filter->outputs);
      av_freep(&filter->priv);
 +    while(filter->command_queue){
 +        ff_command_queue_pop(filter);
 +    }
      av_free(filter);
  }
  
@@@ -623,7 -449,6 +623,7 @@@ static int process_unnamed_options(AVFi
      const AVOption *o = NULL;
      const char *p = args;
      char *val;
 +    int offset= -1;
  
      while (*p) {
          o = av_opt_next(ctx->priv, o);
                     "this filter supports.\n");
              return AVERROR(EINVAL);
          }
 -        if (o->type == AV_OPT_TYPE_CONST)
 +        if (o->type == AV_OPT_TYPE_CONST || o->offset == offset)
              continue;
 +        offset = o->offset;
  
          val = av_get_token(&p, ":");
          if (!val)
@@@ -655,104 -479,8 +655,105 @@@ int avfilter_init_filter(AVFilterContex
      AVDictionary *options = NULL;
      AVDictionaryEntry *e;
      int ret=0;
 +    int anton_options =
 +        !strcmp(filter->filter->name,  "allpass"   ) ||
 +        !strcmp(filter->filter->name,  "afade"     ) ||
 +        !strcmp(filter->filter->name,  "aformat") ||
 +        !strcmp(filter->filter->name,  "amix"      ) ||
 +        !strcmp(filter->filter->name,  "apad"      ) ||
 +        !strcmp(filter->filter->name,  "aphaser"   ) ||
 +        !strcmp(filter->filter->name,  "asplit"    ) ||
 +        !strcmp(filter->filter->name,  "ass")     ||
 +        !strcmp(filter->filter->name,  "asyncts"   ) ||
 +        !strcmp(filter->filter->name,  "bandpass"  ) ||
 +        !strcmp(filter->filter->name,  "bandreject") ||
 +        !strcmp(filter->filter->name,  "bass"      ) ||
 +        !strcmp(filter->filter->name,  "biquad"    ) ||
 +        !strcmp(filter->filter->name,  "blackframe") ||
 +        !strcmp(filter->filter->name,  "blend"     ) ||
 +        !strcmp(filter->filter->name,  "boxblur"   ) ||
 +        !strcmp(filter->filter->name,  "cellauto") ||
 +        !strcmp(filter->filter->name,  "channelmap") ||
 +        !strcmp(filter->filter->name,  "channelsplit") ||
++        !strcmp(filter->filter->name,  "color"     ) ||
 +        !strcmp(filter->filter->name,  "colormatrix") ||
 +        !strcmp(filter->filter->name,  "crop"      ) ||
 +        !strcmp(filter->filter->name,  "cropdetect") ||
 +        !strcmp(filter->filter->name,  "curves"    ) ||
 +        !strcmp(filter->filter->name,  "decimate"  ) ||
 +        !strcmp(filter->filter->name,  "delogo"    ) ||
 +        !strcmp(filter->filter->name,  "drawbox"   ) ||
 +        !strcmp(filter->filter->name,  "drawtext"  ) ||
 +        !strcmp(filter->filter->name,  "ebur128"   ) ||
 +        !strcmp(filter->filter->name,  "edgedetect") ||
 +        !strcmp(filter->filter->name,  "equalizer" ) ||
 +        !strcmp(filter->filter->name,  "fade"      ) ||
 +        !strcmp(filter->filter->name,  "field"     ) ||
 +        !strcmp(filter->filter->name,  "fieldorder") ||
 +        !strcmp(filter->filter->name,  "fps"       ) ||
 +        !strcmp(filter->filter->name,  "framestep" ) ||
 +        !strcmp(filter->filter->name,  "frei0r"    ) ||
 +        !strcmp(filter->filter->name,  "frei0r_src") ||
 +        !strcmp(filter->filter->name,  "geq"       ) ||
 +        !strcmp(filter->filter->name, "gradfun"    ) ||
 +        !strcmp(filter->filter->name, "highpass"  ) ||
 +        !strcmp(filter->filter->name, "histeq"     ) ||
 +        !strcmp(filter->filter->name, "histogram"  ) ||
 +        !strcmp(filter->filter->name, "hqdn3d"     ) ||
 +        !strcmp(filter->filter->name, "idet"       ) ||
 +        !strcmp(filter->filter->name,  "il"        ) ||
 +        !strcmp(filter->filter->name,  "join"      ) ||
 +        !strcmp(filter->filter->name,  "kerndeint" ) ||
 +        !strcmp(filter->filter->name, "ocv"        ) ||
 +        !strcmp(filter->filter->name, "life"       ) ||
 +        !strcmp(filter->filter->name, "lut"        ) ||
 +        !strcmp(filter->filter->name, "lutyuv"     ) ||
 +        !strcmp(filter->filter->name, "lutrgb"     ) ||
 +        !strcmp(filter->filter->name, "lowpass"   ) ||
 +        !strcmp(filter->filter->name, "mandelbrot" ) ||
 +        !strcmp(filter->filter->name, "mptestsrc"  ) ||
 +        !strcmp(filter->filter->name, "negate"     ) ||
 +        !strcmp(filter->filter->name, "noise"      ) ||
 +        !strcmp(filter->filter->name, "overlay"    ) ||
 +        !strcmp(filter->filter->name, "pad"        ) ||
 +        !strcmp(filter->filter->name,   "format") ||
 +        !strcmp(filter->filter->name, "noformat") ||
 +        !strcmp(filter->filter->name, "perms")  ||
 +        !strcmp(filter->filter->name, "pp"   )  ||
 +        !strcmp(filter->filter->name, "aperms") ||
 +        !strcmp(filter->filter->name, "resample") ||
 +        !strcmp(filter->filter->name, "setpts"       ) ||
 +        !strcmp(filter->filter->name, "settb"        ) ||
 +        !strcmp(filter->filter->name, "showspectrum") ||
 +        !strcmp(filter->filter->name, "silencedetect") ||
 +        !strcmp(filter->filter->name, "smartblur") ||
 +        !strcmp(filter->filter->name, "split"    ) ||
 +        !strcmp(filter->filter->name, "stereo3d" ) ||
 +        !strcmp(filter->filter->name, "subtitles") ||
 +        !strcmp(filter->filter->name, "thumbnail") ||
 +        !strcmp(filter->filter->name, "transpose") ||
 +        !strcmp(filter->filter->name, "treble"    ) ||
 +        !strcmp(filter->filter->name, "unsharp"  ) ||
 +//         !strcmp(filter->filter->name, "scale"      ) ||
 +        !strcmp(filter->filter->name, "select") ||
 +        !strcmp(filter->filter->name, "volume"   ) ||
 +        !strcmp(filter->filter->name, "yadif"    ) ||
 +        0
 +        ;
 +
 +    if (filter->filter->shorthand) {
 +        av_assert0(filter->priv);
 +        av_assert0(filter->filter->priv_class);
 +        *(const AVClass **)filter->priv = filter->filter->priv_class;
 +        av_opt_set_defaults(filter->priv);
 +        ret = av_opt_set_from_string(filter->priv, args,
 +                                     filter->filter->shorthand, "=", ":");
 +        if (ret < 0)
 +            return ret;
 +        args = NULL;
 +    }
  
 -    if (args && *args && filter->filter->priv_class) {
 +    if (anton_options && args && *args && filter->filter->priv_class) {
  #if FF_API_OLD_FILTER_OPTS
          if (!strcmp(filter->filter->name, "scale") &&
              strchr(args, ':') < strchr(args, '=')) {
          }
      }
  
 -    if (filter->filter->priv_class) {
 +    if (anton_options && filter->filter->priv_class) {
          ret = av_opt_set_dict(filter->priv, &options);
          if (ret < 0) {
              av_log(filter, AV_LOG_ERROR, "Error applying options to the filter.\n");
          }
      }
  
 -    if (filter->filter->init)
 +    if (filter->filter->init_opaque)
 +        ret = filter->filter->init_opaque(filter, args, opaque);
 +    else if (filter->filter->init)
          ret = filter->filter->init(filter, args);
      else if (filter->filter->init_dict)
          ret = filter->filter->init_dict(filter, &options);
@@@ -885,19 -611,14 +886,19 @@@ static int default_filter_frame(AVFilte
      return ff_filter_frame(link->dst->outputs[0], frame);
  }
  
 -int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
 +static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
  {
      int (*filter_frame)(AVFilterLink *, AVFrame *);
      AVFilterPad *dst = link->dstpad;
      AVFrame *out;
 +    int ret;
 +    AVFilterCommand *cmd= link->dst->command_queue;
 +    int64_t pts;
  
 -    FF_DPRINTF_START(NULL, filter_frame);
 -    ff_dlog_link(NULL, link, 1);
 +    if (link->closed) {
 +        av_frame_free(&frame);
 +        return AVERROR_EOF;
 +    }
  
      if (!(filter_frame = dst->filter_frame))
          filter_frame = default_filter_frame;
      if (dst->needs_writable && !av_frame_is_writable(frame)) {
          av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n");
  
 +        /* Maybe use ff_copy_buffer_ref instead? */
          switch (link->type) {
          case AVMEDIA_TYPE_VIDEO:
              out = ff_get_video_buffer(link, link->w, link->h);
  
          switch (link->type) {
          case AVMEDIA_TYPE_VIDEO:
 -            av_image_copy(out->data, out->linesize, frame->data, frame->linesize,
 +            av_image_copy(out->data, out->linesize, (const uint8_t **)frame->data, frame->linesize,
                            frame->format, frame->width, frame->height);
              break;
          case AVMEDIA_TYPE_AUDIO:
      } else
          out = frame;
  
 -    return filter_frame(link, out);
 +    while(cmd && cmd->time <= out->pts * av_q2d(link->time_base)){
 +        av_log(link->dst, AV_LOG_DEBUG,
 +               "Processing command time:%f command:%s arg:%s\n",
 +               cmd->time, cmd->command, cmd->arg);
 +        avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags);
 +        ff_command_queue_pop(link->dst);
 +        cmd= link->dst->command_queue;
 +    }
 +
 +    pts = out->pts;
 +    ret = filter_frame(link, out);
 +    link->frame_requested = 0;
 +    ff_update_link_current_pts(link, pts);
 +    return ret;
 +}
 +
 +static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
 +{
 +    int insamples = frame->nb_samples, inpos = 0, nb_samples;
 +    AVFrame *pbuf = link->partial_buf;
 +    int nb_channels = av_frame_get_channels(frame);
 +    int ret = 0;
 +
 +    link->flags |= FF_LINK_FLAG_REQUEST_LOOP;
 +    /* Handle framing (min_samples, max_samples) */
 +    while (insamples) {
 +        if (!pbuf) {
 +            AVRational samples_tb = { 1, link->sample_rate };
 +            pbuf = ff_get_audio_buffer(link, link->partial_buf_size);
 +            if (!pbuf) {
 +                av_log(link->dst, AV_LOG_WARNING,
 +                       "Samples dropped due to memory allocation failure.\n");
 +                return 0;
 +            }
 +            av_frame_copy_props(pbuf, frame);
 +            pbuf->pts = frame->pts +
 +                        av_rescale_q(inpos, samples_tb, link->time_base);
 +            pbuf->nb_samples = 0;
 +        }
 +        nb_samples = FFMIN(insamples,
 +                           link->partial_buf_size - pbuf->nb_samples);
 +        av_samples_copy(pbuf->extended_data, frame->extended_data,
 +                        pbuf->nb_samples, inpos,
 +                        nb_samples, nb_channels, link->format);
 +        inpos                   += nb_samples;
 +        insamples               -= nb_samples;
 +        pbuf->nb_samples += nb_samples;
 +        if (pbuf->nb_samples >= link->min_samples) {
 +            ret = ff_filter_frame_framed(link, pbuf);
 +            pbuf = NULL;
 +        }
 +    }
 +    av_frame_free(&frame);
 +    link->partial_buf = pbuf;
 +    return ret;
 +}
 +
 +int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
 +{
 +    FF_TPRINTF_START(NULL, filter_frame); ff_tlog_link(NULL, link, 1); ff_tlog(NULL, " "); ff_tlog_ref(NULL, frame, 1);
 +
 +    /* Consistency checks */
 +    if (link->type == AVMEDIA_TYPE_VIDEO) {
 +        if (strcmp(link->dst->filter->name, "scale")) {
 +            av_assert1(frame->format                 == link->format);
 +            av_assert1(frame->width               == link->w);
 +            av_assert1(frame->height               == link->h);
 +        }
 +    } else {
 +        av_assert1(frame->format                == link->format);
 +        av_assert1(av_frame_get_channels(frame) == link->channels);
 +        av_assert1(frame->channel_layout        == link->channel_layout);
 +        av_assert1(frame->sample_rate           == link->sample_rate);
 +    }
 +
 +    /* Go directly to actual filtering if possible */
 +    if (link->type == AVMEDIA_TYPE_AUDIO &&
 +        link->min_samples &&
 +        (link->partial_buf ||
 +         frame->nb_samples < link->min_samples ||
 +         frame->nb_samples > link->max_samples)) {
 +        return ff_filter_frame_needs_framing(link, frame);
 +    } else {
 +        return ff_filter_frame_framed(link, frame);
 +    }
  }
@@@ -1,22 -1,21 +1,22 @@@
  /*
   * Copyright (c) 2007 Nicolas George <nicolas.george@normalesup.org>
   * Copyright (c) 2011 Stefano Sabatini
 + * Copyright (c) 2012 Paul B Mahol
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
   *
   * rgbtestsrc is ported from MPlayer libmpcodecs/vf_rgbtest.c by
   * Michael Niedermayer.
 + *
 + * smptebars is by Paul B Mahol.
   */
  
  #include <float.h>
  
 +#include "libavutil/avassert.h"
  #include "libavutil/common.h"
 -#include "libavutil/mathematics.h"
  #include "libavutil/opt.h"
 +#include "libavutil/imgutils.h"
  #include "libavutil/intreadwrite.h"
  #include "libavutil/parseutils.h"
  #include "avfilter.h"
 +#include "drawutils.h"
  #include "formats.h"
  #include "internal.h"
  #include "video.h"
  
  typedef struct {
      const AVClass *class;
 -    int h, w;
 +    int w, h;
      unsigned int nb_frame;
 -    AVRational time_base;
 -    int64_t pts, max_pts;
 -    char *size;                 ///< video frame size
 -    char *rate;                 ///< video frame rate
 -    char *duration;             ///< total duration of the generated video
 +    AVRational time_base, frame_rate;
 +    int64_t pts;
 +    char *duration_str;         ///< total duration of the generated video
 +    int64_t duration;           ///< duration expressed in microseconds
      AVRational sar;             ///< sample aspect ratio
 +    int nb_decimals;
 +    int draw_once;              ///< draw only the first frame, always put out the same picture
 +    AVFrame *picref;            ///< cached reference containing the painted picture
  
      void (* fill_picture_fn)(AVFilterContext *ctx, AVFrame *frame);
  
 +    /* only used by color */
 +    char *color_str;
 +    FFDrawContext draw;
 +    FFDrawColor color;
 +    uint8_t color_rgba[4];
 +
      /* only used by rgbtest */
 -    int rgba_map[4];
 +    uint8_t rgba_map[4];
  } TestSourceContext;
  
  #define OFFSET(x) offsetof(TestSourceContext, x)
- static const AVOption options[] = {
-     { "size",     "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },
-     { "s",        "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },
-     { "rate",     "set video rate",     OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
-     { "r",        "set video rate",     OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
-     { "duration", "set video duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str = NULL},   0, 0, FLAGS },
-     { "d",        "set video duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str = NULL},   0, 0, FLAGS },
 +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
 +
-     { "color", "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
-     { "c",     "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
++#define COMMON_OPTIONS \
++    { "size",     "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
++    { "s",        "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
++    { "rate",     "set video rate",     OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
++    { "r",        "set video rate",     OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
++    { "duration", "set video duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str = NULL},   0, 0, FLAGS },\
++    { "d",        "set video duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str = NULL},   0, 0, FLAGS },\
 +    { "sar",      "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl= 1},  0, INT_MAX, FLAGS },
 +
++
++static const AVOption color_options[] = {
 +    /* only used by color */
 -static const AVOption testsrc_options[] = {
 -    { "size",     "set video size",     OFFSET(size),     AV_OPT_TYPE_STRING, {.str = "320x240"}},
 -    { "s",        "set video size",     OFFSET(size),     AV_OPT_TYPE_STRING, {.str = "320x240"}},
 -    { "rate",     "set video rate",     OFFSET(rate),     AV_OPT_TYPE_STRING, {.str = "25"},    },
 -    { "r",        "set video rate",     OFFSET(rate),     AV_OPT_TYPE_STRING, {.str = "25"},    },
 -    { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_STRING, {.str = NULL},    },
 -    { "sar",      "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl = 1},  0, INT_MAX },
++    { "color", "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
++    { "c",     "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
 +
++    COMMON_OPTIONS
++    { NULL },
++};
++
++static const AVOption options[] = {
 +    /* only used by testsrc */
 +    { "decimals", "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.i64=0},  0, 17, FLAGS },
 +    { "n",        "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.i64=0},  0, 17, FLAGS },
++    COMMON_OPTIONS
      { NULL },
  };
  
 -static av_cold int init_common(AVFilterContext *ctx, const char *args)
 +static av_cold int init(AVFilterContext *ctx, const char *args)
  {
      TestSourceContext *test = ctx->priv;
 -    AVRational frame_rate_q;
 -    int64_t duration = -1;
      int ret = 0;
  
--    av_opt_set_defaults(test);
--
 -    if ((ret = (av_set_options_string(test, args, "=", ":"))) < 0) {
 -        av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
 +    if ((ret = (av_set_options_string(test, args, "=", ":"))) < 0)
          return ret;
 -    }
  
 -    if ((ret = av_parse_video_size(&test->w, &test->h, test->size)) < 0) {
 -        av_log(ctx, AV_LOG_ERROR, "Invalid frame size: '%s'\n", test->size);
 +    test->duration = -1;
 +    if (test->duration_str &&
 +        (ret = av_parse_time(&test->duration, test->duration_str, 1)) < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Invalid duration: '%s'\n", test->duration_str);
          return ret;
      }
  
 -    if ((ret = av_parse_video_rate(&frame_rate_q, test->rate)) < 0 ||
 -        frame_rate_q.den <= 0 || frame_rate_q.num <= 0) {
 -        av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", test->rate);
 -        return ret;
 +    if (test->nb_decimals && strcmp(ctx->filter->name, "testsrc")) {
 +        av_log(ctx, AV_LOG_WARNING,
 +               "Option 'decimals' is ignored with source '%s'\n",
 +               ctx->filter->name);
      }
  
 -    if ((test->duration) && (ret = av_parse_time(&duration, test->duration, 1)) < 0) {
 -        av_log(ctx, AV_LOG_ERROR, "Invalid duration: '%s'\n", test->duration);
 -        return ret;
 +    if (test->color_str) {
 +        if (!strcmp(ctx->filter->name, "color")) {
 +            ret = av_parse_color(test->color_rgba, test->color_str, -1, ctx);
 +            if (ret < 0)
 +                return ret;
 +        } else {
 +            av_log(ctx, AV_LOG_WARNING,
 +                   "Option 'color' is ignored with source '%s'\n",
 +                   ctx->filter->name);
 +        }
      }
  
 -    test->time_base.num = frame_rate_q.den;
 -    test->time_base.den = frame_rate_q.num;
 -    test->max_pts = duration >= 0 ?
 -        av_rescale_q(duration, AV_TIME_BASE_Q, test->time_base) : -1;
 +    test->time_base = av_inv_q(test->frame_rate);
      test->nb_frame = 0;
      test->pts = 0;
  
 -    av_log(ctx, AV_LOG_DEBUG, "size:%dx%d rate:%d/%d duration:%f sar:%d/%d\n",
 -           test->w, test->h, frame_rate_q.num, frame_rate_q.den,
 -           duration < 0 ? -1 : test->max_pts * av_q2d(test->time_base),
 +    av_log(ctx, AV_LOG_VERBOSE, "size:%dx%d rate:%d/%d duration:%f sar:%d/%d\n",
 +           test->w, test->h, test->frame_rate.num, test->frame_rate.den,
 +           test->duration < 0 ? -1 : (double)test->duration/1000000,
             test->sar.num, test->sar.den);
      return 0;
  }
  
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    TestSourceContext *test = ctx->priv;
 +
 +    av_opt_free(test);
 +    av_frame_free(&test->picref);
 +}
 +
  static int config_props(AVFilterLink *outlink)
  {
      TestSourceContext *test = outlink->src->priv;
      outlink->w = test->w;
      outlink->h = test->h;
      outlink->sample_aspect_ratio = test->sar;
 -    outlink->time_base = test->time_base;
 +    outlink->frame_rate = test->frame_rate;
 +    outlink->time_base  = test->time_base;
  
      return 0;
  }
@@@ -166,159 -132,36 +173,157 @@@ static int request_frame(AVFilterLink *
      TestSourceContext *test = outlink->src->priv;
      AVFrame *frame;
  
 -    if (test->max_pts >= 0 && test->pts > test->max_pts)
 +    if (test->duration >= 0 &&
 +        av_rescale_q(test->pts, test->time_base, AV_TIME_BASE_Q) >= test->duration)
          return AVERROR_EOF;
 -    frame = ff_get_video_buffer(outlink, test->w, test->h);
 +
 +    if (test->draw_once) {
 +        if (!test->picref) {
 +            test->picref =
 +                ff_get_video_buffer(outlink, test->w, test->h);
 +            if (!test->picref)
 +                return AVERROR(ENOMEM);
 +            test->fill_picture_fn(outlink->src, test->picref);
 +        }
 +        frame = av_frame_clone(test->picref);
 +    } else
 +        frame = ff_get_video_buffer(outlink, test->w, test->h);
 +
      if (!frame)
          return AVERROR(ENOMEM);
 -
 -    frame->pts                 = test->pts++;
 +    frame->pts                 = test->pts;
      frame->key_frame           = 1;
      frame->interlaced_frame    = 0;
      frame->pict_type           = AV_PICTURE_TYPE_I;
      frame->sample_aspect_ratio = test->sar;
 +    if (!test->draw_once)
 +        test->fill_picture_fn(outlink->src, frame);
 +
 +    test->pts++;
      test->nb_frame++;
 -    test->fill_picture_fn(outlink->src, frame);
  
      return ff_filter_frame(outlink, frame);
  }
  
 -#if CONFIG_TESTSRC_FILTER
 +#if CONFIG_COLOR_FILTER
 +
- #define color_options options
 +AVFILTER_DEFINE_CLASS(color);
  
 -static const char *testsrc_get_name(void *ctx)
 +static void color_fill_picture(AVFilterContext *ctx, AVFrame *picref)
  {
 -    return "testsrc";
 +    TestSourceContext *test = ctx->priv;
 +    ff_fill_rectangle(&test->draw, &test->color,
 +                      picref->data, picref->linesize,
 +                      0, 0, test->w, test->h);
 +}
 +
 +static av_cold int color_init(AVFilterContext *ctx, const char *args)
 +{
 +    TestSourceContext *test = ctx->priv;
-     test->class = &color_class;
 +    test->fill_picture_fn = color_fill_picture;
 +    test->draw_once = 1;
-     av_opt_set(test, "color", "black", 0);
-     return init(ctx, args);
++    return init(ctx, NULL);
 +}
 +
 +static int color_query_formats(AVFilterContext *ctx)
 +{
 +    ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
 +    return 0;
  }
  
 -static const AVClass testsrc_class = {
 -    .class_name = "TestSourceContext",
 -    .item_name  = testsrc_get_name,
 -    .option     = testsrc_options,
 +static int color_config_props(AVFilterLink *inlink)
 +{
 +    AVFilterContext *ctx = inlink->src;
 +    TestSourceContext *test = ctx->priv;
 +    int ret;
 +
 +    ff_draw_init(&test->draw, inlink->format, 0);
 +    ff_draw_color(&test->draw, &test->color, test->color_rgba);
 +
 +    test->w = ff_draw_round_to_sub(&test->draw, 0, -1, test->w);
 +    test->h = ff_draw_round_to_sub(&test->draw, 1, -1, test->h);
 +    if (av_image_check_size(test->w, test->h, 0, ctx) < 0)
 +        return AVERROR(EINVAL);
 +
 +    if ((ret = config_props(inlink)) < 0)
 +        return ret;
 +
 +    av_log(ctx, AV_LOG_VERBOSE, "color:0x%02x%02x%02x%02x\n",
 +           test->color_rgba[0], test->color_rgba[1], test->color_rgba[2], test->color_rgba[3]);
 +    return 0;
 +}
 +
 +static const AVFilterPad color_outputs[] = {
 +    {
 +        .name          = "default",
 +        .type          = AVMEDIA_TYPE_VIDEO,
 +        .request_frame = request_frame,
 +        .config_props  = color_config_props,
 +    },
 +    {  NULL }
 +};
 +
 +AVFilter avfilter_vsrc_color = {
 +    .name        = "color",
 +    .description = NULL_IF_CONFIG_SMALL("Provide an uniformly colored input."),
 +
++    .priv_class = &color_class,
 +    .priv_size = sizeof(TestSourceContext),
 +    .init      = color_init,
 +    .uninit    = uninit,
 +
 +    .query_formats = color_query_formats,
 +    .inputs        = NULL,
 +    .outputs       = color_outputs,
-     .priv_class    = &color_class,
 +};
 +
 +#endif /* CONFIG_COLOR_FILTER */
 +
 +#if CONFIG_NULLSRC_FILTER
 +
 +#define nullsrc_options options
 +AVFILTER_DEFINE_CLASS(nullsrc);
 +
 +static void nullsrc_fill_picture(AVFilterContext *ctx, AVFrame *picref) { }
 +
 +static av_cold int nullsrc_init(AVFilterContext *ctx, const char *args)
 +{
 +    TestSourceContext *test = ctx->priv;
 +
 +    test->class = &nullsrc_class;
 +    test->fill_picture_fn = nullsrc_fill_picture;
++    av_opt_set_defaults(test);
 +    return init(ctx, args);
 +}
 +
 +static const AVFilterPad nullsrc_outputs[] = {
 +    {
 +        .name          = "default",
 +        .type          = AVMEDIA_TYPE_VIDEO,
 +        .request_frame = request_frame,
 +        .config_props  = config_props,
 +    },
 +    { NULL },
 +};
 +
 +AVFilter avfilter_vsrc_nullsrc = {
 +    .name        = "nullsrc",
 +    .description = NULL_IF_CONFIG_SMALL("Null video source, return unprocessed video frames."),
 +    .init       = nullsrc_init,
 +    .uninit     = uninit,
 +    .priv_size  = sizeof(TestSourceContext),
 +    .inputs     = NULL,
 +    .outputs    = nullsrc_outputs,
 +    .priv_class = &nullsrc_class,
  };
  
 +#endif /* CONFIG_NULLSRC_FILTER */
 +
 +#if CONFIG_TESTSRC_FILTER
 +
 +#define testsrc_options options
 +AVFILTER_DEFINE_CLASS(testsrc);
 +
  /**
   * Fill a rectangle with value val.
   *
@@@ -441,7 -284,7 +446,7 @@@ static void test_fill_picture(AVFilterC
      }
  
      /* draw sliding color line */
 -    p = data + frame->linesize[0] * height * 3/4;
 +    p0 = p = data + frame->linesize[0] * height * 3/4;
      grad = (256 * test->nb_frame * test->time_base.num / test->time_base.den) %
          GRADIENT_SIZE;
      rgrad = 0;
          if (grad >= GRADIENT_SIZE)
              grad -= GRADIENT_SIZE;
      }
 +    p = p0;
      for (y = height / 8; y > 0; y--) {
 -        memcpy(p, p - frame->linesize[0], 3 * width);
 +        memcpy(p+frame->linesize[0], p, 3 * width);
          p += frame->linesize[0];
      }
  
      /* draw digits */
      seg_size = width / 80;
      if (seg_size >= 1 && height >= 13 * seg_size) {
 -        second = test->nb_frame * test->time_base.num / test->time_base.den;
 +        int64_t p10decimals = 1;
 +        double time = av_q2d(test->time_base) * test->nb_frame *
 +                      pow(10, test->nb_decimals);
 +        if (time >= INT_MAX)
 +            return;
 +
 +        for(x=0; x<test->nb_decimals; x++)
 +            p10decimals *= 10;
 +
 +        second = av_rescale_rnd(test->nb_frame * test->time_base.num, p10decimals, test->time_base.den, AV_ROUND_ZERO);
          x = width - (width - seg_size * 64) / 2;
          y = (height - seg_size * 13) / 2;
          p = data + (x*3 + y * frame->linesize[0]);
@@@ -507,7 -340,7 +512,8 @@@ static av_cold int test_init(AVFilterCo
  
      test->class = &testsrc_class;
      test->fill_picture_fn = test_fill_picture;
 -    return init_common(ctx, args);
++    av_opt_set_defaults(test);
 +    return init(ctx, args);
  }
  
  static int test_query_formats(AVFilterContext *ctx)
@@@ -530,25 -363,32 +536,25 @@@ static const AVFilterPad avfilter_vsrc_
  };
  
  AVFilter avfilter_vsrc_testsrc = {
 -    .name          = "testsrc",
 -    .description   = NULL_IF_CONFIG_SMALL("Generate test pattern."),
 -    .priv_size     = sizeof(TestSourceContext),
 -    .init          = test_init,
 +    .name      = "testsrc",
 +    .description = NULL_IF_CONFIG_SMALL("Generate test pattern."),
 +    .priv_size = sizeof(TestSourceContext),
 +    .init      = test_init,
 +    .uninit    = uninit,
  
 -    .query_formats = test_query_formats,
 +    .query_formats   = test_query_formats,
  
      .inputs    = NULL,
 -
      .outputs   = avfilter_vsrc_testsrc_outputs,
 +    .priv_class = &testsrc_class,
  };
  
  #endif /* CONFIG_TESTSRC_FILTER */
  
  #if CONFIG_RGBTESTSRC_FILTER
  
 -static const char *rgbtestsrc_get_name(void *ctx)
 -{
 -    return "rgbtestsrc";
 -}
 -
 -static const AVClass rgbtestsrc_class = {
 -    .class_name = "RGBTestSourceContext",
 -    .item_name  = rgbtestsrc_get_name,
 -    .option     = testsrc_options,
 -};
 +#define rgbtestsrc_options options
 +AVFILTER_DEFINE_CLASS(rgbtestsrc);
  
  #define R 0
  #define G 1
  
  static void rgbtest_put_pixel(uint8_t *dst, int dst_linesize,
                                int x, int y, int r, int g, int b, enum AVPixelFormat fmt,
 -                              int rgba_map[4])
 +                              uint8_t rgba_map[4])
  {
      int32_t v;
      uint8_t *p;
      case AV_PIX_FMT_BGRA:
      case AV_PIX_FMT_ARGB:
      case AV_PIX_FMT_ABGR:
 -        v = (r << (rgba_map[R]*8)) + (g << (rgba_map[G]*8)) + (b << (rgba_map[B]*8));
 +        v = (r << (rgba_map[R]*8)) + (g << (rgba_map[G]*8)) + (b << (rgba_map[B]*8)) + (255 << (rgba_map[A]*8));
          p = dst + 4*x + y*dst_linesize;
          AV_WL32(p, v);
          break;
@@@ -610,10 -450,9 +616,11 @@@ static av_cold int rgbtest_init(AVFilte
  {
      TestSourceContext *test = ctx->priv;
  
 +    test->draw_once = 1;
      test->class = &rgbtestsrc_class;
      test->fill_picture_fn = rgbtest_fill_picture;
 -    return init_common(ctx, args);
++    av_opt_set_defaults(test);
 +    return init(ctx, args);
  }
  
  static int rgbtest_query_formats(AVFilterContext *ctx)
@@@ -634,7 -473,15 +641,7 @@@ static int rgbtest_config_props(AVFilte
  {
      TestSourceContext *test = outlink->src->priv;
  
 -    switch (outlink->format) {
 -    case AV_PIX_FMT_ARGB:  test->rgba_map[A] = 0; test->rgba_map[R] = 1; test->rgba_map[G] = 2; test->rgba_map[B] = 3; break;
 -    case AV_PIX_FMT_ABGR:  test->rgba_map[A] = 0; test->rgba_map[B] = 1; test->rgba_map[G] = 2; test->rgba_map[R] = 3; break;
 -    case AV_PIX_FMT_RGBA:
 -    case AV_PIX_FMT_RGB24: test->rgba_map[R] = 0; test->rgba_map[G] = 1; test->rgba_map[B] = 2; test->rgba_map[A] = 3; break;
 -    case AV_PIX_FMT_BGRA:
 -    case AV_PIX_FMT_BGR24: test->rgba_map[B] = 0; test->rgba_map[G] = 1; test->rgba_map[R] = 2; test->rgba_map[A] = 3; break;
 -    }
 -
 +    ff_fill_rgba_map(test->rgba_map, outlink->format);
      return config_props(outlink);
  }
  
@@@ -649,161 -496,16 +656,162 @@@ static const AVFilterPad avfilter_vsrc_
  };
  
  AVFilter avfilter_vsrc_rgbtestsrc = {
 -    .name          = "rgbtestsrc",
 -    .description   = NULL_IF_CONFIG_SMALL("Generate RGB test pattern."),
 -    .priv_size     = sizeof(TestSourceContext),
 -    .init          = rgbtest_init,
 +    .name      = "rgbtestsrc",
 +    .description = NULL_IF_CONFIG_SMALL("Generate RGB test pattern."),
 +    .priv_size = sizeof(TestSourceContext),
 +    .init      = rgbtest_init,
 +    .uninit    = uninit,
  
 -    .query_formats = rgbtest_query_formats,
 +    .query_formats   = rgbtest_query_formats,
  
      .inputs    = NULL,
  
      .outputs   = avfilter_vsrc_rgbtestsrc_outputs,
 +    .priv_class = &rgbtestsrc_class,
  };
  
  #endif /* CONFIG_RGBTESTSRC_FILTER */
 +
 +#if CONFIG_SMPTEBARS_FILTER
 +
 +#define smptebars_options options
 +AVFILTER_DEFINE_CLASS(smptebars);
 +
 +static const uint8_t rainbow[7][4] = {
 +    { 191, 191, 191, 255 },     /* gray */
 +    { 191, 191,   0, 255 },     /* yellow */
 +    {   0, 191, 191, 255 },     /* cyan */
 +    {   0, 191,   0, 255 },     /* green */
 +    { 191,   0, 191, 255 },     /* magenta */
 +    { 191,   0,   0, 255 },     /* red */
 +    {   0,   0, 191, 255 },     /* blue */
 +};
 +
 +static const uint8_t wobnair[7][4] = {
 +    {   0,   0, 191, 255 },     /* blue */
 +    {  19,  19,  19, 255 },     /* 7.5% intensity black */
 +    { 191,   0, 191, 255 },     /* magenta */
 +    {  19,  19,  19, 255 },     /* 7.5% intensity black */
 +    {   0, 191, 191, 255 },     /* cyan */
 +    {  19,  19,  19, 255 },     /* 7.5% intensity black */
 +    { 191, 191, 191, 255 },     /* gray */
 +};
 +
 +static const uint8_t white[4] = { 255, 255, 255, 255 };
 +static const uint8_t black[4] = {  19,  19,  19, 255 }; /* 7.5% intensity black */
 +
 +/* pluge pulses */
 +static const uint8_t neg4ire[4] = {   9,   9,   9, 255 }; /*  3.5% intensity black */
 +static const uint8_t pos4ire[4] = {  29,  29,  29, 255 }; /* 11.5% intensity black */
 +
 +/* fudged Q/-I */
 +static const uint8_t i_pixel[4] = {   0,  68, 130, 255 };
 +static const uint8_t q_pixel[4] = {  67,   0, 130, 255 };
 +
 +static void inline draw_bar(TestSourceContext *test, const uint8_t *color,
 +                            unsigned x, unsigned y, unsigned w, unsigned h,
 +                            AVFrame *frame)
 +{
 +    FFDrawColor draw_color;
 +
 +    x = FFMIN(x, test->w - 1);
 +    y = FFMIN(y, test->h - 1);
 +    w = FFMIN(w, test->w - x);
 +    h = FFMIN(h, test->h - y);
 +
 +    av_assert0(x + w <= test->w);
 +    av_assert0(y + h <= test->h);
 +
 +    ff_draw_color(&test->draw, &draw_color, color);
 +    ff_fill_rectangle(&test->draw, &draw_color,
 +                      frame->data, frame->linesize, x, y, w, h);
 +}
 +
 +static void smptebars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
 +{
 +    TestSourceContext *test = ctx->priv;
 +    int r_w, r_h, w_h, p_w, p_h, i, tmp, x = 0;
 +    const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format);
 +
 +    r_w = FFALIGN((test->w + 6) / 7, 1 << pixdesc->log2_chroma_w);
 +    r_h = FFALIGN(test->h * 2 / 3, 1 << pixdesc->log2_chroma_h);
 +    w_h = FFALIGN(test->h * 3 / 4 - r_h,  1 << pixdesc->log2_chroma_h);
 +    p_w = FFALIGN(r_w * 5 / 4, 1 << pixdesc->log2_chroma_w);
 +    p_h = test->h - w_h - r_h;
 +
 +    for (i = 0; i < 7; i++) {
 +        draw_bar(test, rainbow[i], x, 0,   r_w, r_h, picref);
 +        draw_bar(test, wobnair[i], x, r_h, r_w, w_h, picref);
 +        x += r_w;
 +    }
 +    x = 0;
 +    draw_bar(test, i_pixel, x, r_h + w_h, p_w, p_h, picref);
 +    x += p_w;
 +    draw_bar(test, white, x, r_h + w_h, p_w, p_h, picref);
 +    x += p_w;
 +    draw_bar(test, q_pixel, x, r_h + w_h, p_w, p_h, picref);
 +    x += p_w;
 +    tmp = FFALIGN(5 * r_w - x,  1 << pixdesc->log2_chroma_w);
 +    draw_bar(test, black, x, r_h + w_h, tmp, p_h, picref);
 +    x += tmp;
 +    tmp = FFALIGN(r_w / 3,  1 << pixdesc->log2_chroma_w);
 +    draw_bar(test, neg4ire, x, r_h + w_h, tmp, p_h, picref);
 +    x += tmp;
 +    draw_bar(test, black, x, r_h + w_h, tmp, p_h, picref);
 +    x += tmp;
 +    draw_bar(test, pos4ire, x, r_h + w_h, tmp, p_h, picref);
 +    x += tmp;
 +    draw_bar(test, black, x, r_h + w_h, test->w - x, p_h, picref);
 +}
 +
 +static av_cold int smptebars_init(AVFilterContext *ctx, const char *args)
 +{
 +    TestSourceContext *test = ctx->priv;
 +
 +    test->class = &smptebars_class;
 +    test->fill_picture_fn = smptebars_fill_picture;
 +    test->draw_once = 1;
++    av_opt_set_defaults(test);
 +    return init(ctx, args);
 +}
 +
 +static int smptebars_query_formats(AVFilterContext *ctx)
 +{
 +    ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
 +    return 0;
 +}
 +
 +static int smptebars_config_props(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    TestSourceContext *test = ctx->priv;
 +
 +    ff_draw_init(&test->draw, outlink->format, 0);
 +
 +    return config_props(outlink);
 +}
 +
 +static const AVFilterPad smptebars_outputs[] = {
 +    {
 +        .name          = "default",
 +        .type          = AVMEDIA_TYPE_VIDEO,
 +        .request_frame = request_frame,
 +        .config_props  = smptebars_config_props,
 +    },
 +    { NULL }
 +};
 +
 +AVFilter avfilter_vsrc_smptebars = {
 +    .name      = "smptebars",
 +    .description = NULL_IF_CONFIG_SMALL("Generate SMPTE color bars."),
 +    .priv_size = sizeof(TestSourceContext),
 +    .init      = smptebars_init,
 +    .uninit    = uninit,
 +
 +    .query_formats = smptebars_query_formats,
 +    .inputs        = NULL,
 +    .outputs       = smptebars_outputs,
 +    .priv_class    = &smptebars_class,
 +};
 +
 +#endif  /* CONFIG_SMPTEBARS_FILTER */