diff mbox

[FFmpeg-devel,WIP,RFC] avfilter: negotiate color_range between filters

Message ID 20171211174458.10033-1-onemda@gmail.com
State Superseded
Headers show

Commit Message

Paul B Mahol Dec. 11, 2017, 5:44 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---

This is with color range negotiation.
To be applied on top of previous patch set.
It fixes issue Michael found.
This needs more work as every filter needs its query_formats() changed.

---
 fftools/ffmpeg_filter.c     | 13 +++-------
 libavfilter/avfilter.c      |  9 ++++---
 libavfilter/avfilter.h      |  4 ++-
 libavfilter/avfiltergraph.c | 34 ++++++++++++++++++++++++
 libavfilter/buffersink.c    | 16 ++++++++++++
 libavfilter/buffersink.h    |  1 +
 libavfilter/buffersrc.c     |  4 +++
 libavfilter/formats.c       | 63 +++++++++++++++++++++++++++++++++++++++++++++
 libavfilter/formats.h       | 31 ++++++++++++++++++++++
 libavfilter/internal.h      | 11 ++++++++
 libavfilter/vf_format.c     | 46 ++++++++++++++++++++++++++++++++-
 libavfilter/vf_noise.c      |  6 ++++-
 libavfilter/vf_scale.c      | 19 +++++++++++---
 libavfilter/vsrc_testsrc.c  | 15 +++++++++--
 14 files changed, 251 insertions(+), 21 deletions(-)

Comments

Nicolas George Dec. 11, 2017, 6:07 p.m. UTC | #1
I do not have time to look at the code in details right now, and I do
not know when I will have time, but here are a few remarks.

Paul B Mahol (2017-12-11):
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
> 
> This is with color range negotiation.
> To be applied on top of previous patch set.
> It fixes issue Michael found.

> This needs more work as every filter needs its query_formats() changed.

This is annoying. Could you not get the framework set a reasonable value
(all supported) when the list is not set?

> 
> ---
>  fftools/ffmpeg_filter.c     | 13 +++-------
>  libavfilter/avfilter.c      |  9 ++++---
>  libavfilter/avfilter.h      |  4 ++-
>  libavfilter/avfiltergraph.c | 34 ++++++++++++++++++++++++
>  libavfilter/buffersink.c    | 16 ++++++++++++
>  libavfilter/buffersink.h    |  1 +
>  libavfilter/buffersrc.c     |  4 +++
>  libavfilter/formats.c       | 63 +++++++++++++++++++++++++++++++++++++++++++++
>  libavfilter/formats.h       | 31 ++++++++++++++++++++++
>  libavfilter/internal.h      | 11 ++++++++
>  libavfilter/vf_format.c     | 46 ++++++++++++++++++++++++++++++++-
>  libavfilter/vf_noise.c      |  6 ++++-
>  libavfilter/vf_scale.c      | 19 +++++++++++---
>  libavfilter/vsrc_testsrc.c  | 15 +++++++++--
>  14 files changed, 251 insertions(+), 21 deletions(-)
> 
> diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
> index 3aad564b81..a8fbcdecfb 100644
> --- a/fftools/ffmpeg_filter.c
> +++ b/fftools/ffmpeg_filter.c
> @@ -144,6 +144,8 @@ static char *choose_pix_fmts(OutputFilter *ofilter)
>              const char *name = av_get_pix_fmt_name(*p);
>              avio_printf(s, "%s|", name);
>          }
> +        if (av_color_range_name(ost->enc->color_range))
> +            avio_printf(s, ":color_ranges=%s|", av_color_range_name(ost->enc->color_range));
>          len = avio_close_dyn_buf(s, &ret);
>          ret[len - 1] = 0;
>          return ret;
> @@ -447,7 +449,6 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
>      OutputStream *ost = ofilter->ost;
>      OutputFile    *of = output_files[ost->file_index];
>      AVFilterContext *last_filter = out->filter_ctx;
> -    AVDictionaryEntry *cre = NULL;
>      int pad_idx = out->pad_idx;
>      int ret;
>      char name[255];
> @@ -460,9 +461,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
>      if (ret < 0)
>          return ret;
>  
> -    cre = av_dict_get(ost->encoder_opts, "color_range", NULL, 0);
> -
> -    if (ofilter->width || ofilter->height || (cre && cre->value) || ost->enc->color_range) {
> +    if (ofilter->width || ofilter->height) {
>          char args[255];
>          AVFilterContext *filter;
>          AVDictionaryEntry *e = NULL;
> @@ -475,12 +474,6 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
>              av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value);
>          }
>  
> -        if (cre && cre->value) {
> -            av_strlcatf(args, sizeof(args), ":out_range=%s", cre->value);
> -        } else if (ost->enc->color_range) {
> -            av_strlcatf(args, sizeof(args), ":out_range=%s", av_color_range_name(ost->enc->color_range));
> -        }
> -
>          snprintf(name, sizeof(name), "scaler_out_%d_%d",
>                   ost->file_index, ost->index);
>          if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
> diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
> index 4a579bb49d..c3a19d100c 100644
> --- a/libavfilter/avfilter.c
> +++ b/libavfilter/avfilter.c
> @@ -262,6 +262,9 @@ int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
>      if (link->out_formats)
>          ff_formats_changeref(&link->out_formats,
>                               &filt->outputs[filt_dstpad_idx]->out_formats);
> +    if (link->out_color_ranges)
> +        ff_formats_changeref(&link->out_color_ranges,
> +                             &filt->outputs[filt_dstpad_idx]->out_color_ranges);
>      if (link->out_samplerates)
>          ff_formats_changeref(&link->out_samplerates,
>                               &filt->outputs[filt_dstpad_idx]->out_samplerates);
> @@ -785,6 +788,8 @@ static void free_link(AVFilterLink *link)
>  
>      ff_formats_unref(&link->in_formats);
>      ff_formats_unref(&link->out_formats);
> +    ff_formats_unref(&link->in_color_ranges);
> +    ff_formats_unref(&link->out_color_ranges);
>      ff_formats_unref(&link->in_samplerates);
>      ff_formats_unref(&link->out_samplerates);
>      ff_channel_layouts_unref(&link->in_channel_layouts);
> @@ -970,9 +975,7 @@ int avfilter_init_str(AVFilterContext *filter, const char *args)
>          }
>  
>  #if FF_API_OLD_FILTER_OPTS_ERROR
> -            if (   !strcmp(filter->filter->name, "format")     ||
> -                   !strcmp(filter->filter->name, "noformat")   ||
> -                   !strcmp(filter->filter->name, "frei0r")     ||
> +            if (   !strcmp(filter->filter->name, "frei0r")     ||
>                     !strcmp(filter->filter->name, "frei0r_src") ||
>                     !strcmp(filter->filter->name, "ocv")        ||
>                     !strcmp(filter->filter->name, "pan")        ||
> diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
> index 40ad28ffd8..138bdeb5c9 100644
> --- a/libavfilter/avfilter.h
> +++ b/libavfilter/avfilter.h
> @@ -456,7 +456,7 @@ struct AVFilterLink {
>       *****************************************************************
>       */
>      /**
> -     * Lists of formats and channel layouts supported by the input and output
> +     * Lists of formats, color_ranges and channel layouts supported by the input and output
>       * filters respectively. These lists are used for negotiating the format
>       * to actually be used, which will be loaded into the format and
>       * channel_layout members, above, when chosen.
> @@ -464,6 +464,8 @@ struct AVFilterLink {
>       */
>      AVFilterFormats *in_formats;
>      AVFilterFormats *out_formats;
> +    AVFilterFormats  *in_color_ranges;
> +    AVFilterFormats *out_color_ranges;
>  
>      /**
>       * Lists of channel layouts and sample rates used for automatic
> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
> index a959a9ef3f..ee5ddebe22 100644
> --- a/libavfilter/avfiltergraph.c
> +++ b/libavfilter/avfiltergraph.c
> @@ -360,6 +360,9 @@ static int formats_declared(AVFilterContext *f)
>              !(f->inputs[i]->out_samplerates &&
>                f->inputs[i]->out_channel_layouts))
>              return 0;
> +        if (f->inputs[i]->type == AVMEDIA_TYPE_VIDEO &&
> +            !(f->inputs[i]->out_color_ranges))
> +            return 0;
>      }
>      for (i = 0; i < f->nb_outputs; i++) {
>          if (!f->outputs[i]->in_formats)
> @@ -368,6 +371,9 @@ static int formats_declared(AVFilterContext *f)
>              !(f->outputs[i]->in_samplerates &&
>                f->outputs[i]->in_channel_layouts))
>              return 0;
> +        if (f->outputs[i]->type == AVMEDIA_TYPE_VIDEO &&
> +            !(f->outputs[i]->in_color_ranges))
> +            return 0;
>      }
>      return 1;
>  }
> @@ -485,6 +491,15 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>                          convert_needed = 1;
>              }
>  
> +            if (link->type == AVMEDIA_TYPE_VIDEO) {
> +                if (link->in_color_ranges != link->out_color_ranges
> +                    && link->in_color_ranges && link->out_color_ranges)
> +                    if (!can_merge_formats(link->in_color_ranges,
> +                                           link->out_color_ranges,
> +                                           0, 1))
> +                        convert_needed = 1;
> +            }
> +
>  #define MERGE_DISPATCH(field, statement)                                     \
>              if (!(link->in_ ## field && link->out_ ## field)) {              \
>                  count_delayed++;                                             \
> @@ -507,6 +522,13 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>                          convert_needed = 1;
>                  )
>              }
> +            if (link->type == AVMEDIA_TYPE_VIDEO) {
> +                MERGE_DISPATCH(color_ranges,

> +                    if (!ff_merge_samplerates(link->in_color_ranges,
> +                                              link->out_color_ranges))

Did you use ff_merge_samplerates() instead of ff_merge_formats on
purpose? IIRC, ff_merge_samplerates() makes a special case.

> +                        convert_needed = 1;
> +                )
> +            }
>              MERGE_DISPATCH(formats,
>                  if (!ff_merge_formats(link->in_formats, link->out_formats,
>                                        link->type))
> @@ -580,6 +602,12 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>                  av_assert0( inlink->out_formats->refcount > 0);
>                  av_assert0(outlink-> in_formats->refcount > 0);
>                  av_assert0(outlink->out_formats->refcount > 0);
> +                if (outlink->type == AVMEDIA_TYPE_VIDEO) {
> +                    av_assert0( inlink-> in_color_ranges->refcount > 0);
> +                    av_assert0( inlink->out_color_ranges->refcount > 0);
> +                    av_assert0(outlink-> in_color_ranges->refcount > 0);
> +                    av_assert0(outlink->out_color_ranges->refcount > 0);
> +                }
>                  if (outlink->type == AVMEDIA_TYPE_AUDIO) {
>                      av_assert0( inlink-> in_samplerates->refcount > 0);
>                      av_assert0( inlink->out_samplerates->refcount > 0);
> @@ -593,6 +621,12 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>                  if (!ff_merge_formats( inlink->in_formats,  inlink->out_formats,  inlink->type) ||
>                      !ff_merge_formats(outlink->in_formats, outlink->out_formats, outlink->type))
>                      ret = AVERROR(ENOSYS);
> +                if (inlink->type == AVMEDIA_TYPE_VIDEO &&
> +                    (!ff_merge_samplerates(inlink->in_color_ranges, inlink->out_color_ranges)))
> +                    ret = AVERROR(ENOSYS);
> +                if (outlink->type == AVMEDIA_TYPE_VIDEO &&
> +                    (!ff_merge_samplerates(outlink->in_color_ranges, outlink->out_color_ranges)))
> +                    ret = AVERROR(ENOSYS);
>                  if (inlink->type == AVMEDIA_TYPE_AUDIO &&
>                      (!ff_merge_samplerates(inlink->in_samplerates,
>                                             inlink->out_samplerates) ||
> diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
> index 897396cac4..8fe109106b 100644
> --- a/libavfilter/buffersink.c
> +++ b/libavfilter/buffersink.c
> @@ -45,6 +45,8 @@ typedef struct BufferSinkContext {
>      /* only used for video */
>      enum AVPixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
>      int pixel_fmts_size;
> +    enum AVColorRange *color_ranges;          ///< list of accepted color ranges, must be terminated with 0
> +    int color_ranges_size;
>  
>      /* only used for audio */
>      enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
> @@ -130,11 +132,13 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
>  AVBufferSinkParams *av_buffersink_params_alloc(void)
>  {
>      static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
> +    static const int color_ranges[] = { -1};
>      AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
>      if (!params)
>          return NULL;
>  
>      params->pixel_fmts = pixel_fmts;
> +    params->color_ranges = color_ranges;
>      return params;
>  }
>  
> @@ -211,6 +215,8 @@ static av_cold int vsink_init(AVFilterContext *ctx, void *opaque)
>      if (params) {
>          if ((ret = av_opt_set_int_list(buf, "pix_fmts", params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0)
>              return ret;
> +        if ((ret = av_opt_set_int_list(buf, "color_ranges", params->color_ranges, -1, 0)) < 0)
> +            return ret;
>      }
>  
>      return common_init(ctx);
> @@ -227,16 +233,25 @@ static int vsink_query_formats(AVFilterContext *ctx)
>  {
>      BufferSinkContext *buf = ctx->priv;
>      AVFilterFormats *formats = NULL;
> +    AVFilterFormats *color_ranges = NULL;
>      unsigned i;
>      int ret;
>  
>      CHECK_LIST_SIZE(pixel_fmts)
> +    CHECK_LIST_SIZE(color_ranges)
>      if (buf->pixel_fmts_size) {
>          for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
>              if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0)
>                  return ret;
>          if ((ret = ff_set_common_formats(ctx, formats)) < 0)
>              return ret;
> +    }
> +    if (buf->color_ranges_size) {
> +        for (i = 0; i < NB_ITEMS(buf->color_ranges); i++)
> +            if ((ret = ff_add_format(&color_ranges, buf->color_ranges[i])) < 0)
> +                return ret;
> +        if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
> +            return ret;
>      } else {
>          if ((ret = ff_default_query_formats(ctx)) < 0)
>              return ret;
> @@ -318,6 +333,7 @@ static int asink_query_formats(AVFilterContext *ctx)
>  #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
>  static const AVOption buffersink_options[] = {
>      { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
> +    { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS },
>      { NULL },
>  };
>  #undef FLAGS
> diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
> index e6d6504832..3a74a039a2 100644
> --- a/libavfilter/buffersink.h
> +++ b/libavfilter/buffersink.h
> @@ -64,6 +64,7 @@ int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flag
>   */
>  typedef struct AVBufferSinkParams {
>      const enum AVPixelFormat *pixel_fmts; ///< list of allowed pixel formats, terminated by AV_PIX_FMT_NONE
> +    const enum AVPixelFormat *color_ranges; ///< list of allowed color ranges, terminated by AVCOL_RANGE_UNSPECIFIED
>  } AVBufferSinkParams;
>  
>  /**
> diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
> index 51a1a9fb49..e450a2bca7 100644
> --- a/libavfilter/buffersrc.c
> +++ b/libavfilter/buffersrc.c
> @@ -412,6 +412,7 @@ static int query_formats(AVFilterContext *ctx)
>      BufferSourceContext *c = ctx->priv;
>      AVFilterChannelLayouts *channel_layouts = NULL;
>      AVFilterFormats *formats = NULL;
> +    AVFilterFormats *color_ranges = NULL;
>      AVFilterFormats *samplerates = NULL;
>      int ret;
>  
> @@ -420,6 +421,9 @@ static int query_formats(AVFilterContext *ctx)
>          if ((ret = ff_add_format         (&formats, c->pix_fmt)) < 0 ||
>              (ret = ff_set_common_formats (ctx     , formats   )) < 0)
>              return ret;
> +        if ((ret = ff_add_format         (&color_ranges, c->color_range)) < 0 ||
> +            (ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
> +            return ret;
>          break;
>      case AVMEDIA_TYPE_AUDIO:
>          if ((ret = ff_add_format             (&formats    , c->sample_fmt )) < 0 ||
> diff --git a/libavfilter/formats.c b/libavfilter/formats.c
> index d4de862237..560b348524 100644
> --- a/libavfilter/formats.c
> +++ b/libavfilter/formats.c
> @@ -289,6 +289,15 @@ AVFilterFormats *ff_make_format_list(const int *fmts)
>      return formats;
>  }
>  

> +AVFilterFormats *ff_make_color_range_list(const int *fmts)

Looks strange. It seems you are aiming for type safety, but the
parameter is still int.

> +{
> +    MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
> +    while (count--)
> +        formats->formats[count] = fmts[count];
> +
> +    return formats;
> +}
> +
>  AVFilterChannelLayouts *ff_make_formatu64_list(const uint64_t *fmts)
>  {
>      MAKE_FORMAT_LIST(AVFilterChannelLayouts,
> @@ -398,6 +407,37 @@ AVFilterFormats *ff_all_samplerates(void)
>      return ret;
>  }
>  

> +AVFilterFormats *ff_jpeg_color_ranges(void)
> +{
> +    AVFilterFormats *ret = NULL;
> +
> +    if (ff_add_format(&ret, AVCOL_RANGE_JPEG) < 0)
> +        return NULL;
> +
> +    return ret;
> +}
> +
> +AVFilterFormats *ff_mpeg_color_ranges(void)
> +{
> +    AVFilterFormats *ret = NULL;
> +
> +    if (ff_add_format(&ret, AVCOL_RANGE_MPEG) < 0)
> +        return NULL;
> +
> +    return ret;

I think one function to return a list with a single element would be
more convenient. Do we not already have that?

> +}
> +
> +AVFilterFormats *ff_all_color_ranges(void)
> +{
> +    AVFilterFormats *fmts = NULL;
> +    int ret;
> +
> +    ret = ff_add_format(&fmts, AVCOL_RANGE_UNSPECIFIED);
> +    ret = ff_add_format(&fmts, AVCOL_RANGE_MPEG);
> +    ret = ff_add_format(&fmts, AVCOL_RANGE_JPEG);
> +    return fmts;
> +}
> +
>  AVFilterChannelLayouts *ff_all_channel_layouts(void)
>  {
>      AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
> @@ -560,6 +600,13 @@ int ff_set_common_samplerates(AVFilterContext *ctx,
>                         ff_formats_ref, ff_formats_unref, formats);
>  }
>  
> +int ff_set_common_color_ranges(AVFilterContext *ctx,
> +                               AVFilterFormats *color_ranges)
> +{
> +    SET_COMMON_FORMATS(ctx, color_ranges, in_color_ranges, out_color_ranges,
> +                       ff_formats_ref, ff_formats_unref, formats);
> +}
> +
>  /**
>   * A helper for query_formats() which sets all links to the same list of
>   * formats. If there are no links hooked to this filter, the list of formats is
> @@ -590,6 +637,11 @@ static int default_query_formats_common(AVFilterContext *ctx,
>          if (ret < 0)
>              return ret;
>      }
> +    if (type == AVMEDIA_TYPE_VIDEO) {
> +        ret = ff_set_common_color_ranges(ctx, ff_all_color_ranges());
> +        if (ret < 0)
> +            return ret;
> +    }
>  
>      return 0;
>  }
> @@ -659,6 +711,17 @@ int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
>      return 0;
>  }
>  
> +int ff_parse_color_range(int *ret, const char *arg, void *log_ctx)
> +{
> +    int color_range = av_color_range_from_name(arg);
> +    if (color_range < 0) {
> +        av_log(log_ctx, AV_LOG_ERROR, "Invalid color range '%s'\n", arg);
> +        return AVERROR(EINVAL);
> +    }
> +    *ret = color_range;
> +    return 0;
> +}
> +
>  int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
>                              void *log_ctx)
>  {
> diff --git a/libavfilter/formats.h b/libavfilter/formats.h
> index 870809b5a0..6706f76dce 100644
> --- a/libavfilter/formats.h
> +++ b/libavfilter/formats.h
> @@ -166,6 +166,9 @@ av_warn_unused_result
>  int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
>  
>  av_warn_unused_result
> +int ff_set_common_color_ranges(AVFilterContext *ctx, AVFilterFormats *color_ranges);
> +
> +av_warn_unused_result
>  int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
>  
>  /**
> @@ -205,6 +208,16 @@ av_warn_unused_result
>  AVFilterFormats *ff_make_format_list(const int *fmts);
>  
>  /**
> + * Create a list of supported color ranges. This is intended for use in
> + * AVFilter->query_formats().
> + *
> + * @param fmts list of color ranges, terminated by -1
> + * @return the format list, with no existing references
> + */
> +av_warn_unused_result
> +AVFilterFormats *ff_make_color_range_list(const int *color_ranges);
> +
> +/**
>   * Add fmt to the list of media formats contained in *avff.
>   * If *avff is NULL the function allocates the filter formats struct
>   * and puts its pointer in *avff.
> @@ -222,6 +235,24 @@ av_warn_unused_result
>  AVFilterFormats *ff_all_formats(enum AVMediaType type);
>  
>  /**
> + * Return a list of all color ranges supported by FFmpeg.
> + */
> +av_warn_unused_result
> +AVFilterFormats *ff_all_color_ranges(void);
> +
> +/**
> + * Return a list of all mpeg color ranges supported by FFmpeg.
> + */
> +av_warn_unused_result
> +AVFilterFormats *ff_mpeg_color_ranges(void);
> +
> +/**
> + * Return a list of all jpeg color ranges supported by FFmpeg.
> + */
> +av_warn_unused_result
> +AVFilterFormats *ff_jpeg_color_ranges(void);
> +
> +/**
>   * Construct a formats list containing all planar sample formats.
>   */
>  av_warn_unused_result
> diff --git a/libavfilter/internal.h b/libavfilter/internal.h
> index f9679ed1d7..ca806d9443 100644
> --- a/libavfilter/internal.h
> +++ b/libavfilter/internal.h
> @@ -191,6 +191,17 @@ av_warn_unused_result
>  int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx);
>  
>  /**
> + * Parse a color range.
> + *
> + * @param ret unsigned enum pointer to where the value should be written
> + * @param arg string to parse
> + * @param log_ctx log context
> + * @return >= 0 in case of success, a negative AVERROR code on error
> + */
> +av_warn_unused_result
> +int ff_parse_color_range(int *ret, const char *arg, void *log_ctx);
> +
> +/**
>   * Parse a time base.
>   *
>   * @param ret unsigned AVRational pointer to where the value should be written
> diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
> index a57c99d797..067c03aa5a 100644
> --- a/libavfilter/vf_format.c
> +++ b/libavfilter/vf_format.c
> @@ -38,18 +38,21 @@
>  typedef struct FormatContext {
>      const AVClass *class;
>      char *pix_fmts;
> +    char *color_ranges_str;
>  
>      /**
>       * pix_fmts parsed into AVPixelFormats and terminated with
>       * AV_PIX_FMT_NONE
>       */
>      enum AVPixelFormat *formats;
> +    int *color_ranges;
>  } FormatContext;
>  
>  static av_cold void uninit(AVFilterContext *ctx)
>  {
>      FormatContext *s = ctx->priv;
>      av_freep(&s->formats);
> +    av_freep(&s->color_ranges);
>  }
>  
>  static av_cold int init(AVFilterContext *ctx)
> @@ -57,6 +60,7 @@ static av_cold int init(AVFilterContext *ctx)
>      FormatContext *s = ctx->priv;
>      char *cur, *sep;
>      int nb_formats = 1;
> +    int nb_color_ranges = 1;
>      int i;
>      int ret;
>  
> @@ -91,6 +95,37 @@ static av_cold int init(AVFilterContext *ctx)
>      }
>      s->formats[nb_formats] = AV_PIX_FMT_NONE;
>  
> +    if (!s->color_ranges_str) {
> +        av_log(ctx, AV_LOG_ERROR, "Empty output color range string.\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    /* count the color ranges */
> +    cur = s->color_ranges_str;
> +    while ((cur = strchr(cur, '|'))) {
> +        nb_color_ranges++;
> +        if (*cur)
> +            cur++;
> +    }
> +
> +    s->color_ranges = av_malloc_array(nb_color_ranges + 1, sizeof(*s->color_ranges));
> +    if (!s->color_ranges)
> +        return AVERROR(ENOMEM);
> +
> +    /* parse the list of formats */
> +    cur = s->color_ranges_str;
> +    for (i = 0; i < nb_color_ranges; i++) {
> +        sep = strchr(cur, '|');
> +        if (sep)
> +            *sep++ = 0;
> +
> +        if ((ret = ff_parse_color_range(&s->color_ranges[i], cur, ctx)) < 0)
> +            return ret;
> +
> +        cur = sep;
> +    }
> +    s->color_ranges[nb_color_ranges] = -1;
> +
>      if (!strcmp(ctx->filter->name, "noformat")) {
>          const AVPixFmtDescriptor *desc = NULL;
>          enum AVPixelFormat *formats_allowed;
> @@ -130,17 +165,26 @@ static int query_formats(AVFilterContext *ctx)
>  {
>      FormatContext *s = ctx->priv;
>      AVFilterFormats *formats = ff_make_format_list(s->formats);
> +    AVFilterFormats *color_ranges = ff_make_color_range_list(s->color_ranges);
> +    int ret;
>  
>      if (!formats)
>          return AVERROR(ENOMEM);
>  
> -    return ff_set_common_formats(ctx, formats);
> +    ret = ff_set_common_formats(ctx, formats);
> +    if (ret < 0)
> +        return ret;
> +
> +    if (!color_ranges)
> +        return AVERROR(ENOMEM);
> +    return ff_set_common_color_ranges(ctx, color_ranges);
>  }
>  
>  
>  #define OFFSET(x) offsetof(FormatContext, x)
>  static const AVOption options[] = {
>      { "pix_fmts", "A '|'-separated list of pixel formats", OFFSET(pix_fmts), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
> +    { "color_ranges", "A '|'-separated list of color ranges", OFFSET(color_ranges_str), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
>      { NULL }
>  };
>  
> diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
> index abdf04708b..c7af77b669 100644
> --- a/libavfilter/vf_noise.c
> +++ b/libavfilter/vf_noise.c
> @@ -142,7 +142,11 @@ static int query_formats(AVFilterContext *ctx)
>                  return ret;
>      }
>  
> -    return ff_set_common_formats(ctx, formats);
> +    ret = ff_set_common_formats(ctx, formats);
> +    if (ret < 0)
> +        return ret;
> +
> +    return ff_set_common_color_ranges(ctx, ff_all_color_ranges());
>  }
>  
>  static int config_input(AVFilterLink *inlink)
> diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
> index 802f841cc3..a571673b37 100644
> --- a/libavfilter/vf_scale.c
> +++ b/libavfilter/vf_scale.c
> @@ -157,7 +157,9 @@ static av_cold void uninit(AVFilterContext *ctx)
>  
>  static int query_formats(AVFilterContext *ctx)
>  {
> +    ScaleContext *scale = ctx->priv;
>      AVFilterFormats *formats;
> +    AVFilterFormats *color_ranges;
>      enum AVPixelFormat pix_fmt;
>      int ret;
>  
> @@ -174,10 +176,14 @@ static int query_formats(AVFilterContext *ctx)
>          }
>          if ((ret = ff_formats_ref(formats, &ctx->inputs[0]->out_formats)) < 0)
>              return ret;
> +        color_ranges = ff_all_color_ranges();
> +        if ((ret = ff_formats_ref(color_ranges, &ctx->inputs[0]->out_color_ranges)) < 0)
> +            return ret;
>      }
>      if (ctx->outputs[0]) {
>          const AVPixFmtDescriptor *desc = NULL;
>          formats = NULL;
> +        color_ranges = NULL;
>          while ((desc = av_pix_fmt_desc_next(desc))) {
>              pix_fmt = av_pix_fmt_desc_get_id(desc);
>              if ((sws_isSupportedOutput(pix_fmt) || pix_fmt == AV_PIX_FMT_PAL8 ||
> @@ -188,6 +194,12 @@ static int query_formats(AVFilterContext *ctx)
>          }
>          if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->in_formats)) < 0)
>              return ret;
> +
> +        ret = ff_add_format(&color_ranges, scale->out_range ? scale->out_range : AVCOL_RANGE_MPEG);
> +        if (ret < 0)
> +            return ret;
> +        if ((ret = ff_formats_ref(color_ranges, &ctx->outputs[0]->in_color_ranges)) < 0)
> +            return ret;
>      }
>  
>      return 0;
> @@ -276,6 +288,7 @@ static int config_props(AVFilterLink *outlink)
>      scale->isws[0] = scale->isws[1] = scale->sws = NULL;
>      if (inlink0->w == outlink->w &&
>          inlink0->h == outlink->h &&
> +        inlink0->color_range == outlink->color_range &&
>          !scale->out_color_matrix &&
>          scale->in_range == scale->out_range &&
>          inlink0->format == outlink->format)
> @@ -348,11 +361,11 @@ static int config_props(AVFilterLink *outlink)
>      } else
>          outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
>  
> -    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",
> +    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d cr:%d -> w:%d h:%d fmt:%s sar:%d/%d cr:%d flags:0x%0x\n",
>             inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
> -           inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
> +           inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, inlink->color_range,
>             outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
> -           outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
> +           outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den, outlink->color_range,
>             scale->flags);
>      return 0;
>  
> diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
> index eb12335472..a531e76f06 100644
> --- a/libavfilter/vsrc_testsrc.c
> +++ b/libavfilter/vsrc_testsrc.c
> @@ -207,7 +207,13 @@ static av_cold int color_init(AVFilterContext *ctx)
>  
>  static int color_query_formats(AVFilterContext *ctx)
>  {
> -    return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
> +    int ret;
> +
> +    ret = ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
> +    if (ret < 0)
> +        return ret;
> +
> +    return ff_set_common_color_ranges(ctx, ff_mpeg_color_ranges());
>  }
>  
>  static int color_config_props(AVFilterLink *inlink)
> @@ -653,11 +659,16 @@ static int test_query_formats(AVFilterContext *ctx)
>      static const enum AVPixelFormat pix_fmts[] = {
>          AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
>      };
> +    int ret;
>  
>      AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
>      if (!fmts_list)
>          return AVERROR(ENOMEM);
> -    return ff_set_common_formats(ctx, fmts_list);
> +    ret = ff_set_common_formats(ctx, fmts_list);
> +    if (ret < 0)
> +        return ret;
> +
> +    return ff_set_common_color_ranges(ctx, ff_jpeg_color_ranges());
>  }
>  
>  static const AVFilterPad avfilter_vsrc_testsrc_outputs[] = {

Regards,
Paul B Mahol Dec. 11, 2017, 6:42 p.m. UTC | #2
On 12/11/17, Nicolas George <george@nsup.org> wrote:
> I do not have time to look at the code in details right now, and I do
> not know when I will have time, but here are a few remarks.
>
> Paul B Mahol (2017-12-11):
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>>
>> This is with color range negotiation.
>> To be applied on top of previous patch set.
>> It fixes issue Michael found.
>
>> This needs more work as every filter needs its query_formats() changed.
>
> This is annoying. Could you not get the framework set a reasonable value
> (all supported) when the list is not set?

Done locally.

>
>>
>> ---
>>  fftools/ffmpeg_filter.c     | 13 +++-------
>>  libavfilter/avfilter.c      |  9 ++++---
>>  libavfilter/avfilter.h      |  4 ++-
>>  libavfilter/avfiltergraph.c | 34 ++++++++++++++++++++++++
>>  libavfilter/buffersink.c    | 16 ++++++++++++
>>  libavfilter/buffersink.h    |  1 +
>>  libavfilter/buffersrc.c     |  4 +++
>>  libavfilter/formats.c       | 63
>> +++++++++++++++++++++++++++++++++++++++++++++
>>  libavfilter/formats.h       | 31 ++++++++++++++++++++++
>>  libavfilter/internal.h      | 11 ++++++++
>>  libavfilter/vf_format.c     | 46 ++++++++++++++++++++++++++++++++-
>>  libavfilter/vf_noise.c      |  6 ++++-
>>  libavfilter/vf_scale.c      | 19 +++++++++++---
>>  libavfilter/vsrc_testsrc.c  | 15 +++++++++--
>>  14 files changed, 251 insertions(+), 21 deletions(-)
>>
>> diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
>> index 3aad564b81..a8fbcdecfb 100644
>> --- a/fftools/ffmpeg_filter.c
>> +++ b/fftools/ffmpeg_filter.c
>> @@ -144,6 +144,8 @@ static char *choose_pix_fmts(OutputFilter *ofilter)
>>              const char *name = av_get_pix_fmt_name(*p);
>>              avio_printf(s, "%s|", name);
>>          }
>> +        if (av_color_range_name(ost->enc->color_range))
>> +            avio_printf(s, ":color_ranges=%s|",
>> av_color_range_name(ost->enc->color_range));
>>          len = avio_close_dyn_buf(s, &ret);
>>          ret[len - 1] = 0;
>>          return ret;
>> @@ -447,7 +449,6 @@ static int configure_output_video_filter(FilterGraph
>> *fg, OutputFilter *ofilter,
>>      OutputStream *ost = ofilter->ost;
>>      OutputFile    *of = output_files[ost->file_index];
>>      AVFilterContext *last_filter = out->filter_ctx;
>> -    AVDictionaryEntry *cre = NULL;
>>      int pad_idx = out->pad_idx;
>>      int ret;
>>      char name[255];
>> @@ -460,9 +461,7 @@ static int configure_output_video_filter(FilterGraph
>> *fg, OutputFilter *ofilter,
>>      if (ret < 0)
>>          return ret;
>>
>> -    cre = av_dict_get(ost->encoder_opts, "color_range", NULL, 0);
>> -
>> -    if (ofilter->width || ofilter->height || (cre && cre->value) ||
>> ost->enc->color_range) {
>> +    if (ofilter->width || ofilter->height) {
>>          char args[255];
>>          AVFilterContext *filter;
>>          AVDictionaryEntry *e = NULL;
>> @@ -475,12 +474,6 @@ static int configure_output_video_filter(FilterGraph
>> *fg, OutputFilter *ofilter,
>>              av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value);
>>          }
>>
>> -        if (cre && cre->value) {
>> -            av_strlcatf(args, sizeof(args), ":out_range=%s",
>> cre->value);
>> -        } else if (ost->enc->color_range) {
>> -            av_strlcatf(args, sizeof(args), ":out_range=%s",
>> av_color_range_name(ost->enc->color_range));
>> -        }
>> -
>>          snprintf(name, sizeof(name), "scaler_out_%d_%d",
>>                   ost->file_index, ost->index);
>>          if ((ret = avfilter_graph_create_filter(&filter,
>> avfilter_get_by_name("scale"),
>> diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
>> index 4a579bb49d..c3a19d100c 100644
>> --- a/libavfilter/avfilter.c
>> +++ b/libavfilter/avfilter.c
>> @@ -262,6 +262,9 @@ int avfilter_insert_filter(AVFilterLink *link,
>> AVFilterContext *filt,
>>      if (link->out_formats)
>>          ff_formats_changeref(&link->out_formats,
>>
>> &filt->outputs[filt_dstpad_idx]->out_formats);
>> +    if (link->out_color_ranges)
>> +        ff_formats_changeref(&link->out_color_ranges,
>> +
>> &filt->outputs[filt_dstpad_idx]->out_color_ranges);
>>      if (link->out_samplerates)
>>          ff_formats_changeref(&link->out_samplerates,
>>
>> &filt->outputs[filt_dstpad_idx]->out_samplerates);
>> @@ -785,6 +788,8 @@ static void free_link(AVFilterLink *link)
>>
>>      ff_formats_unref(&link->in_formats);
>>      ff_formats_unref(&link->out_formats);
>> +    ff_formats_unref(&link->in_color_ranges);
>> +    ff_formats_unref(&link->out_color_ranges);
>>      ff_formats_unref(&link->in_samplerates);
>>      ff_formats_unref(&link->out_samplerates);
>>      ff_channel_layouts_unref(&link->in_channel_layouts);
>> @@ -970,9 +975,7 @@ int avfilter_init_str(AVFilterContext *filter, const
>> char *args)
>>          }
>>
>>  #if FF_API_OLD_FILTER_OPTS_ERROR
>> -            if (   !strcmp(filter->filter->name, "format")     ||
>> -                   !strcmp(filter->filter->name, "noformat")   ||
>> -                   !strcmp(filter->filter->name, "frei0r")     ||
>> +            if (   !strcmp(filter->filter->name, "frei0r")     ||
>>                     !strcmp(filter->filter->name, "frei0r_src") ||
>>                     !strcmp(filter->filter->name, "ocv")        ||
>>                     !strcmp(filter->filter->name, "pan")        ||
>> diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
>> index 40ad28ffd8..138bdeb5c9 100644
>> --- a/libavfilter/avfilter.h
>> +++ b/libavfilter/avfilter.h
>> @@ -456,7 +456,7 @@ struct AVFilterLink {
>>       *****************************************************************
>>       */
>>      /**
>> -     * Lists of formats and channel layouts supported by the input and
>> output
>> +     * Lists of formats, color_ranges and channel layouts supported by
>> the input and output
>>       * filters respectively. These lists are used for negotiating the
>> format
>>       * to actually be used, which will be loaded into the format and
>>       * channel_layout members, above, when chosen.
>> @@ -464,6 +464,8 @@ struct AVFilterLink {
>>       */
>>      AVFilterFormats *in_formats;
>>      AVFilterFormats *out_formats;
>> +    AVFilterFormats  *in_color_ranges;
>> +    AVFilterFormats *out_color_ranges;
>>
>>      /**
>>       * Lists of channel layouts and sample rates used for automatic
>> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
>> index a959a9ef3f..ee5ddebe22 100644
>> --- a/libavfilter/avfiltergraph.c
>> +++ b/libavfilter/avfiltergraph.c
>> @@ -360,6 +360,9 @@ static int formats_declared(AVFilterContext *f)
>>              !(f->inputs[i]->out_samplerates &&
>>                f->inputs[i]->out_channel_layouts))
>>              return 0;
>> +        if (f->inputs[i]->type == AVMEDIA_TYPE_VIDEO &&
>> +            !(f->inputs[i]->out_color_ranges))
>> +            return 0;
>>      }
>>      for (i = 0; i < f->nb_outputs; i++) {
>>          if (!f->outputs[i]->in_formats)
>> @@ -368,6 +371,9 @@ static int formats_declared(AVFilterContext *f)
>>              !(f->outputs[i]->in_samplerates &&
>>                f->outputs[i]->in_channel_layouts))
>>              return 0;
>> +        if (f->outputs[i]->type == AVMEDIA_TYPE_VIDEO &&
>> +            !(f->outputs[i]->in_color_ranges))
>> +            return 0;
>>      }
>>      return 1;
>>  }
>> @@ -485,6 +491,15 @@ static int query_formats(AVFilterGraph *graph,
>> AVClass *log_ctx)
>>                          convert_needed = 1;
>>              }
>>
>> +            if (link->type == AVMEDIA_TYPE_VIDEO) {
>> +                if (link->in_color_ranges != link->out_color_ranges
>> +                    && link->in_color_ranges && link->out_color_ranges)
>> +                    if (!can_merge_formats(link->in_color_ranges,
>> +                                           link->out_color_ranges,
>> +                                           0, 1))
>> +                        convert_needed = 1;
>> +            }
>> +
>>  #define MERGE_DISPATCH(field, statement)
>>    \
>>              if (!(link->in_ ## field && link->out_ ## field)) {
>>    \
>>                  count_delayed++;
>>    \
>> @@ -507,6 +522,13 @@ static int query_formats(AVFilterGraph *graph,
>> AVClass *log_ctx)
>>                          convert_needed = 1;
>>                  )
>>              }
>> +            if (link->type == AVMEDIA_TYPE_VIDEO) {
>> +                MERGE_DISPATCH(color_ranges,
>
>> +                    if (!ff_merge_samplerates(link->in_color_ranges,
>> +                                              link->out_color_ranges))
>
> Did you use ff_merge_samplerates() instead of ff_merge_formats on
> purpose? IIRC, ff_merge_samplerates() makes a special case.

ff_merge_samplerates expect list that ends with -1.

ff_merge_formats expect pix_fmts for video type.

>
>> +                        convert_needed = 1;
>> +                )
>> +            }
>>              MERGE_DISPATCH(formats,
>>                  if (!ff_merge_formats(link->in_formats,
>> link->out_formats,
>>                                        link->type))
>> @@ -580,6 +602,12 @@ static int query_formats(AVFilterGraph *graph,
>> AVClass *log_ctx)
>>                  av_assert0( inlink->out_formats->refcount > 0);
>>                  av_assert0(outlink-> in_formats->refcount > 0);
>>                  av_assert0(outlink->out_formats->refcount > 0);
>> +                if (outlink->type == AVMEDIA_TYPE_VIDEO) {
>> +                    av_assert0( inlink-> in_color_ranges->refcount > 0);
>> +                    av_assert0( inlink->out_color_ranges->refcount > 0);
>> +                    av_assert0(outlink-> in_color_ranges->refcount > 0);
>> +                    av_assert0(outlink->out_color_ranges->refcount > 0);
>> +                }
>>                  if (outlink->type == AVMEDIA_TYPE_AUDIO) {
>>                      av_assert0( inlink-> in_samplerates->refcount > 0);
>>                      av_assert0( inlink->out_samplerates->refcount > 0);
>> @@ -593,6 +621,12 @@ static int query_formats(AVFilterGraph *graph,
>> AVClass *log_ctx)
>>                  if (!ff_merge_formats( inlink->in_formats,
>> inlink->out_formats,  inlink->type) ||
>>                      !ff_merge_formats(outlink->in_formats,
>> outlink->out_formats, outlink->type))
>>                      ret = AVERROR(ENOSYS);
>> +                if (inlink->type == AVMEDIA_TYPE_VIDEO &&
>> +                    (!ff_merge_samplerates(inlink->in_color_ranges,
>> inlink->out_color_ranges)))
>> +                    ret = AVERROR(ENOSYS);
>> +                if (outlink->type == AVMEDIA_TYPE_VIDEO &&
>> +                    (!ff_merge_samplerates(outlink->in_color_ranges,
>> outlink->out_color_ranges)))
>> +                    ret = AVERROR(ENOSYS);
>>                  if (inlink->type == AVMEDIA_TYPE_AUDIO &&
>>                      (!ff_merge_samplerates(inlink->in_samplerates,
>>                                             inlink->out_samplerates) ||
>> diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
>> index 897396cac4..8fe109106b 100644
>> --- a/libavfilter/buffersink.c
>> +++ b/libavfilter/buffersink.c
>> @@ -45,6 +45,8 @@ typedef struct BufferSinkContext {
>>      /* only used for video */
>>      enum AVPixelFormat *pixel_fmts;           ///< list of accepted pixel
>> formats, must be terminated with -1
>>      int pixel_fmts_size;
>> +    enum AVColorRange *color_ranges;          ///< list of accepted color
>> ranges, must be terminated with 0
>> +    int color_ranges_size;
>>
>>      /* only used for audio */
>>      enum AVSampleFormat *sample_fmts;       ///< list of accepted sample
>> formats, terminated by AV_SAMPLE_FMT_NONE
>> @@ -130,11 +132,13 @@ int attribute_align_arg
>> av_buffersink_get_samples(AVFilterContext *ctx,
>>  AVBufferSinkParams *av_buffersink_params_alloc(void)
>>  {
>>      static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
>> +    static const int color_ranges[] = { -1};
>>      AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
>>      if (!params)
>>          return NULL;
>>
>>      params->pixel_fmts = pixel_fmts;
>> +    params->color_ranges = color_ranges;
>>      return params;
>>  }
>>
>> @@ -211,6 +215,8 @@ static av_cold int vsink_init(AVFilterContext *ctx,
>> void *opaque)
>>      if (params) {
>>          if ((ret = av_opt_set_int_list(buf, "pix_fmts",
>> params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0)
>>              return ret;
>> +        if ((ret = av_opt_set_int_list(buf, "color_ranges",
>> params->color_ranges, -1, 0)) < 0)
>> +            return ret;
>>      }
>>
>>      return common_init(ctx);
>> @@ -227,16 +233,25 @@ static int vsink_query_formats(AVFilterContext
>> *ctx)
>>  {
>>      BufferSinkContext *buf = ctx->priv;
>>      AVFilterFormats *formats = NULL;
>> +    AVFilterFormats *color_ranges = NULL;
>>      unsigned i;
>>      int ret;
>>
>>      CHECK_LIST_SIZE(pixel_fmts)
>> +    CHECK_LIST_SIZE(color_ranges)
>>      if (buf->pixel_fmts_size) {
>>          for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
>>              if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0)
>>                  return ret;
>>          if ((ret = ff_set_common_formats(ctx, formats)) < 0)
>>              return ret;
>> +    }
>> +    if (buf->color_ranges_size) {
>> +        for (i = 0; i < NB_ITEMS(buf->color_ranges); i++)
>> +            if ((ret = ff_add_format(&color_ranges,
>> buf->color_ranges[i])) < 0)
>> +                return ret;
>> +        if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
>> +            return ret;
>>      } else {
>>          if ((ret = ff_default_query_formats(ctx)) < 0)
>>              return ret;
>> @@ -318,6 +333,7 @@ static int asink_query_formats(AVFilterContext *ctx)
>>  #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
>>  static const AVOption buffersink_options[] = {
>>      { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts),
>> AV_OPT_TYPE_BINARY, .flags = FLAGS },
>> +    { "color_ranges", "set the supported color ranges",
>> OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS },
>>      { NULL },
>>  };
>>  #undef FLAGS
>> diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
>> index e6d6504832..3a74a039a2 100644
>> --- a/libavfilter/buffersink.h
>> +++ b/libavfilter/buffersink.h
>> @@ -64,6 +64,7 @@ int av_buffersink_get_frame_flags(AVFilterContext *ctx,
>> AVFrame *frame, int flag
>>   */
>>  typedef struct AVBufferSinkParams {
>>      const enum AVPixelFormat *pixel_fmts; ///< list of allowed pixel
>> formats, terminated by AV_PIX_FMT_NONE
>> +    const enum AVPixelFormat *color_ranges; ///< list of allowed color
>> ranges, terminated by AVCOL_RANGE_UNSPECIFIED
>>  } AVBufferSinkParams;
>>
>>  /**
>> diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
>> index 51a1a9fb49..e450a2bca7 100644
>> --- a/libavfilter/buffersrc.c
>> +++ b/libavfilter/buffersrc.c
>> @@ -412,6 +412,7 @@ static int query_formats(AVFilterContext *ctx)
>>      BufferSourceContext *c = ctx->priv;
>>      AVFilterChannelLayouts *channel_layouts = NULL;
>>      AVFilterFormats *formats = NULL;
>> +    AVFilterFormats *color_ranges = NULL;
>>      AVFilterFormats *samplerates = NULL;
>>      int ret;
>>
>> @@ -420,6 +421,9 @@ static int query_formats(AVFilterContext *ctx)
>>          if ((ret = ff_add_format         (&formats, c->pix_fmt)) < 0 ||
>>              (ret = ff_set_common_formats (ctx     , formats   )) < 0)
>>              return ret;
>> +        if ((ret = ff_add_format         (&color_ranges, c->color_range))
>> < 0 ||
>> +            (ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
>> +            return ret;
>>          break;
>>      case AVMEDIA_TYPE_AUDIO:
>>          if ((ret = ff_add_format             (&formats    , c->sample_fmt
>> )) < 0 ||
>> diff --git a/libavfilter/formats.c b/libavfilter/formats.c
>> index d4de862237..560b348524 100644
>> --- a/libavfilter/formats.c
>> +++ b/libavfilter/formats.c
>> @@ -289,6 +289,15 @@ AVFilterFormats *ff_make_format_list(const int
>> *fmts)
>>      return formats;
>>  }
>>
>
>> +AVFilterFormats *ff_make_color_range_list(const int *fmts)
>
> Looks strange. It seems you are aiming for type safety, but the
> parameter is still int.

Using enum will not work with -1 to signal end of list.

>
>> +{
>> +    MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
>> +    while (count--)
>> +        formats->formats[count] = fmts[count];
>> +
>> +    return formats;
>> +}
>> +
>>  AVFilterChannelLayouts *ff_make_formatu64_list(const uint64_t *fmts)
>>  {
>>      MAKE_FORMAT_LIST(AVFilterChannelLayouts,
>> @@ -398,6 +407,37 @@ AVFilterFormats *ff_all_samplerates(void)
>>      return ret;
>>  }
>>
>
>> +AVFilterFormats *ff_jpeg_color_ranges(void)
>> +{
>> +    AVFilterFormats *ret = NULL;
>> +
>> +    if (ff_add_format(&ret, AVCOL_RANGE_JPEG) < 0)
>> +        return NULL;
>> +
>> +    return ret;
>> +}
>> +
>> +AVFilterFormats *ff_mpeg_color_ranges(void)
>> +{
>> +    AVFilterFormats *ret = NULL;
>> +
>> +    if (ff_add_format(&ret, AVCOL_RANGE_MPEG) < 0)
>> +        return NULL;
>> +
>> +    return ret;
>
> I think one function to return a list with a single element would be
> more convenient. Do we not already have that?

Looks like not.

>
>> +}
>> +
>> +AVFilterFormats *ff_all_color_ranges(void)
>> +{
>> +    AVFilterFormats *fmts = NULL;
>> +    int ret;
>> +
>> +    ret = ff_add_format(&fmts, AVCOL_RANGE_UNSPECIFIED);
>> +    ret = ff_add_format(&fmts, AVCOL_RANGE_MPEG);
>> +    ret = ff_add_format(&fmts, AVCOL_RANGE_JPEG);
>> +    return fmts;
>> +}
>> +
>>  AVFilterChannelLayouts *ff_all_channel_layouts(void)
>>  {
>>      AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
>> @@ -560,6 +600,13 @@ int ff_set_common_samplerates(AVFilterContext *ctx,
>>                         ff_formats_ref, ff_formats_unref, formats);
>>  }
>>
>> +int ff_set_common_color_ranges(AVFilterContext *ctx,
>> +                               AVFilterFormats *color_ranges)
>> +{
>> +    SET_COMMON_FORMATS(ctx, color_ranges, in_color_ranges,
>> out_color_ranges,
>> +                       ff_formats_ref, ff_formats_unref, formats);
>> +}
>> +
>>  /**
>>   * A helper for query_formats() which sets all links to the same list of
>>   * formats. If there are no links hooked to this filter, the list of
>> formats is
>> @@ -590,6 +637,11 @@ static int
>> default_query_formats_common(AVFilterContext *ctx,
>>          if (ret < 0)
>>              return ret;
>>      }
>> +    if (type == AVMEDIA_TYPE_VIDEO) {
>> +        ret = ff_set_common_color_ranges(ctx, ff_all_color_ranges());
>> +        if (ret < 0)
>> +            return ret;
>> +    }
>>
>>      return 0;
>>  }
>> @@ -659,6 +711,17 @@ int ff_parse_sample_rate(int *ret, const char *arg,
>> void *log_ctx)
>>      return 0;
>>  }
>>
>> +int ff_parse_color_range(int *ret, const char *arg, void *log_ctx)
>> +{
>> +    int color_range = av_color_range_from_name(arg);
>> +    if (color_range < 0) {
>> +        av_log(log_ctx, AV_LOG_ERROR, "Invalid color range '%s'\n",
>> arg);
>> +        return AVERROR(EINVAL);
>> +    }
>> +    *ret = color_range;
>> +    return 0;
>> +}
>> +
>>  int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
>>                              void *log_ctx)
>>  {
>> diff --git a/libavfilter/formats.h b/libavfilter/formats.h
>> index 870809b5a0..6706f76dce 100644
>> --- a/libavfilter/formats.h
>> +++ b/libavfilter/formats.h
>> @@ -166,6 +166,9 @@ av_warn_unused_result
>>  int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats
>> *formats);
>>
>>  av_warn_unused_result
>> +int ff_set_common_color_ranges(AVFilterContext *ctx, AVFilterFormats
>> *color_ranges);
>> +
>> +av_warn_unused_result
>>  int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t
>> channel_layout);
>>
>>  /**
>> @@ -205,6 +208,16 @@ av_warn_unused_result
>>  AVFilterFormats *ff_make_format_list(const int *fmts);
>>
>>  /**
>> + * Create a list of supported color ranges. This is intended for use in
>> + * AVFilter->query_formats().
>> + *
>> + * @param fmts list of color ranges, terminated by -1
>> + * @return the format list, with no existing references
>> + */
>> +av_warn_unused_result
>> +AVFilterFormats *ff_make_color_range_list(const int *color_ranges);
>> +
>> +/**
>>   * Add fmt to the list of media formats contained in *avff.
>>   * If *avff is NULL the function allocates the filter formats struct
>>   * and puts its pointer in *avff.
>> @@ -222,6 +235,24 @@ av_warn_unused_result
>>  AVFilterFormats *ff_all_formats(enum AVMediaType type);
>>
>>  /**
>> + * Return a list of all color ranges supported by FFmpeg.
>> + */
>> +av_warn_unused_result
>> +AVFilterFormats *ff_all_color_ranges(void);
>> +
>> +/**
>> + * Return a list of all mpeg color ranges supported by FFmpeg.
>> + */
>> +av_warn_unused_result
>> +AVFilterFormats *ff_mpeg_color_ranges(void);
>> +
>> +/**
>> + * Return a list of all jpeg color ranges supported by FFmpeg.
>> + */
>> +av_warn_unused_result
>> +AVFilterFormats *ff_jpeg_color_ranges(void);
>> +
>> +/**
>>   * Construct a formats list containing all planar sample formats.
>>   */
>>  av_warn_unused_result
>> diff --git a/libavfilter/internal.h b/libavfilter/internal.h
>> index f9679ed1d7..ca806d9443 100644
>> --- a/libavfilter/internal.h
>> +++ b/libavfilter/internal.h
>> @@ -191,6 +191,17 @@ av_warn_unused_result
>>  int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx);
>>
>>  /**
>> + * Parse a color range.
>> + *
>> + * @param ret unsigned enum pointer to where the value should be written
>> + * @param arg string to parse
>> + * @param log_ctx log context
>> + * @return >= 0 in case of success, a negative AVERROR code on error
>> + */
>> +av_warn_unused_result
>> +int ff_parse_color_range(int *ret, const char *arg, void *log_ctx);
>> +
>> +/**
>>   * Parse a time base.
>>   *
>>   * @param ret unsigned AVRational pointer to where the value should be
>> written
>> diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
>> index a57c99d797..067c03aa5a 100644
>> --- a/libavfilter/vf_format.c
>> +++ b/libavfilter/vf_format.c
>> @@ -38,18 +38,21 @@
>>  typedef struct FormatContext {
>>      const AVClass *class;
>>      char *pix_fmts;
>> +    char *color_ranges_str;
>>
>>      /**
>>       * pix_fmts parsed into AVPixelFormats and terminated with
>>       * AV_PIX_FMT_NONE
>>       */
>>      enum AVPixelFormat *formats;
>> +    int *color_ranges;
>>  } FormatContext;
>>
>>  static av_cold void uninit(AVFilterContext *ctx)
>>  {
>>      FormatContext *s = ctx->priv;
>>      av_freep(&s->formats);
>> +    av_freep(&s->color_ranges);
>>  }
>>
>>  static av_cold int init(AVFilterContext *ctx)
>> @@ -57,6 +60,7 @@ static av_cold int init(AVFilterContext *ctx)
>>      FormatContext *s = ctx->priv;
>>      char *cur, *sep;
>>      int nb_formats = 1;
>> +    int nb_color_ranges = 1;
>>      int i;
>>      int ret;
>>
>> @@ -91,6 +95,37 @@ static av_cold int init(AVFilterContext *ctx)
>>      }
>>      s->formats[nb_formats] = AV_PIX_FMT_NONE;
>>
>> +    if (!s->color_ranges_str) {
>> +        av_log(ctx, AV_LOG_ERROR, "Empty output color range string.\n");
>> +        return AVERROR(EINVAL);
>> +    }
>> +
>> +    /* count the color ranges */
>> +    cur = s->color_ranges_str;
>> +    while ((cur = strchr(cur, '|'))) {
>> +        nb_color_ranges++;
>> +        if (*cur)
>> +            cur++;
>> +    }
>> +
>> +    s->color_ranges = av_malloc_array(nb_color_ranges + 1,
>> sizeof(*s->color_ranges));
>> +    if (!s->color_ranges)
>> +        return AVERROR(ENOMEM);
>> +
>> +    /* parse the list of formats */
>> +    cur = s->color_ranges_str;
>> +    for (i = 0; i < nb_color_ranges; i++) {
>> +        sep = strchr(cur, '|');
>> +        if (sep)
>> +            *sep++ = 0;
>> +
>> +        if ((ret = ff_parse_color_range(&s->color_ranges[i], cur, ctx)) <
>> 0)
>> +            return ret;
>> +
>> +        cur = sep;
>> +    }
>> +    s->color_ranges[nb_color_ranges] = -1;
>> +
>>      if (!strcmp(ctx->filter->name, "noformat")) {
>>          const AVPixFmtDescriptor *desc = NULL;
>>          enum AVPixelFormat *formats_allowed;
>> @@ -130,17 +165,26 @@ static int query_formats(AVFilterContext *ctx)
>>  {
>>      FormatContext *s = ctx->priv;
>>      AVFilterFormats *formats = ff_make_format_list(s->formats);
>> +    AVFilterFormats *color_ranges =
>> ff_make_color_range_list(s->color_ranges);
>> +    int ret;
>>
>>      if (!formats)
>>          return AVERROR(ENOMEM);
>>
>> -    return ff_set_common_formats(ctx, formats);
>> +    ret = ff_set_common_formats(ctx, formats);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    if (!color_ranges)
>> +        return AVERROR(ENOMEM);
>> +    return ff_set_common_color_ranges(ctx, color_ranges);
>>  }
>>
>>
>>  #define OFFSET(x) offsetof(FormatContext, x)
>>  static const AVOption options[] = {
>>      { "pix_fmts", "A '|'-separated list of pixel formats",
>> OFFSET(pix_fmts), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM |
>> AV_OPT_FLAG_FILTERING_PARAM },
>> +    { "color_ranges", "A '|'-separated list of color ranges",
>> OFFSET(color_ranges_str), AV_OPT_TYPE_STRING, .flags =
>> AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
>>      { NULL }
>>  };
>>
>> diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
>> index abdf04708b..c7af77b669 100644
>> --- a/libavfilter/vf_noise.c
>> +++ b/libavfilter/vf_noise.c
>> @@ -142,7 +142,11 @@ static int query_formats(AVFilterContext *ctx)
>>                  return ret;
>>      }
>>
>> -    return ff_set_common_formats(ctx, formats);
>> +    ret = ff_set_common_formats(ctx, formats);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return ff_set_common_color_ranges(ctx, ff_all_color_ranges());
>>  }
>>
>>  static int config_input(AVFilterLink *inlink)
>> diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
>> index 802f841cc3..a571673b37 100644
>> --- a/libavfilter/vf_scale.c
>> +++ b/libavfilter/vf_scale.c
>> @@ -157,7 +157,9 @@ static av_cold void uninit(AVFilterContext *ctx)
>>
>>  static int query_formats(AVFilterContext *ctx)
>>  {
>> +    ScaleContext *scale = ctx->priv;
>>      AVFilterFormats *formats;
>> +    AVFilterFormats *color_ranges;
>>      enum AVPixelFormat pix_fmt;
>>      int ret;
>>
>> @@ -174,10 +176,14 @@ static int query_formats(AVFilterContext *ctx)
>>          }
>>          if ((ret = ff_formats_ref(formats, &ctx->inputs[0]->out_formats))
>> < 0)
>>              return ret;
>> +        color_ranges = ff_all_color_ranges();
>> +        if ((ret = ff_formats_ref(color_ranges,
>> &ctx->inputs[0]->out_color_ranges)) < 0)
>> +            return ret;
>>      }
>>      if (ctx->outputs[0]) {
>>          const AVPixFmtDescriptor *desc = NULL;
>>          formats = NULL;
>> +        color_ranges = NULL;
>>          while ((desc = av_pix_fmt_desc_next(desc))) {
>>              pix_fmt = av_pix_fmt_desc_get_id(desc);
>>              if ((sws_isSupportedOutput(pix_fmt) || pix_fmt ==
>> AV_PIX_FMT_PAL8 ||
>> @@ -188,6 +194,12 @@ static int query_formats(AVFilterContext *ctx)
>>          }
>>          if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->in_formats))
>> < 0)
>>              return ret;
>> +
>> +        ret = ff_add_format(&color_ranges, scale->out_range ?
>> scale->out_range : AVCOL_RANGE_MPEG);
>> +        if (ret < 0)
>> +            return ret;
>> +        if ((ret = ff_formats_ref(color_ranges,
>> &ctx->outputs[0]->in_color_ranges)) < 0)
>> +            return ret;
>>      }
>>
>>      return 0;
>> @@ -276,6 +288,7 @@ static int config_props(AVFilterLink *outlink)
>>      scale->isws[0] = scale->isws[1] = scale->sws = NULL;
>>      if (inlink0->w == outlink->w &&
>>          inlink0->h == outlink->h &&
>> +        inlink0->color_range == outlink->color_range &&
>>          !scale->out_color_matrix &&
>>          scale->in_range == scale->out_range &&
>>          inlink0->format == outlink->format)
>> @@ -348,11 +361,11 @@ static int config_props(AVFilterLink *outlink)
>>      } else
>>          outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
>>
>> -    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d
>> fmt:%s sar:%d/%d flags:0x%0x\n",
>> +    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d cr:%d -> w:%d
>> h:%d fmt:%s sar:%d/%d cr:%d flags:0x%0x\n",
>>             inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
>> -           inlink->sample_aspect_ratio.num,
>> inlink->sample_aspect_ratio.den,
>> +           inlink->sample_aspect_ratio.num,
>> inlink->sample_aspect_ratio.den, inlink->color_range,
>>             outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
>> -           outlink->sample_aspect_ratio.num,
>> outlink->sample_aspect_ratio.den,
>> +           outlink->sample_aspect_ratio.num,
>> outlink->sample_aspect_ratio.den, outlink->color_range,
>>             scale->flags);
>>      return 0;
>>
>> diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
>> index eb12335472..a531e76f06 100644
>> --- a/libavfilter/vsrc_testsrc.c
>> +++ b/libavfilter/vsrc_testsrc.c
>> @@ -207,7 +207,13 @@ static av_cold int color_init(AVFilterContext *ctx)
>>
>>  static int color_query_formats(AVFilterContext *ctx)
>>  {
>> -    return ff_set_common_formats(ctx,
>> ff_draw_supported_pixel_formats(0));
>> +    int ret;
>> +
>> +    ret = ff_set_common_formats(ctx,
>> ff_draw_supported_pixel_formats(0));
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return ff_set_common_color_ranges(ctx, ff_mpeg_color_ranges());
>>  }
>>
>>  static int color_config_props(AVFilterLink *inlink)
>> @@ -653,11 +659,16 @@ static int test_query_formats(AVFilterContext *ctx)
>>      static const enum AVPixelFormat pix_fmts[] = {
>>          AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
>>      };
>> +    int ret;
>>
>>      AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
>>      if (!fmts_list)
>>          return AVERROR(ENOMEM);
>> -    return ff_set_common_formats(ctx, fmts_list);
>> +    ret = ff_set_common_formats(ctx, fmts_list);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return ff_set_common_color_ranges(ctx, ff_jpeg_color_ranges());
>>  }
>>
>>  static const AVFilterPad avfilter_vsrc_testsrc_outputs[] = {
>
> Regards,
>
> --
>   Nicolas George
>
diff mbox

Patch

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 3aad564b81..a8fbcdecfb 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -144,6 +144,8 @@  static char *choose_pix_fmts(OutputFilter *ofilter)
             const char *name = av_get_pix_fmt_name(*p);
             avio_printf(s, "%s|", name);
         }
+        if (av_color_range_name(ost->enc->color_range))
+            avio_printf(s, ":color_ranges=%s|", av_color_range_name(ost->enc->color_range));
         len = avio_close_dyn_buf(s, &ret);
         ret[len - 1] = 0;
         return ret;
@@ -447,7 +449,6 @@  static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
     OutputStream *ost = ofilter->ost;
     OutputFile    *of = output_files[ost->file_index];
     AVFilterContext *last_filter = out->filter_ctx;
-    AVDictionaryEntry *cre = NULL;
     int pad_idx = out->pad_idx;
     int ret;
     char name[255];
@@ -460,9 +461,7 @@  static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
     if (ret < 0)
         return ret;
 
-    cre = av_dict_get(ost->encoder_opts, "color_range", NULL, 0);
-
-    if (ofilter->width || ofilter->height || (cre && cre->value) || ost->enc->color_range) {
+    if (ofilter->width || ofilter->height) {
         char args[255];
         AVFilterContext *filter;
         AVDictionaryEntry *e = NULL;
@@ -475,12 +474,6 @@  static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
             av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value);
         }
 
-        if (cre && cre->value) {
-            av_strlcatf(args, sizeof(args), ":out_range=%s", cre->value);
-        } else if (ost->enc->color_range) {
-            av_strlcatf(args, sizeof(args), ":out_range=%s", av_color_range_name(ost->enc->color_range));
-        }
-
         snprintf(name, sizeof(name), "scaler_out_%d_%d",
                  ost->file_index, ost->index);
         if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 4a579bb49d..c3a19d100c 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -262,6 +262,9 @@  int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
     if (link->out_formats)
         ff_formats_changeref(&link->out_formats,
                              &filt->outputs[filt_dstpad_idx]->out_formats);
+    if (link->out_color_ranges)
+        ff_formats_changeref(&link->out_color_ranges,
+                             &filt->outputs[filt_dstpad_idx]->out_color_ranges);
     if (link->out_samplerates)
         ff_formats_changeref(&link->out_samplerates,
                              &filt->outputs[filt_dstpad_idx]->out_samplerates);
@@ -785,6 +788,8 @@  static void free_link(AVFilterLink *link)
 
     ff_formats_unref(&link->in_formats);
     ff_formats_unref(&link->out_formats);
+    ff_formats_unref(&link->in_color_ranges);
+    ff_formats_unref(&link->out_color_ranges);
     ff_formats_unref(&link->in_samplerates);
     ff_formats_unref(&link->out_samplerates);
     ff_channel_layouts_unref(&link->in_channel_layouts);
@@ -970,9 +975,7 @@  int avfilter_init_str(AVFilterContext *filter, const char *args)
         }
 
 #if FF_API_OLD_FILTER_OPTS_ERROR
-            if (   !strcmp(filter->filter->name, "format")     ||
-                   !strcmp(filter->filter->name, "noformat")   ||
-                   !strcmp(filter->filter->name, "frei0r")     ||
+            if (   !strcmp(filter->filter->name, "frei0r")     ||
                    !strcmp(filter->filter->name, "frei0r_src") ||
                    !strcmp(filter->filter->name, "ocv")        ||
                    !strcmp(filter->filter->name, "pan")        ||
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 40ad28ffd8..138bdeb5c9 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -456,7 +456,7 @@  struct AVFilterLink {
      *****************************************************************
      */
     /**
-     * Lists of formats and channel layouts supported by the input and output
+     * Lists of formats, color_ranges and channel layouts supported by the input and output
      * filters respectively. These lists are used for negotiating the format
      * to actually be used, which will be loaded into the format and
      * channel_layout members, above, when chosen.
@@ -464,6 +464,8 @@  struct AVFilterLink {
      */
     AVFilterFormats *in_formats;
     AVFilterFormats *out_formats;
+    AVFilterFormats  *in_color_ranges;
+    AVFilterFormats *out_color_ranges;
 
     /**
      * Lists of channel layouts and sample rates used for automatic
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index a959a9ef3f..ee5ddebe22 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -360,6 +360,9 @@  static int formats_declared(AVFilterContext *f)
             !(f->inputs[i]->out_samplerates &&
               f->inputs[i]->out_channel_layouts))
             return 0;
+        if (f->inputs[i]->type == AVMEDIA_TYPE_VIDEO &&
+            !(f->inputs[i]->out_color_ranges))
+            return 0;
     }
     for (i = 0; i < f->nb_outputs; i++) {
         if (!f->outputs[i]->in_formats)
@@ -368,6 +371,9 @@  static int formats_declared(AVFilterContext *f)
             !(f->outputs[i]->in_samplerates &&
               f->outputs[i]->in_channel_layouts))
             return 0;
+        if (f->outputs[i]->type == AVMEDIA_TYPE_VIDEO &&
+            !(f->outputs[i]->in_color_ranges))
+            return 0;
     }
     return 1;
 }
@@ -485,6 +491,15 @@  static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
                         convert_needed = 1;
             }
 
+            if (link->type == AVMEDIA_TYPE_VIDEO) {
+                if (link->in_color_ranges != link->out_color_ranges
+                    && link->in_color_ranges && link->out_color_ranges)
+                    if (!can_merge_formats(link->in_color_ranges,
+                                           link->out_color_ranges,
+                                           0, 1))
+                        convert_needed = 1;
+            }
+
 #define MERGE_DISPATCH(field, statement)                                     \
             if (!(link->in_ ## field && link->out_ ## field)) {              \
                 count_delayed++;                                             \
@@ -507,6 +522,13 @@  static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
                         convert_needed = 1;
                 )
             }
+            if (link->type == AVMEDIA_TYPE_VIDEO) {
+                MERGE_DISPATCH(color_ranges,
+                    if (!ff_merge_samplerates(link->in_color_ranges,
+                                              link->out_color_ranges))
+                        convert_needed = 1;
+                )
+            }
             MERGE_DISPATCH(formats,
                 if (!ff_merge_formats(link->in_formats, link->out_formats,
                                       link->type))
@@ -580,6 +602,12 @@  static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
                 av_assert0( inlink->out_formats->refcount > 0);
                 av_assert0(outlink-> in_formats->refcount > 0);
                 av_assert0(outlink->out_formats->refcount > 0);
+                if (outlink->type == AVMEDIA_TYPE_VIDEO) {
+                    av_assert0( inlink-> in_color_ranges->refcount > 0);
+                    av_assert0( inlink->out_color_ranges->refcount > 0);
+                    av_assert0(outlink-> in_color_ranges->refcount > 0);
+                    av_assert0(outlink->out_color_ranges->refcount > 0);
+                }
                 if (outlink->type == AVMEDIA_TYPE_AUDIO) {
                     av_assert0( inlink-> in_samplerates->refcount > 0);
                     av_assert0( inlink->out_samplerates->refcount > 0);
@@ -593,6 +621,12 @@  static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
                 if (!ff_merge_formats( inlink->in_formats,  inlink->out_formats,  inlink->type) ||
                     !ff_merge_formats(outlink->in_formats, outlink->out_formats, outlink->type))
                     ret = AVERROR(ENOSYS);
+                if (inlink->type == AVMEDIA_TYPE_VIDEO &&
+                    (!ff_merge_samplerates(inlink->in_color_ranges, inlink->out_color_ranges)))
+                    ret = AVERROR(ENOSYS);
+                if (outlink->type == AVMEDIA_TYPE_VIDEO &&
+                    (!ff_merge_samplerates(outlink->in_color_ranges, outlink->out_color_ranges)))
+                    ret = AVERROR(ENOSYS);
                 if (inlink->type == AVMEDIA_TYPE_AUDIO &&
                     (!ff_merge_samplerates(inlink->in_samplerates,
                                            inlink->out_samplerates) ||
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 897396cac4..8fe109106b 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -45,6 +45,8 @@  typedef struct BufferSinkContext {
     /* only used for video */
     enum AVPixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
     int pixel_fmts_size;
+    enum AVColorRange *color_ranges;          ///< list of accepted color ranges, must be terminated with 0
+    int color_ranges_size;
 
     /* only used for audio */
     enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
@@ -130,11 +132,13 @@  int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
 AVBufferSinkParams *av_buffersink_params_alloc(void)
 {
     static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
+    static const int color_ranges[] = { -1};
     AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
     if (!params)
         return NULL;
 
     params->pixel_fmts = pixel_fmts;
+    params->color_ranges = color_ranges;
     return params;
 }
 
@@ -211,6 +215,8 @@  static av_cold int vsink_init(AVFilterContext *ctx, void *opaque)
     if (params) {
         if ((ret = av_opt_set_int_list(buf, "pix_fmts", params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0)
             return ret;
+        if ((ret = av_opt_set_int_list(buf, "color_ranges", params->color_ranges, -1, 0)) < 0)
+            return ret;
     }
 
     return common_init(ctx);
@@ -227,16 +233,25 @@  static int vsink_query_formats(AVFilterContext *ctx)
 {
     BufferSinkContext *buf = ctx->priv;
     AVFilterFormats *formats = NULL;
+    AVFilterFormats *color_ranges = NULL;
     unsigned i;
     int ret;
 
     CHECK_LIST_SIZE(pixel_fmts)
+    CHECK_LIST_SIZE(color_ranges)
     if (buf->pixel_fmts_size) {
         for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
             if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0)
                 return ret;
         if ((ret = ff_set_common_formats(ctx, formats)) < 0)
             return ret;
+    }
+    if (buf->color_ranges_size) {
+        for (i = 0; i < NB_ITEMS(buf->color_ranges); i++)
+            if ((ret = ff_add_format(&color_ranges, buf->color_ranges[i])) < 0)
+                return ret;
+        if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
+            return ret;
     } else {
         if ((ret = ff_default_query_formats(ctx)) < 0)
             return ret;
@@ -318,6 +333,7 @@  static int asink_query_formats(AVFilterContext *ctx)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 static const AVOption buffersink_options[] = {
     { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
+    { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS },
     { NULL },
 };
 #undef FLAGS
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index e6d6504832..3a74a039a2 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -64,6 +64,7 @@  int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flag
  */
 typedef struct AVBufferSinkParams {
     const enum AVPixelFormat *pixel_fmts; ///< list of allowed pixel formats, terminated by AV_PIX_FMT_NONE
+    const enum AVPixelFormat *color_ranges; ///< list of allowed color ranges, terminated by AVCOL_RANGE_UNSPECIFIED
 } AVBufferSinkParams;
 
 /**
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index 51a1a9fb49..e450a2bca7 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -412,6 +412,7 @@  static int query_formats(AVFilterContext *ctx)
     BufferSourceContext *c = ctx->priv;
     AVFilterChannelLayouts *channel_layouts = NULL;
     AVFilterFormats *formats = NULL;
+    AVFilterFormats *color_ranges = NULL;
     AVFilterFormats *samplerates = NULL;
     int ret;
 
@@ -420,6 +421,9 @@  static int query_formats(AVFilterContext *ctx)
         if ((ret = ff_add_format         (&formats, c->pix_fmt)) < 0 ||
             (ret = ff_set_common_formats (ctx     , formats   )) < 0)
             return ret;
+        if ((ret = ff_add_format         (&color_ranges, c->color_range)) < 0 ||
+            (ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
+            return ret;
         break;
     case AVMEDIA_TYPE_AUDIO:
         if ((ret = ff_add_format             (&formats    , c->sample_fmt )) < 0 ||
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index d4de862237..560b348524 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -289,6 +289,15 @@  AVFilterFormats *ff_make_format_list(const int *fmts)
     return formats;
 }
 
+AVFilterFormats *ff_make_color_range_list(const int *fmts)
+{
+    MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
+    while (count--)
+        formats->formats[count] = fmts[count];
+
+    return formats;
+}
+
 AVFilterChannelLayouts *ff_make_formatu64_list(const uint64_t *fmts)
 {
     MAKE_FORMAT_LIST(AVFilterChannelLayouts,
@@ -398,6 +407,37 @@  AVFilterFormats *ff_all_samplerates(void)
     return ret;
 }
 
+AVFilterFormats *ff_jpeg_color_ranges(void)
+{
+    AVFilterFormats *ret = NULL;
+
+    if (ff_add_format(&ret, AVCOL_RANGE_JPEG) < 0)
+        return NULL;
+
+    return ret;
+}
+
+AVFilterFormats *ff_mpeg_color_ranges(void)
+{
+    AVFilterFormats *ret = NULL;
+
+    if (ff_add_format(&ret, AVCOL_RANGE_MPEG) < 0)
+        return NULL;
+
+    return ret;
+}
+
+AVFilterFormats *ff_all_color_ranges(void)
+{
+    AVFilterFormats *fmts = NULL;
+    int ret;
+
+    ret = ff_add_format(&fmts, AVCOL_RANGE_UNSPECIFIED);
+    ret = ff_add_format(&fmts, AVCOL_RANGE_MPEG);
+    ret = ff_add_format(&fmts, AVCOL_RANGE_JPEG);
+    return fmts;
+}
+
 AVFilterChannelLayouts *ff_all_channel_layouts(void)
 {
     AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
@@ -560,6 +600,13 @@  int ff_set_common_samplerates(AVFilterContext *ctx,
                        ff_formats_ref, ff_formats_unref, formats);
 }
 
+int ff_set_common_color_ranges(AVFilterContext *ctx,
+                               AVFilterFormats *color_ranges)
+{
+    SET_COMMON_FORMATS(ctx, color_ranges, in_color_ranges, out_color_ranges,
+                       ff_formats_ref, ff_formats_unref, formats);
+}
+
 /**
  * A helper for query_formats() which sets all links to the same list of
  * formats. If there are no links hooked to this filter, the list of formats is
@@ -590,6 +637,11 @@  static int default_query_formats_common(AVFilterContext *ctx,
         if (ret < 0)
             return ret;
     }
+    if (type == AVMEDIA_TYPE_VIDEO) {
+        ret = ff_set_common_color_ranges(ctx, ff_all_color_ranges());
+        if (ret < 0)
+            return ret;
+    }
 
     return 0;
 }
@@ -659,6 +711,17 @@  int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
     return 0;
 }
 
+int ff_parse_color_range(int *ret, const char *arg, void *log_ctx)
+{
+    int color_range = av_color_range_from_name(arg);
+    if (color_range < 0) {
+        av_log(log_ctx, AV_LOG_ERROR, "Invalid color range '%s'\n", arg);
+        return AVERROR(EINVAL);
+    }
+    *ret = color_range;
+    return 0;
+}
+
 int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
                             void *log_ctx)
 {
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index 870809b5a0..6706f76dce 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -166,6 +166,9 @@  av_warn_unused_result
 int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
 
 av_warn_unused_result
+int ff_set_common_color_ranges(AVFilterContext *ctx, AVFilterFormats *color_ranges);
+
+av_warn_unused_result
 int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
 
 /**
@@ -205,6 +208,16 @@  av_warn_unused_result
 AVFilterFormats *ff_make_format_list(const int *fmts);
 
 /**
+ * Create a list of supported color ranges. This is intended for use in
+ * AVFilter->query_formats().
+ *
+ * @param fmts list of color ranges, terminated by -1
+ * @return the format list, with no existing references
+ */
+av_warn_unused_result
+AVFilterFormats *ff_make_color_range_list(const int *color_ranges);
+
+/**
  * Add fmt to the list of media formats contained in *avff.
  * If *avff is NULL the function allocates the filter formats struct
  * and puts its pointer in *avff.
@@ -222,6 +235,24 @@  av_warn_unused_result
 AVFilterFormats *ff_all_formats(enum AVMediaType type);
 
 /**
+ * Return a list of all color ranges supported by FFmpeg.
+ */
+av_warn_unused_result
+AVFilterFormats *ff_all_color_ranges(void);
+
+/**
+ * Return a list of all mpeg color ranges supported by FFmpeg.
+ */
+av_warn_unused_result
+AVFilterFormats *ff_mpeg_color_ranges(void);
+
+/**
+ * Return a list of all jpeg color ranges supported by FFmpeg.
+ */
+av_warn_unused_result
+AVFilterFormats *ff_jpeg_color_ranges(void);
+
+/**
  * Construct a formats list containing all planar sample formats.
  */
 av_warn_unused_result
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index f9679ed1d7..ca806d9443 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -191,6 +191,17 @@  av_warn_unused_result
 int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx);
 
 /**
+ * Parse a color range.
+ *
+ * @param ret unsigned enum pointer to where the value should be written
+ * @param arg string to parse
+ * @param log_ctx log context
+ * @return >= 0 in case of success, a negative AVERROR code on error
+ */
+av_warn_unused_result
+int ff_parse_color_range(int *ret, const char *arg, void *log_ctx);
+
+/**
  * Parse a time base.
  *
  * @param ret unsigned AVRational pointer to where the value should be written
diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
index a57c99d797..067c03aa5a 100644
--- a/libavfilter/vf_format.c
+++ b/libavfilter/vf_format.c
@@ -38,18 +38,21 @@ 
 typedef struct FormatContext {
     const AVClass *class;
     char *pix_fmts;
+    char *color_ranges_str;
 
     /**
      * pix_fmts parsed into AVPixelFormats and terminated with
      * AV_PIX_FMT_NONE
      */
     enum AVPixelFormat *formats;
+    int *color_ranges;
 } FormatContext;
 
 static av_cold void uninit(AVFilterContext *ctx)
 {
     FormatContext *s = ctx->priv;
     av_freep(&s->formats);
+    av_freep(&s->color_ranges);
 }
 
 static av_cold int init(AVFilterContext *ctx)
@@ -57,6 +60,7 @@  static av_cold int init(AVFilterContext *ctx)
     FormatContext *s = ctx->priv;
     char *cur, *sep;
     int nb_formats = 1;
+    int nb_color_ranges = 1;
     int i;
     int ret;
 
@@ -91,6 +95,37 @@  static av_cold int init(AVFilterContext *ctx)
     }
     s->formats[nb_formats] = AV_PIX_FMT_NONE;
 
+    if (!s->color_ranges_str) {
+        av_log(ctx, AV_LOG_ERROR, "Empty output color range string.\n");
+        return AVERROR(EINVAL);
+    }
+
+    /* count the color ranges */
+    cur = s->color_ranges_str;
+    while ((cur = strchr(cur, '|'))) {
+        nb_color_ranges++;
+        if (*cur)
+            cur++;
+    }
+
+    s->color_ranges = av_malloc_array(nb_color_ranges + 1, sizeof(*s->color_ranges));
+    if (!s->color_ranges)
+        return AVERROR(ENOMEM);
+
+    /* parse the list of formats */
+    cur = s->color_ranges_str;
+    for (i = 0; i < nb_color_ranges; i++) {
+        sep = strchr(cur, '|');
+        if (sep)
+            *sep++ = 0;
+
+        if ((ret = ff_parse_color_range(&s->color_ranges[i], cur, ctx)) < 0)
+            return ret;
+
+        cur = sep;
+    }
+    s->color_ranges[nb_color_ranges] = -1;
+
     if (!strcmp(ctx->filter->name, "noformat")) {
         const AVPixFmtDescriptor *desc = NULL;
         enum AVPixelFormat *formats_allowed;
@@ -130,17 +165,26 @@  static int query_formats(AVFilterContext *ctx)
 {
     FormatContext *s = ctx->priv;
     AVFilterFormats *formats = ff_make_format_list(s->formats);
+    AVFilterFormats *color_ranges = ff_make_color_range_list(s->color_ranges);
+    int ret;
 
     if (!formats)
         return AVERROR(ENOMEM);
 
-    return ff_set_common_formats(ctx, formats);
+    ret = ff_set_common_formats(ctx, formats);
+    if (ret < 0)
+        return ret;
+
+    if (!color_ranges)
+        return AVERROR(ENOMEM);
+    return ff_set_common_color_ranges(ctx, color_ranges);
 }
 
 
 #define OFFSET(x) offsetof(FormatContext, x)
 static const AVOption options[] = {
     { "pix_fmts", "A '|'-separated list of pixel formats", OFFSET(pix_fmts), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
+    { "color_ranges", "A '|'-separated list of color ranges", OFFSET(color_ranges_str), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
     { NULL }
 };
 
diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
index abdf04708b..c7af77b669 100644
--- a/libavfilter/vf_noise.c
+++ b/libavfilter/vf_noise.c
@@ -142,7 +142,11 @@  static int query_formats(AVFilterContext *ctx)
                 return ret;
     }
 
-    return ff_set_common_formats(ctx, formats);
+    ret = ff_set_common_formats(ctx, formats);
+    if (ret < 0)
+        return ret;
+
+    return ff_set_common_color_ranges(ctx, ff_all_color_ranges());
 }
 
 static int config_input(AVFilterLink *inlink)
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 802f841cc3..a571673b37 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -157,7 +157,9 @@  static av_cold void uninit(AVFilterContext *ctx)
 
 static int query_formats(AVFilterContext *ctx)
 {
+    ScaleContext *scale = ctx->priv;
     AVFilterFormats *formats;
+    AVFilterFormats *color_ranges;
     enum AVPixelFormat pix_fmt;
     int ret;
 
@@ -174,10 +176,14 @@  static int query_formats(AVFilterContext *ctx)
         }
         if ((ret = ff_formats_ref(formats, &ctx->inputs[0]->out_formats)) < 0)
             return ret;
+        color_ranges = ff_all_color_ranges();
+        if ((ret = ff_formats_ref(color_ranges, &ctx->inputs[0]->out_color_ranges)) < 0)
+            return ret;
     }
     if (ctx->outputs[0]) {
         const AVPixFmtDescriptor *desc = NULL;
         formats = NULL;
+        color_ranges = NULL;
         while ((desc = av_pix_fmt_desc_next(desc))) {
             pix_fmt = av_pix_fmt_desc_get_id(desc);
             if ((sws_isSupportedOutput(pix_fmt) || pix_fmt == AV_PIX_FMT_PAL8 ||
@@ -188,6 +194,12 @@  static int query_formats(AVFilterContext *ctx)
         }
         if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->in_formats)) < 0)
             return ret;
+
+        ret = ff_add_format(&color_ranges, scale->out_range ? scale->out_range : AVCOL_RANGE_MPEG);
+        if (ret < 0)
+            return ret;
+        if ((ret = ff_formats_ref(color_ranges, &ctx->outputs[0]->in_color_ranges)) < 0)
+            return ret;
     }
 
     return 0;
@@ -276,6 +288,7 @@  static int config_props(AVFilterLink *outlink)
     scale->isws[0] = scale->isws[1] = scale->sws = NULL;
     if (inlink0->w == outlink->w &&
         inlink0->h == outlink->h &&
+        inlink0->color_range == outlink->color_range &&
         !scale->out_color_matrix &&
         scale->in_range == scale->out_range &&
         inlink0->format == outlink->format)
@@ -348,11 +361,11 @@  static int config_props(AVFilterLink *outlink)
     } else
         outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
 
-    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",
+    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d cr:%d -> w:%d h:%d fmt:%s sar:%d/%d cr:%d flags:0x%0x\n",
            inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
-           inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
+           inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, inlink->color_range,
            outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
-           outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
+           outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den, outlink->color_range,
            scale->flags);
     return 0;
 
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index eb12335472..a531e76f06 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -207,7 +207,13 @@  static av_cold int color_init(AVFilterContext *ctx)
 
 static int color_query_formats(AVFilterContext *ctx)
 {
-    return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+    int ret;
+
+    ret = ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+    if (ret < 0)
+        return ret;
+
+    return ff_set_common_color_ranges(ctx, ff_mpeg_color_ranges());
 }
 
 static int color_config_props(AVFilterLink *inlink)
@@ -653,11 +659,16 @@  static int test_query_formats(AVFilterContext *ctx)
     static const enum AVPixelFormat pix_fmts[] = {
         AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
     };
+    int ret;
 
     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
     if (!fmts_list)
         return AVERROR(ENOMEM);
-    return ff_set_common_formats(ctx, fmts_list);
+    ret = ff_set_common_formats(ctx, fmts_list);
+    if (ret < 0)
+        return ret;
+
+    return ff_set_common_color_ranges(ctx, ff_jpeg_color_ranges());
 }
 
 static const AVFilterPad avfilter_vsrc_testsrc_outputs[] = {