mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-28 10:04:37 +08:00
avfilter: add link negotiation for AVChromaLocation
Chroma sample location is the last of the video colorimetry properties without a negotiated link value, so nothing downstream can ask a filter for a particular siting and no encoder can constrain the graph. Add it alongside the existing color space, color range and alpha mode negotiation. Merge conflicts are resolved by inserting a scale filter, the same way as for color space and color range. Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
This commit is contained in:
1 parent
a74f493bae
commit
08a654a564
8 files changed
+167
-4
No files matched your search
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2026-06-23.
|
||||
|
||||
API changes, most recent first:
|
||||
|
||||
2026-09-xx - xxxxxxxxxx - lavfi 12.4.101 - avfilter.h
|
||||
Add AVFilterLink.chroma_location.
|
||||
|
||||
2026-08-xx - xxxxxxxxxx - lavf 63.7.100 - avformat.h
|
||||
Add AV_STREAM_GROUP_PARAMS_GAIN_MAP.
|
||||
|
||||
|
||||
@@ -315,6 +315,9 @@ int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
|
||||
if (link->outcfg.alpha_modes)
|
||||
ff_formats_changeref(&link->outcfg.alpha_modes,
|
||||
&filt->outputs[filt_dstpad_idx]->outcfg.alpha_modes);
|
||||
if (link->outcfg.chroma_locations)
|
||||
ff_formats_changeref(&link->outcfg.chroma_locations,
|
||||
&filt->outputs[filt_dstpad_idx]->outcfg.chroma_locations);
|
||||
if (link->outcfg.samplerates)
|
||||
ff_formats_changeref(&link->outcfg.samplerates,
|
||||
&filt->outputs[filt_dstpad_idx]->outcfg.samplerates);
|
||||
@@ -790,6 +793,8 @@ static void free_link(AVFilterLink *link)
|
||||
ff_formats_unref(&link->outcfg.color_ranges);
|
||||
ff_formats_unref(&link->incfg.alpha_modes);
|
||||
ff_formats_unref(&link->outcfg.alpha_modes);
|
||||
ff_formats_unref(&link->incfg.chroma_locations);
|
||||
ff_formats_unref(&link->outcfg.chroma_locations);
|
||||
ff_formats_unref(&link->incfg.samplerates);
|
||||
ff_formats_unref(&link->outcfg.samplerates);
|
||||
ff_channel_layouts_unref(&link->incfg.channel_layouts);
|
||||
|
||||
@@ -145,6 +145,12 @@ typedef struct AVFilterFormatsConfig {
|
||||
*/
|
||||
AVFilterFormats *alpha_modes; ///< AVAlphaMode
|
||||
|
||||
/**
|
||||
* List of supported chroma sample locations, only for video with
|
||||
* subsampled chroma.
|
||||
*/
|
||||
AVFilterFormats *chroma_locations; ///< AVChromaLocation
|
||||
|
||||
} AVFilterFormatsConfig;
|
||||
|
||||
/**
|
||||
@@ -407,6 +413,11 @@ struct AVFilterLink {
|
||||
|
||||
enum AVAlphaMode alpha_mode; ///< alpha mode (for videos with an alpha channel)
|
||||
|
||||
/**
|
||||
* Agreed upon chroma sample location, for video with subsampled chroma.
|
||||
*/
|
||||
enum AVChromaLocation chroma_location;
|
||||
|
||||
/*****************************************************************
|
||||
* 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
|
||||
|
||||
@@ -304,7 +304,8 @@ static int filter_link_check_formats(void *log, AVFilterLink *link, AVFilterForm
|
||||
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 ||
|
||||
(ret = ff_formats_check_alpha_modes(log, cfg->alpha_modes)) < 0)
|
||||
(ret = ff_formats_check_alpha_modes(log, cfg->alpha_modes)) < 0 ||
|
||||
(ret = ff_formats_check_chroma_locations(log, cfg->chroma_locations)) < 0)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
@@ -420,7 +421,8 @@ static int formats_declared(AVFilterContext *f)
|
||||
if (f->inputs[i]->type == AVMEDIA_TYPE_VIDEO &&
|
||||
!(f->inputs[i]->outcfg.color_ranges &&
|
||||
f->inputs[i]->outcfg.color_spaces &&
|
||||
f->inputs[i]->outcfg.alpha_modes))
|
||||
f->inputs[i]->outcfg.alpha_modes &&
|
||||
f->inputs[i]->outcfg.chroma_locations))
|
||||
return 0;
|
||||
if (f->inputs[i]->type == AVMEDIA_TYPE_AUDIO &&
|
||||
!(f->inputs[i]->outcfg.samplerates &&
|
||||
@@ -433,7 +435,8 @@ static int formats_declared(AVFilterContext *f)
|
||||
if (f->outputs[i]->type == AVMEDIA_TYPE_VIDEO &&
|
||||
!(f->outputs[i]->incfg.color_ranges &&
|
||||
f->outputs[i]->incfg.color_spaces &&
|
||||
f->outputs[i]->incfg.alpha_modes))
|
||||
f->outputs[i]->incfg.alpha_modes &&
|
||||
f->outputs[i]->incfg.chroma_locations))
|
||||
return 0;
|
||||
if (f->outputs[i]->type == AVMEDIA_TYPE_AUDIO &&
|
||||
!(f->outputs[i]->incfg.samplerates &&
|
||||
@@ -666,6 +669,10 @@ retry:
|
||||
av_assert0( inlink->outcfg.alpha_modes->refcount > 0);
|
||||
av_assert0(outlink-> incfg.alpha_modes->refcount > 0);
|
||||
av_assert0(outlink->outcfg.alpha_modes->refcount > 0);
|
||||
av_assert0( inlink-> incfg.chroma_locations->refcount > 0);
|
||||
av_assert0( inlink->outcfg.chroma_locations->refcount > 0);
|
||||
av_assert0(outlink-> incfg.chroma_locations->refcount > 0);
|
||||
av_assert0(outlink->outcfg.chroma_locations->refcount > 0);
|
||||
} else if (outlink->type == AVMEDIA_TYPE_AUDIO) {
|
||||
av_assert0( inlink-> incfg.samplerates->refcount > 0);
|
||||
av_assert0( inlink->outcfg.samplerates->refcount > 0);
|
||||
@@ -896,6 +903,20 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref)
|
||||
} else {
|
||||
link->alpha_mode = AVALPHA_MODE_UNSPECIFIED;
|
||||
}
|
||||
|
||||
if (desc->log2_chroma_w || desc->log2_chroma_h) {
|
||||
if (!link->incfg.chroma_locations->nb_formats) {
|
||||
av_log(link->src, AV_LOG_ERROR, "Cannot select chroma location"
|
||||
" for the link between filters %s and %s.\n", link->src->name,
|
||||
link->dst->name);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
link->incfg.chroma_locations->nb_formats = 1;
|
||||
link->chroma_location = link->incfg.chroma_locations->formats[0];
|
||||
} else {
|
||||
/* Chroma location is meaningless without subsampled chroma. */
|
||||
link->chroma_location = AVCHROMA_LOC_UNSPECIFIED;
|
||||
}
|
||||
} else if (link->type == AVMEDIA_TYPE_AUDIO) {
|
||||
int ret;
|
||||
|
||||
@@ -936,6 +957,8 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref)
|
||||
ff_formats_unref(&link->outcfg.color_ranges);
|
||||
ff_formats_unref(&link->incfg.alpha_modes);
|
||||
ff_formats_unref(&link->outcfg.alpha_modes);
|
||||
ff_formats_unref(&link->incfg.chroma_locations);
|
||||
ff_formats_unref(&link->outcfg.chroma_locations);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -991,6 +1014,8 @@ static int reduce_formats_on_filter(AVFilterContext *filter)
|
||||
nb_formats, ff_add_format);
|
||||
REDUCE_FORMATS(int, AVFilterFormats, alpha_modes, formats,
|
||||
nb_formats, ff_add_format);
|
||||
REDUCE_FORMATS(int, AVFilterFormats, chroma_locations, formats,
|
||||
nb_formats, ff_add_format);
|
||||
|
||||
/* reduce channel layouts */
|
||||
for (i = 0; i < filter->nb_inputs; i++) {
|
||||
|
||||
@@ -363,6 +363,7 @@ PRINT_NAME(enum AVPixelFormat, get_pix_fmt_name)
|
||||
PRINT_NAME(enum AVColorSpace, color_space_name)
|
||||
PRINT_NAME(enum AVColorRange, color_range_name)
|
||||
PRINT_NAME(enum AVAlphaMode, alpha_mode_name)
|
||||
PRINT_NAME(enum AVChromaLocation, chroma_location_name)
|
||||
|
||||
static void print_channel_layout_desc(AVBPrint *bp, const void *layoutsp)
|
||||
{
|
||||
@@ -421,6 +422,14 @@ static const AVFilterFormatsMerger mergers_video[] = {
|
||||
.print_list = print_alpha_mode_name,
|
||||
.conversion_filter = "premultiply_dynamic",
|
||||
},
|
||||
{
|
||||
.name = "Chroma locations",
|
||||
.offset = offsetof(AVFilterFormatsConfig, chroma_locations),
|
||||
.merge = merge_generic,
|
||||
.can_merge = can_merge_generic,
|
||||
.print_list = print_chroma_location_name,
|
||||
CONVERSION_FILTER_SWSCALE
|
||||
},
|
||||
};
|
||||
|
||||
static const AVFilterFormatsMerger mergers_audio[] = {
|
||||
@@ -733,6 +742,17 @@ AVFilterFormats *ff_all_alpha_modes(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
AVFilterFormats *ff_all_chroma_locations(void)
|
||||
{
|
||||
AVFilterFormats *ret = NULL;
|
||||
for (int loc = 0; loc < AVCHROMA_LOC_NB; loc++) {
|
||||
if (ff_add_format(&ret, loc) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define FORMATS_REF(f, ref, unref_fn) \
|
||||
void *tmp; \
|
||||
\
|
||||
@@ -956,6 +976,24 @@ int ff_set_common_all_alpha_modes(AVFilterContext *ctx)
|
||||
return ff_set_common_alpha_modes(ctx, ff_all_alpha_modes());
|
||||
}
|
||||
|
||||
int ff_set_common_chroma_locations(AVFilterContext *ctx,
|
||||
AVFilterFormats *chroma_locations)
|
||||
{
|
||||
SET_COMMON_FORMATS(ctx, chroma_locations, AVMEDIA_TYPE_VIDEO,
|
||||
ff_formats_ref, ff_formats_unref);
|
||||
}
|
||||
|
||||
int ff_set_common_chroma_locations_from_list(AVFilterContext *ctx,
|
||||
const int *chroma_locations)
|
||||
{
|
||||
return ff_set_common_chroma_locations(ctx, ff_make_format_list(chroma_locations));
|
||||
}
|
||||
|
||||
int ff_set_common_all_chroma_locations(AVFilterContext *ctx)
|
||||
{
|
||||
return ff_set_common_chroma_locations(ctx, ff_all_chroma_locations());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -1135,6 +1173,31 @@ int ff_set_common_all_alpha_modes2(const AVFilterContext *ctx,
|
||||
return ff_set_common_alpha_modes2(ctx, cfg_in, cfg_out, ff_all_alpha_modes());
|
||||
}
|
||||
|
||||
int ff_set_common_chroma_locations2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out,
|
||||
AVFilterFormats *chroma_locations)
|
||||
{
|
||||
SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, chroma_locations, AVMEDIA_TYPE_VIDEO,
|
||||
ff_formats_ref, ff_formats_unref);
|
||||
}
|
||||
|
||||
int ff_set_common_chroma_locations_from_list2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out,
|
||||
const int *chroma_locations)
|
||||
{
|
||||
return ff_set_common_chroma_locations2(ctx, cfg_in, cfg_out,
|
||||
ff_make_format_list(chroma_locations));
|
||||
}
|
||||
|
||||
int ff_set_common_all_chroma_locations2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out)
|
||||
{
|
||||
return ff_set_common_chroma_locations2(ctx, cfg_in, cfg_out, ff_all_chroma_locations());
|
||||
}
|
||||
|
||||
int ff_set_common_formats2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out,
|
||||
@@ -1218,6 +1281,9 @@ int ff_default_query_formats(AVFilterContext *ctx)
|
||||
ret = ff_set_common_all_alpha_modes(ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ff_set_common_all_chroma_locations(ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (type != AVMEDIA_TYPE_VIDEO) {
|
||||
ret = ff_set_common_all_channel_counts(ctx);
|
||||
@@ -1290,6 +1356,11 @@ int ff_formats_check_alpha_modes(void *log, const AVFilterFormats *fmts)
|
||||
return check_list(log, "alpha mode", fmts);
|
||||
}
|
||||
|
||||
int ff_formats_check_chroma_locations(void *log, const AVFilterFormats *fmts)
|
||||
{
|
||||
return check_list(log, "chroma location", fmts);
|
||||
}
|
||||
|
||||
static int layouts_compatible(const AVChannelLayout *a, const AVChannelLayout *b)
|
||||
{
|
||||
return !av_channel_layout_compare(a, b) ||
|
||||
|
||||
@@ -150,6 +150,12 @@ AVFilterFormats *ff_all_color_ranges(void);
|
||||
av_warn_unused_result
|
||||
AVFilterFormats *ff_all_alpha_modes(void);
|
||||
|
||||
/**
|
||||
* Construct an AVFilterFormats representing all possible chroma locations.
|
||||
*/
|
||||
av_warn_unused_result
|
||||
AVFilterFormats *ff_all_chroma_locations(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,
|
||||
@@ -233,6 +239,23 @@ int ff_set_common_alpha_modes_from_list(AVFilterContext *ctx,
|
||||
av_warn_unused_result
|
||||
int ff_set_common_all_alpha_modes(AVFilterContext *ctx);
|
||||
|
||||
av_warn_unused_result
|
||||
int ff_set_common_chroma_locations(AVFilterContext *ctx,
|
||||
AVFilterFormats *chroma_locations);
|
||||
|
||||
/**
|
||||
* Equivalent to ff_set_common_chroma_locations(ctx, ff_make_format_list(chroma_locations))
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int ff_set_common_chroma_locations_from_list(AVFilterContext *ctx,
|
||||
const int *chroma_locations);
|
||||
|
||||
/**
|
||||
* Equivalent to ff_set_common_chroma_locations(ctx, ff_all_chroma_locations())
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int ff_set_common_all_chroma_locations(AVFilterContext *ctx);
|
||||
|
||||
|
||||
/**
|
||||
* A helper for query_formats() which sets all links to the same list of
|
||||
@@ -349,6 +372,23 @@ int ff_set_common_all_alpha_modes2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out);
|
||||
|
||||
av_warn_unused_result
|
||||
int ff_set_common_chroma_locations2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out,
|
||||
AVFilterFormats *chroma_locations);
|
||||
|
||||
av_warn_unused_result
|
||||
int ff_set_common_chroma_locations_from_list2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out,
|
||||
const int *chroma_locations);
|
||||
|
||||
av_warn_unused_result
|
||||
int ff_set_common_all_chroma_locations2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
AVFilterFormatsConfig **cfg_out);
|
||||
|
||||
av_warn_unused_result
|
||||
int ff_set_common_formats2(const AVFilterContext *ctx,
|
||||
AVFilterFormatsConfig **cfg_in,
|
||||
@@ -557,6 +597,13 @@ int ff_formats_check_color_ranges(void *log, const AVFilterFormats *fmts);
|
||||
*/
|
||||
int ff_formats_check_alpha_modes(void *log, const AVFilterFormats *fmts);
|
||||
|
||||
/**
|
||||
* Check that fmts is a valid formats list for chroma locations.
|
||||
*
|
||||
* In particular, check for duplicates.
|
||||
*/
|
||||
int ff_formats_check_chroma_locations(void *log, const AVFilterFormats *fmts);
|
||||
|
||||
struct AVBPrint;
|
||||
|
||||
typedef struct AVFilterFormatMerger {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "version_major.h"
|
||||
|
||||
#define LIBAVFILTER_VERSION_MINOR 4
|
||||
#define LIBAVFILTER_VERSION_MICRO 100
|
||||
#define LIBAVFILTER_VERSION_MICRO 101
|
||||
|
||||
|
||||
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
|
||||
|
||||
@@ -77,6 +77,7 @@ AVFrame *ff_default_get_video_buffer2(AVFilterLink *link, int w, int h, int alig
|
||||
frame->colorspace = link->colorspace;
|
||||
frame->color_range = link->color_range;
|
||||
frame->alpha_mode = link->alpha_mode;
|
||||
frame->chroma_location = link->chroma_location;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user