PR #25823 opened by Zhao Zhili (quink) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25823 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25823.patch
FFmpeg has no limited range RGB. swscale expands limited range YUV to full range RGB, but this filter inherited the input range, so YUV input produced studio range RGB that other filters read as full range. # Summary of changes Briefly describe what this PR does and why. <!-- If this PR requires new FATE test samples, attach them to the PR and list their target paths below (relative to the fate-suite root). Attached filenames must match the sample's filename: ```fate-samples # e.g. vorbis/new-sample.ogg ``` --> >From 124fb14408d69d572611c25e7ae744661b33bff8 Mon Sep 17 00:00:00 2001 From: Zhao Zhili <[email protected]> Date: Thu, 5 Nov 2026 22:23:14 +0800 Subject: [PATCH] avfilter/vf_scale_d3d12: always output full range RGB FFmpeg has no limited range RGB. swscale expands limited range YUV to full range RGB, but this filter inherited the input range, so YUV input produced studio range RGB that other filters read as full range. --- doc/filters.texi | 16 ++++------------ libavfilter/vf_scale_d3d12.c | 29 +++++++++++++++++------------ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index ec23628067a..6a3ecc8dd60 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -22458,11 +22458,10 @@ Limited range. Full range. @end table -If not specified, it defaults to the input range, except that a -@option{out_color_transfer} of @code{linear} (explicit or defaulted, -see below) always selects @code{full} range. If the range is still -unspecified at that point, it defaults to @code{limited} for YUV -output and @code{full} for RGB output. +This option only applies to YUV output; RGB output is always full range +and @code{limited} is rejected for it. +If not specified, YUV output uses the input range, or @code{limited} if +the input range is unspecified. @item out_color_primaries Set the output color primaries. It accepts the same values as the @@ -22528,13 +22527,6 @@ its HDR color properties: @example scale_d3d12=format=x2bgr10 @end example - -@item -Scale and convert to full-range BGRA, for example before @code{hwdownload} -feeds a renderer that expects full-range RGB: -@example -scale_d3d12=format=bgra:out_range=full -@end example @end itemize @section scharr diff --git a/libavfilter/vf_scale_d3d12.c b/libavfilter/vf_scale_d3d12.c index cadd48e5a02..a726ba2fd1f 100644 --- a/libavfilter/vf_scale_d3d12.c +++ b/libavfilter/vf_scale_d3d12.c @@ -626,8 +626,8 @@ static int d3d12_scale_get_colorspace(AVFilterContext *ctx, int is_rgb, int is_o if (is_output) av_log(ctx, AV_LOG_ERROR, "Studio range linear RGB has no DXGI color " - "space; use out_range=full, or a non-linear " - "out_color_transfer (e.g. bt709)\n"); + "space; use a non-linear out_color_transfer " + "(e.g. bt709)\n"); else av_log(ctx, AV_LOG_ERROR, "Studio range linear RGB has no DXGI color " @@ -1230,7 +1230,7 @@ static int scale_d3d12_filter_frame(AVFilterLink *inlink, AVFrame *in) input_601_hint = in_primaries; /* Output color properties: options override, otherwise inherit - * from the input. RGB output defaults to full range. */ + * from the input. RGB output is always full range. */ out_map = d3d12_scale_map_from_dxgi(s->output_format); s->output_is_rgb = out_map ? out_map->is_rgb : 0; const AVPixFmtDescriptor *out_desc = out_map ? av_pix_fmt_desc_get(out_map->pix_fmt) : NULL; @@ -1250,17 +1250,15 @@ static int scale_d3d12_filter_frame(AVFilterLink *inlink, AVFrame *in) if (!s->output_is_rgb && out_spc == AVCOL_SPC_RGB) out_spc = AVCOL_SPC_UNSPECIFIED; - if (s->color_range != AVCOL_RANGE_UNSPECIFIED) - out_range = s->color_range; - else if (out_trc == AVCOL_TRC_LINEAR) - /* Linear RGB has no studio-range DXGI color space either default - * to full range and let the processor do the limited->full expansion - * instead. */ + /* There is no limited range RGB in FFmpeg. */ + if (s->output_is_rgb) out_range = AVCOL_RANGE_JPEG; + else if (s->color_range != AVCOL_RANGE_UNSPECIFIED) + out_range = s->color_range; else if (in->color_range != AVCOL_RANGE_UNSPECIFIED) out_range = in->color_range; else - out_range = s->output_is_rgb ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + out_range = AVCOL_RANGE_MPEG; ret = d3d12_scale_get_colorspace(ctx, s->output_is_rgb, 1, &out_spc, &out_range, &out_primaries, &out_trc, in->chroma_location, @@ -1756,12 +1754,19 @@ static int scale_d3d12_config_props(AVFilterLink *outlink) const D3D12ScaleFormatMap *in_map = d3d12_scale_map_from_pixfmt(in_frames_ctx->sw_format); int input_is_rgb = in_map ? in_map->is_rgb : 0; + if (s->output_is_rgb && s->color_range == AVCOL_RANGE_MPEG) { + av_log(ctx, AV_LOG_ERROR, "out_range=limited does not apply to RGB output; " + "remove the option or choose a YUV output format\n"); + av_buffer_unref(&s->hw_frames_ctx_out); + + return AVERROR(EINVAL); + } + if (s->color_primaries != AVCOL_PRI_UNSPECIFIED || s->color_transfer != AVCOL_TRC_UNSPECIFIED || s->color_matrix != AVCOL_SPC_UNSPECIFIED || input_is_rgb != s->output_is_rgb || - frames_ctx->sw_format == AV_PIX_FMT_RGBAF16 || - (input_is_rgb && s->color_range != AVCOL_RANGE_UNSPECIFIED)) + frames_ctx->sw_format == AV_PIX_FMT_RGBAF16) av_frame_side_data_remove_by_props(&outlink->side_data, &outlink->nb_side_data, AV_SIDE_DATA_PROP_COLOR_DEPENDENT); -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
