1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-01-24 13:56:33 +02:00

avfilter: properly reduce YUV colorspace format lists

Doing this with REDUCE_FORMATS() instead of swap_color_*() is not only
shorter, but more importantly comes with the benefit of being done
inside a loop, allowing us to correctly propagate complex graphs
involving multiple conversion filters (e.g. -vf scale,zscale).

The latter family of swapping functions is only used to settle the
best *remaining* entry if no exact match was found, and as such was
never the correct solution to YUV colorspaces, which only care about
exact matches.

(cherry picked from commit b89ee2653919c14193f646ba03b2bf1d13c9aa2d)
This commit is contained in:
Niklas Haas 2024-03-25 16:07:23 +01:00
parent 87e5bc918a
commit 5cd6683ddc

View File

@ -794,6 +794,10 @@ static int reduce_formats_on_filter(AVFilterContext *filter)
nb_formats, ff_add_format);
REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats,
nb_formats, ff_add_format);
REDUCE_FORMATS(int, AVFilterFormats, color_spaces, formats,
nb_formats, ff_add_format);
REDUCE_FORMATS(int, AVFilterFormats, color_ranges, formats,
nb_formats, ff_add_format);
/* reduce channel layouts */
for (i = 0; i < filter->nb_inputs; i++) {
@ -906,82 +910,6 @@ 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)
@ -1258,10 +1186,6 @@ 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);