avfilter/blend: clip expression output to pixel depth

Clip integer expression results in the double domain before storing them. This keeps high-bit-depth samples within their declared range and gives NaN and infinities defined behavior while preserving float formats.

Fixes issue #24121.
This commit is contained in:
jiangjie authored and Niklas Haas committed 2026-08-18 13:55:13 +00:00
1 parent ade01193a1
commit 21bbd98e7b
4 files changed
+18 -5

No files matched your search

+1
View File
@@ -78,6 +78,7 @@ typedef struct SliceParams {
typedef struct FilterParams {
enum BlendMode mode;
double opacity;
unsigned max_value;
AVExpr **e;
char *expr_str;
void (*blend)(const uint8_t *top, ptrdiff_t top_linesize,
+8 -5
View File
@@ -129,7 +129,7 @@ static const AVOption blend_options[] = {
FRAMESYNC_DEFINE_CLASS(blend, BlendContext, fs);
#define DEFINE_BLEND_EXPR(type, name, div) \
#define DEFINE_BLEND_EXPR(type, name, div, clip) \
static void blend_expr_## name(const uint8_t *_top, ptrdiff_t top_linesize, \
const uint8_t *_bottom, ptrdiff_t bottom_linesize, \
uint8_t *_dst, ptrdiff_t dst_linesize, \
@@ -153,7 +153,8 @@ static void blend_expr_## name(const uint8_t *_top, ptrdiff_t top_linesize,
values[VAR_X] = x; \
values[VAR_TOP] = values[VAR_A] = top[x]; \
values[VAR_BOTTOM] = values[VAR_B] = bottom[x]; \
dst[x] = av_expr_eval(e, values, NULL); \
double value = av_expr_eval(e, values, NULL); \
dst[x] = clip ? av_clipd(value, 0, param->max_value) : value; \
} \
dst += dst_linesize; \
top += top_linesize; \
@@ -161,9 +162,9 @@ static void blend_expr_## name(const uint8_t *_top, ptrdiff_t top_linesize,
} \
}
DEFINE_BLEND_EXPR(uint8_t, 8bit, 1)
DEFINE_BLEND_EXPR(uint16_t, 16bit, 2)
DEFINE_BLEND_EXPR(float, 32bit, 4)
DEFINE_BLEND_EXPR(uint8_t, 8bit, 1, 1)
DEFINE_BLEND_EXPR(uint16_t, 16bit, 2, 1)
DEFINE_BLEND_EXPR(float, 32bit, 4, 0)
static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
@@ -306,6 +307,8 @@ static int config_params(AVFilterContext *ctx)
for (int plane = 0; plane < FF_ARRAY_ELEMS(s->params); plane++) {
FilterParams *param = &s->params[plane];
param->max_value = UINT32_MAX >> (32 - s->depth);
if (s->all_mode >= 0)
param->mode = s->all_mode;
if (s->all_opacity < 1)
+3
View File
@@ -382,6 +382,9 @@ FATE_FILTER_VSYNTH_PGMYUV-$(CONFIG_SWAPRECT_FILTER) += $(FATE_SWAPRECT)
FATE_FILTER_VSYNTH_PGMYUV-$(CONFIG_TBLEND_FILTER) += fate-filter-tblend
fate-filter-tblend: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf tblend=all_mode=difference128
FATE_FILTER-$(call FILTERFRAMECRC, BLEND FORMAT NULLSRC SCALE SPLIT) += fate-filter-blend-expr-clipping
fate-filter-blend-expr-clipping: CMD = framecrc -lavfi "nullsrc=s=1x1:d=1:r=1,format=gray10,split[a][b];[a][b]blend=c0_expr=1024,scale" -pix_fmt gray10le
FATE_FILTER_VSYNTH_PGMYUV-$(CONFIG_TELECINE_FILTER) += fate-filter-telecine
fate-filter-telecine: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf telecine
@@ -0,0 +1,6 @@
#tb 0: 1/1
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 1x1
#sar 0: 1/1
0, 0, 0, 1, 2, 0x02010102