Message ID | 20171211174458.10033-1-onemda@gmail.com |
---|---|
State | Superseded |
Headers | show |
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,
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 --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[] = {
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(-)