[FFmpeg-devel] [WIP][RFC][PATCH] avfilter: negotiate color_range between filters
Paul B Mahol
onemda at gmail.com
Mon Dec 11 20:42:15 EET 2017
On 12/11/17, Nicolas George <george at 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 at 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
>
More information about the ffmpeg-devel
mailing list