From: Niklas Haas <ffmpeg@haasn.xyz> To: ffmpeg-devel@ffmpeg.org Cc: Niklas Haas <git@haasn.dev> Subject: [FFmpeg-devel] [PATCH 03/25] avfilter: add negotiation API for color space/range Date: Thu, 9 Nov 2023 13:19:35 +0100 Message-ID: <20231109122534.124157-4-ffmpeg@haasn.xyz> (raw) In-Reply-To: <20231109122534.124157-1-ffmpeg@haasn.xyz> From: Niklas Haas <git@haasn.dev> Motivated by YUVJ removal. This change will allow full negotiation between color ranges and matrices as needed. By default, all ranges and matrices are marked as supported. Because grayscale formats are currently handled very inconsistently (and in particular, assumed as forced full-range by swscale), we exclude them from negotiation altogether for the time being, to get this API merged. After filter negotiation is available, we can relax the grayscale-is-forced-jpeg restriction again, when it will be more feasible to do so without breaking a million test cases. Note that this commit updates one FATE test as a consequence of the sanity fallback for non-YUV formats. In particular, the test case now writes rgb24(pc, gbr/unspecified/unspecified) to the matroska file, instead of rgb24(unspecified/unspecified/unspecified) as before. --- doc/APIchanges | 8 ++ libavfilter/avfilter.c | 19 ++++- libavfilter/avfilter.h | 28 ++++++ libavfilter/avfiltergraph.c | 166 +++++++++++++++++++++++++++++++++++- libavfilter/formats.c | 122 +++++++++++++++++++++++++- libavfilter/formats.h | 54 ++++++++++++ libavfilter/internal.h | 6 ++ libavfilter/vaapi_vpp.c | 4 + libavfilter/version.h | 2 +- libavfilter/video.c | 2 + tests/ref/fate/shortest-sub | 4 +- 11 files changed, 405 insertions(+), 10 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index 12383a28d3..ce3f90a674 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,14 @@ The last version increases of all libraries were on 2023-02-09 API changes, most recent first: +2023-11-xx - xxxxxxxxxx - lavf 58.14.100 - avfilter.h formats.h + Add AVFilterFormatsConfig.color_spaces, AVFilterFormatsConfig.color_ranges, + AVFilterLink.colorspace, AVFilterLink.color_range, ff_all_color_spaces, + ff_all_color_ranges, ff_set_common_color_spaces, ff_set_common_color_ranges, + ff_set_common_color_spaces_from_list, ff_set_common_color_ranges_from_list, + ff_set_common_all_color_spaces, ff_set_common_all_color_ranges, + ff_formats_check_color_spaces, ff_formats_check_color_ranges. + 2023-11-08 - xxxxxxxxxx - lavu 58.32.100 - channel_layout.h Add AV_CH_LAYOUT_7POINT2POINT3 and AV_CHANNEL_LAYOUT_7POINT2POINT3. Add AV_CH_LAYOUT_9POINT1POINT4_BACK and AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK. diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index ab7782862a..77bfec00c5 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -185,6 +185,7 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, link->type = src->output_pads[srcpad].type; av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1); link->format = -1; + link->colorspace = AVCOL_SPC_UNSPECIFIED; ff_framequeue_init(&link->fifo, &src->graph->internal->frame_queues); return 0; @@ -286,6 +287,12 @@ int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, if (link->outcfg.formats) ff_formats_changeref(&link->outcfg.formats, &filt->outputs[filt_dstpad_idx]->outcfg.formats); + if (link->outcfg.color_spaces) + ff_formats_changeref(&link->outcfg.color_spaces, + &filt->outputs[filt_dstpad_idx]->outcfg.color_spaces); + if (link->outcfg.color_ranges) + ff_formats_changeref(&link->outcfg.color_ranges, + &filt->outputs[filt_dstpad_idx]->outcfg.color_ranges); if (link->outcfg.samplerates) ff_formats_changeref(&link->outcfg.samplerates, &filt->outputs[filt_dstpad_idx]->outcfg.samplerates); @@ -730,6 +737,10 @@ static void free_link(AVFilterLink *link) ff_formats_unref(&link->incfg.formats); ff_formats_unref(&link->outcfg.formats); + ff_formats_unref(&link->incfg.color_spaces); + ff_formats_unref(&link->outcfg.color_spaces); + ff_formats_unref(&link->incfg.color_ranges); + ff_formats_unref(&link->outcfg.color_ranges); ff_formats_unref(&link->incfg.samplerates); ff_formats_unref(&link->outcfg.samplerates); ff_channel_layouts_unref(&link->incfg.channel_layouts); @@ -987,9 +998,11 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) strcmp(link->dst->filter->name, "idet") && strcmp(link->dst->filter->name, "null") && strcmp(link->dst->filter->name, "scale")) { - av_assert1(frame->format == link->format); - av_assert1(frame->width == link->w); - av_assert1(frame->height == link->h); + av_assert1(frame->format == link->format); + av_assert1(frame->width == link->w); + av_assert1(frame->height == link->h); + av_assert1(frame->colorspace == link->color_space); + av_assert1(frame->color_range == link->color_range); } frame->sample_aspect_ratio = link->sample_aspect_ratio; diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index d69381aed4..246d000251 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -301,6 +301,14 @@ typedef struct AVFilter { * @ref AVFilterFormatsConfig.formats "incfg.formats" * on every output link to a list of pixel/sample formats that the filter * supports on that link. + * For video links, this filter may also set + * @ref AVFilterFormatsConfig.color_spaces "incfg.color_spaces" + * / + * @ref AVFilterFormatsConfig.color_spaces "outcfg.color_spaces" + * and @ref AVFilterFormatsConfig.color_ranges "incfg.color_ranges" + * / + * @ref AVFilterFormatsConfig.color_ranges "outcfg.color_ranges" + * analogously. * For audio links, this filter must also set * @ref AVFilterFormatsConfig.samplerates "incfg.samplerates" * / @@ -322,6 +330,10 @@ typedef struct AVFilter { * to indicate that this filter supports each of these pixel formats, * provided that all inputs and outputs use the same pixel format. * + * In addition to that the generic code will mark all inputs + * and all outputs as supporting all color spaces and ranges, as + * long as all inputs and outputs use the same color space/range. + * * This list must never be NULL if the union is in this state. * The type of all inputs and outputs of filters using this must * be AVMEDIA_TYPE_VIDEO. @@ -514,6 +526,12 @@ typedef struct AVFilterFormatsConfig { */ AVFilterChannelLayouts *channel_layouts; + /** + * Lists of supported YUV color metadata, only for YUV video. + */ + AVFilterFormats *color_spaces; ///< AVColorSpace + AVFilterFormats *color_ranges; ///< AVColorRange + } AVFilterFormatsConfig; /** @@ -565,6 +583,16 @@ struct AVFilterLink { AVChannelLayout ch_layout; ///< channel layout of current buffer (see libavutil/channel_layout.h) + /** + * For non-YUV links, these are respectively set to fallback values (as + * appropriate for that colorspace). + * + * Note: This includes grayscale formats, as these are currently treated + * as forced full range always. + */ + enum AVColorSpace colorspace; ///< agreed upon YUV color space + enum AVColorRange color_range; ///< agreed upon YUV color range + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavfilter and can be changed and diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 625cbc022e..e7fabe85ea 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -298,7 +298,9 @@ static int filter_link_check_formats(void *log, AVFilterLink *link, AVFilterForm switch (link->type) { case AVMEDIA_TYPE_VIDEO: - if ((ret = ff_formats_check_pixel_formats(log, cfg->formats)) < 0) + if ((ret = ff_formats_check_pixel_formats(log, cfg->formats)) < 0 || + (ret = ff_formats_check_color_spaces(log, cfg->color_spaces)) < 0 || + (ret = ff_formats_check_color_ranges(log, cfg->color_ranges)) < 0) return ret; break; @@ -365,6 +367,10 @@ static int formats_declared(AVFilterContext *f) for (i = 0; i < f->nb_inputs; i++) { if (!f->inputs[i]->outcfg.formats) return 0; + if (f->inputs[i]->type == AVMEDIA_TYPE_VIDEO && + !(f->inputs[i]->outcfg.color_ranges && + f->inputs[i]->outcfg.color_spaces)) + return 0; if (f->inputs[i]->type == AVMEDIA_TYPE_AUDIO && !(f->inputs[i]->outcfg.samplerates && f->inputs[i]->outcfg.channel_layouts)) @@ -373,6 +379,10 @@ static int formats_declared(AVFilterContext *f) for (i = 0; i < f->nb_outputs; i++) { if (!f->outputs[i]->incfg.formats) return 0; + if (f->outputs[i]->type == AVMEDIA_TYPE_VIDEO && + !(f->outputs[i]->incfg.color_ranges && + f->outputs[i]->incfg.color_spaces)) + return 0; if (f->outputs[i]->type == AVMEDIA_TYPE_AUDIO && !(f->outputs[i]->incfg.samplerates && f->outputs[i]->incfg.channel_layouts)) @@ -493,7 +503,16 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) av_assert0( inlink->outcfg.formats->refcount > 0); av_assert0(outlink->incfg.formats->refcount > 0); av_assert0(outlink->outcfg.formats->refcount > 0); - if (outlink->type == AVMEDIA_TYPE_AUDIO) { + if (outlink->type == AVMEDIA_TYPE_VIDEO) { + av_assert0( inlink-> incfg.color_spaces->refcount > 0); + av_assert0( inlink->outcfg.color_spaces->refcount > 0); + av_assert0(outlink-> incfg.color_spaces->refcount > 0); + av_assert0(outlink->outcfg.color_spaces->refcount > 0); + av_assert0( inlink-> incfg.color_ranges->refcount > 0); + av_assert0( inlink->outcfg.color_ranges->refcount > 0); + av_assert0(outlink-> incfg.color_ranges->refcount > 0); + av_assert0(outlink->outcfg.color_ranges->refcount > 0); + } else if (outlink->type == AVMEDIA_TYPE_AUDIO) { av_assert0( inlink-> incfg.samplerates->refcount > 0); av_assert0( inlink->outcfg.samplerates->refcount > 0); av_assert0(outlink-> incfg.samplerates->refcount > 0); @@ -583,6 +602,29 @@ static enum AVSampleFormat find_best_sample_fmt_of_2(enum AVSampleFormat dst_fmt return score1 < score2 ? dst_fmt1 : dst_fmt2; } +int ff_fmt_is_regular_yuv(enum AVPixelFormat fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + if (!desc) + return 0; + if (desc->nb_components < 3) + return 0; /* Grayscale is explicitly full-range in swscale */ + if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL | + AV_PIX_FMT_FLAG_XYZ | AV_PIX_FMT_FLAG_FLOAT)) + return 0; + + switch (fmt) { + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUVJ422P: + case AV_PIX_FMT_YUVJ444P: + case AV_PIX_FMT_YUVJ440P: + case AV_PIX_FMT_YUVJ411P: + return 0; + default: + return 1; + } +} + static int pick_format(AVFilterLink *link, AVFilterLink *ref) { if (!link || !link->incfg.formats) @@ -603,6 +645,7 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) av_get_pix_fmt_name(ref->format), has_alpha); link->incfg.formats->formats[0] = best; } + } else if (link->type == AVMEDIA_TYPE_AUDIO) { if(ref && ref->type == AVMEDIA_TYPE_AUDIO){ enum AVSampleFormat best= AV_SAMPLE_FMT_NONE; @@ -621,7 +664,40 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) link->incfg.formats->nb_formats = 1; link->format = link->incfg.formats->formats[0]; - if (link->type == AVMEDIA_TYPE_AUDIO) { + if (link->type == AVMEDIA_TYPE_VIDEO) { + if (!ff_fmt_is_regular_yuv(link->format)) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); + /* These fields are explicitly documented as affecting YUV only, + * so set them to sane values for other formats. */ + if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) + link->color_range = AVCOL_RANGE_UNSPECIFIED; + else + link->color_range = AVCOL_RANGE_JPEG; + if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_XYZ)) { + link->colorspace = AVCOL_SPC_RGB; + } else { + link->colorspace = AVCOL_SPC_UNSPECIFIED; + } + } else { + if (!link->incfg.color_spaces->nb_formats) { + av_log(link->src, AV_LOG_ERROR, "Cannot select color space for" + " the link between filters %s and %s.\n", link->src->name, + link->dst->name); + return AVERROR(EINVAL); + } + link->incfg.color_spaces->nb_formats = 1; + link->colorspace = link->incfg.color_spaces->formats[0]; + + if (!link->incfg.color_ranges->nb_formats) { + av_log(link->src, AV_LOG_ERROR, "Cannot select color range for" + " the link between filters %s and %s.\n", link->src->name, + link->dst->name); + return AVERROR(EINVAL); + } + link->incfg.color_ranges->nb_formats = 1; + link->color_range = link->incfg.color_ranges->formats[0]; + } + } else if (link->type == AVMEDIA_TYPE_AUDIO) { int ret; if (!link->incfg.samplerates->nb_formats) { @@ -661,6 +737,10 @@ FF_ENABLE_DEPRECATION_WARNINGS ff_formats_unref(&link->outcfg.samplerates); ff_channel_layouts_unref(&link->incfg.channel_layouts); ff_channel_layouts_unref(&link->outcfg.channel_layouts); + ff_formats_unref(&link->incfg.color_spaces); + ff_formats_unref(&link->outcfg.color_spaces); + ff_formats_unref(&link->incfg.color_ranges); + ff_formats_unref(&link->outcfg.color_ranges); return 0; } @@ -822,6 +902,82 @@ static void swap_samplerates(AVFilterGraph *graph) swap_samplerates_on_filter(graph->filters[i]); } +static void swap_color_spaces_on_filter(AVFilterContext *filter) +{ + AVFilterLink *link = NULL; + enum AVColorSpace csp; + int i; + + for (i = 0; i < filter->nb_inputs; i++) { + link = filter->inputs[i]; + if (link->type == AVMEDIA_TYPE_VIDEO && + link->outcfg.color_spaces->nb_formats == 1) + break; + } + if (i == filter->nb_inputs) + return; + + csp = link->outcfg.color_spaces->formats[0]; + + for (i = 0; i < filter->nb_outputs; i++) { + AVFilterLink *outlink = filter->outputs[i]; + if (outlink->type != AVMEDIA_TYPE_VIDEO) + continue; + /* there is no meaningful 'score' between different yuv matrices, + * so just prioritize an exact match if it exists */ + for (int j = 0; j < outlink->incfg.color_spaces->nb_formats; j++) { + if (csp == outlink->incfg.color_spaces->formats[j]) { + FFSWAP(int, outlink->incfg.color_spaces->formats[0], + outlink->incfg.color_spaces->formats[j]); + break; + } + } + } +} + +static void swap_color_spaces(AVFilterGraph *graph) +{ + for (int i = 0; i < graph->nb_filters; i++) + swap_color_spaces_on_filter(graph->filters[i]); +} + +static void swap_color_ranges_on_filter(AVFilterContext *filter) +{ + AVFilterLink *link = NULL; + enum AVColorRange range; + int i; + + for (i = 0; i < filter->nb_inputs; i++) { + link = filter->inputs[i]; + if (link->type == AVMEDIA_TYPE_VIDEO && + link->outcfg.color_ranges->nb_formats == 1) + break; + } + if (i == filter->nb_inputs) + return; + + range = link->outcfg.color_ranges->formats[0]; + + for (i = 0; i < filter->nb_outputs; i++) { + AVFilterLink *outlink = filter->outputs[i]; + if (outlink->type != AVMEDIA_TYPE_VIDEO) + continue; + for (int j = 0; j < outlink->incfg.color_ranges->nb_formats; j++) { + if (range == outlink->incfg.color_ranges->formats[j]) { + FFSWAP(int, outlink->incfg.color_ranges->formats[0], + outlink->incfg.color_ranges->formats[j]); + break; + } + } + } +} + +static void swap_color_ranges(AVFilterGraph *graph) +{ + for (int i = 0; i < graph->nb_filters; i++) + swap_color_ranges_on_filter(graph->filters[i]); +} + #define CH_CENTER_PAIR (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER) #define CH_FRONT_PAIR (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT) #define CH_STEREO_PAIR (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT) @@ -1098,6 +1254,10 @@ static int graph_config_formats(AVFilterGraph *graph, void *log_ctx) if ((ret = reduce_formats(graph)) < 0) return ret; + /* for video filters, ensure that the best colorspace metadata is selected */ + swap_color_spaces(graph); + swap_color_ranges(graph); + /* for audio filters, ensure the best format, sample rate and channel layout * is selected */ swap_sample_fmts(graph); diff --git a/libavfilter/formats.c b/libavfilter/formats.c index d1c97daf64..20f00d2db4 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -321,12 +321,46 @@ static int merge_channel_layouts(void *a, void *b) return merge_channel_layouts_internal(a, b, 0); } +static int merge_generic_internal(AVFilterFormats *a, + AVFilterFormats *b, int check) +{ + av_assert2(check || (a->refcount && b->refcount)); + + if (a == b) + return 1; + + MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 0); + + return 1; +} + +static int can_merge_generic(const void *a, const void *b) +{ + return merge_generic_internal((AVFilterFormats *)a, + (AVFilterFormats *)b, 1); +} + +static int merge_generic(void *a, void *b) +{ + return merge_generic_internal(a, b, 0); +} + static const AVFilterFormatsMerger mergers_video[] = { { .offset = offsetof(AVFilterFormatsConfig, formats), .merge = merge_pix_fmts, .can_merge = can_merge_pix_fmts, }, + { + .offset = offsetof(AVFilterFormatsConfig, color_spaces), + .merge = merge_generic, + .can_merge = can_merge_generic, + }, + { + .offset = offsetof(AVFilterFormatsConfig, color_ranges), + .merge = merge_generic, + .can_merge = can_merge_generic, + }, }; static const AVFilterFormatsMerger mergers_audio[] = { @@ -594,6 +628,33 @@ AVFilterChannelLayouts *ff_all_channel_counts(void) return ret; } +AVFilterFormats *ff_all_color_spaces(void) +{ + AVFilterFormats *ret = NULL; + if (ff_add_format(&ret, AVCOL_SPC_UNSPECIFIED) < 0) + return NULL; + for (int csp = 0; csp < AVCOL_SPC_NB; csp++) { + if (csp == AVCOL_SPC_RESERVED || + csp == AVCOL_SPC_UNSPECIFIED) + continue; + if (ff_add_format(&ret, csp) < 0) + return NULL; + } + + return ret; +} + +AVFilterFormats *ff_all_color_ranges(void) +{ + AVFilterFormats *ret = NULL; + for (int range = 0; range < AVCOL_RANGE_NB; range++) { + if (ff_add_format(&ret, range) < 0) + return NULL; + } + + return ret; +} + #define FORMATS_REF(f, ref, unref_fn) \ void *tmp; \ \ @@ -763,6 +824,42 @@ int ff_set_common_all_samplerates(AVFilterContext *ctx) return ff_set_common_samplerates(ctx, ff_all_samplerates()); } +int ff_set_common_color_spaces(AVFilterContext *ctx, + AVFilterFormats *color_spaces) +{ + SET_COMMON_FORMATS(ctx, color_spaces, AVMEDIA_TYPE_VIDEO, + ff_formats_ref, ff_formats_unref); +} + +int ff_set_common_color_spaces_from_list(AVFilterContext *ctx, + const int *color_ranges) +{ + return ff_set_common_color_spaces(ctx, ff_make_format_list(color_ranges)); +} + +int ff_set_common_all_color_spaces(AVFilterContext *ctx) +{ + return ff_set_common_color_spaces(ctx, ff_all_color_spaces()); +} + +int ff_set_common_color_ranges(AVFilterContext *ctx, + AVFilterFormats *color_ranges) +{ + SET_COMMON_FORMATS(ctx, color_ranges, AVMEDIA_TYPE_VIDEO, + ff_formats_ref, ff_formats_unref); +} + +int ff_set_common_color_ranges_from_list(AVFilterContext *ctx, + const int *color_ranges) +{ + return ff_set_common_color_ranges(ctx, ff_make_format_list(color_ranges)); +} + +int ff_set_common_all_color_ranges(AVFilterContext *ctx) +{ + return ff_set_common_color_ranges(ctx, ff_all_color_ranges()); +} + /** * 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 @@ -817,7 +914,14 @@ int ff_default_query_formats(AVFilterContext *ctx) ret = ff_set_common_formats(ctx, formats); if (ret < 0) return ret; - if (type == AVMEDIA_TYPE_AUDIO) { + if (type == AVMEDIA_TYPE_VIDEO) { + ret = ff_set_common_all_color_spaces(ctx); + if (ret < 0) + return ret; + ret = ff_set_common_all_color_ranges(ctx); + if (ret < 0) + return ret; + } else if (type == AVMEDIA_TYPE_AUDIO) { ret = ff_set_common_all_channel_counts(ctx); if (ret < 0) return ret; @@ -935,6 +1039,22 @@ int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts) return check_list(log, "sample rate", fmts); } +int ff_formats_check_color_spaces(void *log, const AVFilterFormats *fmts) +{ + for (int i = 0; fmts && i < fmts->nb_formats; i++) { + if (fmts->formats[i] == AVCOL_SPC_RESERVED) { + av_log(log, AV_LOG_ERROR, "Invalid color range\n"); + return AVERROR(EINVAL); + } + } + return check_list(log, "color space", fmts); +} + +int ff_formats_check_color_ranges(void *log, const AVFilterFormats *fmts) +{ + return check_list(log, "color range", fmts); +} + static int layouts_compatible(const AVChannelLayout *a, const AVChannelLayout *b) { return !av_channel_layout_compare(a, b) || diff --git a/libavfilter/formats.h b/libavfilter/formats.h index d44890109e..82b3af4be1 100644 --- a/libavfilter/formats.h +++ b/libavfilter/formats.h @@ -130,6 +130,20 @@ AVFilterChannelLayouts *ff_all_channel_counts(void); av_warn_unused_result AVFilterChannelLayouts *ff_make_channel_layout_list(const AVChannelLayout *fmts); +/** + * Construct an AVFilterFormats representing all possible color spaces. + * + * Note: This list does not include AVCOL_SPC_RESERVED. + */ +av_warn_unused_result +AVFilterFormats *ff_all_color_spaces(void); + +/** + * Construct an AVFilterFormats representing all possible color ranges. + */ +av_warn_unused_result +AVFilterFormats *ff_all_color_ranges(void); + /** * Helpers for query_formats() which set all free audio links to the same list * of channel layouts/sample rates. If there are no links hooked to this list, @@ -165,6 +179,38 @@ int ff_set_common_samplerates_from_list(AVFilterContext *ctx, av_warn_unused_result int ff_set_common_all_samplerates(AVFilterContext *ctx); +av_warn_unused_result +int ff_set_common_color_spaces(AVFilterContext *ctx, + AVFilterFormats *color_spaces); +/** + * Equivalent to ff_set_common_color_spaces(ctx, ff_make_format_list(color_spaces)) + */ +av_warn_unused_result +int ff_set_common_color_spaces_from_list(AVFilterContext *ctx, + const int *color_spaces); + +/** + * Equivalent to ff_set_common_color_spaces(ctx, ff_all_color_spaces()) + */ +av_warn_unused_result +int ff_set_common_all_color_spaces(AVFilterContext *ctx); + +av_warn_unused_result +int ff_set_common_color_ranges(AVFilterContext *ctx, + AVFilterFormats *color_ranges); +/** + * Equivalent to ff_set_common_color_ranges(ctx, ff_make_format_list(color_ranges)) + */ +av_warn_unused_result +int ff_set_common_color_ranges_from_list(AVFilterContext *ctx, + const int *color_ranges); + +/** + * Equivalent to ff_set_common_color_ranges(ctx, ff_all_color_ranges()) + */ +av_warn_unused_result +int ff_set_common_all_color_ranges(AVFilterContext *ctx); + /** * 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 @@ -328,6 +374,14 @@ int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts); */ int ff_formats_check_channel_layouts(void *log, const AVFilterChannelLayouts *fmts); +/** + * Check that fmts is a valid formats list for YUV colorspace metadata. + * + * In particular, check for duplicates. + */ +int ff_formats_check_color_spaces(void *log, const AVFilterFormats *fmts); +int ff_formats_check_color_ranges(void *log, const AVFilterFormats *fmts); + typedef struct AVFilterFormatMerger { unsigned offset; int (*merge)(void *a, void *b); diff --git a/libavfilter/internal.h b/libavfilter/internal.h index 2dbc5def0a..a6cdf9994c 100644 --- a/libavfilter/internal.h +++ b/libavfilter/internal.h @@ -203,6 +203,12 @@ enum FilterFormatsState { */ int ff_fmt_is_in(int fmt, const int *fmts); +/** + * Returns true if a pixel format is "regular YUV", which includes all pixel + * formats that are affected by YUV colorspace negotiation. + */ +int ff_fmt_is_regular_yuv(enum AVPixelFormat fmt); + /* Functions to parse audio format arguments */ /** diff --git a/libavfilter/vaapi_vpp.c b/libavfilter/vaapi_vpp.c index cf2592e068..59961bfa4a 100644 --- a/libavfilter/vaapi_vpp.c +++ b/libavfilter/vaapi_vpp.c @@ -38,6 +38,10 @@ int ff_vaapi_vpp_query_formats(AVFilterContext *avctx) &avctx->outputs[0]->incfg.formats)) < 0) return err; + if ((err = ff_set_common_all_color_spaces(avctx)) < 0 || + (err = ff_set_common_all_color_ranges(avctx)) < 0) + return err; + return 0; } diff --git a/libavfilter/version.h b/libavfilter/version.h index 537df129cd..7642b670d1 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFILTER_VERSION_MINOR 13 +#define LIBAVFILTER_VERSION_MINOR 14 #define LIBAVFILTER_VERSION_MICRO 100 diff --git a/libavfilter/video.c b/libavfilter/video.c index 42eeb98c28..243762c8fd 100644 --- a/libavfilter/video.c +++ b/libavfilter/video.c @@ -96,6 +96,8 @@ AVFrame *ff_default_get_video_buffer2(AVFilterLink *link, int w, int h, int alig return NULL; frame->sample_aspect_ratio = link->sample_aspect_ratio; + frame->colorspace = link->colorspace; + frame->color_range = link->color_range; return frame; } diff --git a/tests/ref/fate/shortest-sub b/tests/ref/fate/shortest-sub index 9caee587ce..16b1324e83 100644 --- a/tests/ref/fate/shortest-sub +++ b/tests/ref/fate/shortest-sub @@ -1,5 +1,5 @@ -73d142a80965f9e0884a5863abde0dab *tests/data/fate/shortest-sub.matroska -139249 tests/data/fate/shortest-sub.matroska +d6608277c93097383e62388196dc62f0 *tests/data/fate/shortest-sub.matroska +139260 tests/data/fate/shortest-sub.matroska #extradata 1: 167, 0xf7272d5f #tb 0: 1/1000 #media_type 0: video -- 2.42.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2023-11-09 12:26 UTC|newest] Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top 2023-11-09 12:19 [FFmpeg-devel] [RFC PATCH 00/25] YUVJ removal + filter negotiation Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 01/25] avfilter/formats: document ff_default_query_formats Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 02/25] avfilter: always call ff_default_query_formats Niklas Haas 2023-11-27 16:56 ` Anton Khirnov 2023-11-09 12:19 ` Niklas Haas [this message] 2023-12-06 15:03 ` [FFmpeg-devel] [PATCH 03/25] avfilter: add negotiation API for color space/range Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 04/25] fftools/ffmpeg_filter: don't clear buffersrc params Niklas Haas 2023-11-27 16:05 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 05/25] avfilter/buffersrc: add color_space/range parameters Niklas Haas 2023-12-06 15:10 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 06/25] fftools/ffmpeg_filter: configure buffersrc with csp/range Niklas Haas 2023-12-06 15:13 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 07/25] vf_scale: use colorspace negotiation API Niklas Haas 2023-12-07 16:02 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 08/25] avfilter/vf_scale: remove YCgCo check Niklas Haas 2023-12-07 16:04 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 09/25] avfilter/vf_zscale: remove unused variables Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 10/25] avfilter/vf_zscale: switch to colorspace negotiation API Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 11/25] avfilter/vf_libplacebo: don't force dovi frames to bt.2020-ncl Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 12/25] avfilter/vf_libplacebo: switch to colorspace negotiation API Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 13/25] avfilter/buffersink: add color space/range accessors Niklas Haas 2023-12-12 13:08 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 14/25] avfilter/vf_format: re-use AVFilterList for pix_fmt parsing Niklas Haas 2023-12-13 8:48 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 15/25] avfilter/vf_format: add color_ranges/spaces Niklas Haas 2023-12-13 11:33 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 16/25] avfilter/vf_format: allow empty pix_fmts list Niklas Haas 2023-12-13 11:38 ` Anton Khirnov 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 17/25] avcodec: add YUV color space metadata to AVCodec Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 18/25] lavc: set color_ranges for YUVJ-only codecs Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 19/25] (WIP) lavc: set color_ranges for MPEG-only codecs Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 20/25] fftools/ffmpeg_filter: simplify choose_pix_fmts Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 21/25] fftools/ffmpeg_filter: propagate codec yuv metadata to filters Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 22/25] tests/fate: force MPEG range for rawvideo tests Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 23/25] lavfi/lavu/lavc: remove YUVJ pixel formats Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 24/25] avutil/pixdesc: remove old yuvj pixel format check Niklas Haas 2023-11-09 12:19 ` [FFmpeg-devel] [PATCH 25/25] avcodec/encode: enforce AVCodec capabilities at encode time Niklas Haas
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20231109122534.124157-4-ffmpeg@haasn.xyz \ --to=ffmpeg@haasn.xyz \ --cc=ffmpeg-devel@ffmpeg.org \ --cc=git@haasn.dev \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git