1
0
mirror of https://git.ffmpeg.org/ffmpeg.git synced 2026-10-24 02:09:03 +03:00

avfilter/vf_drawvg: values from the p() function can be used as colors.

To be able to reuse colors from the original frame, the last value returned by
`p()` is tracked in the eval state, and if it is assigned to a variable, the
original color components are copied to `color_vars`. Thus, commands like
`setcolor` and `colorstop` can use those variables:

    setvar pixel (p(0, 0))
    ...
    setcolor pixel

`fate-filter-drawvg-video` now also verifies the `p()` function.

Signed-off-by: Ayose <ayosec@gmail.com>
This commit is contained in:
Ayose
2025-12-05 14:19:49 +00:00
committed by Marton Balint
parent 46c9584dc5
commit c7a2646bc7
5 changed files with 61 additions and 22 deletions

View File

@@ -1443,6 +1443,12 @@ struct VGSEvalState {
/// Colors stored in variables.
cairo_color color_vars[USER_VAR_COUNT];
/// Track last color read by the `p()` function.
struct {
double numeric;
uint8_t components[4];
} last_fn_p_color;
/// State for each index available for the `randomg` function.
FFSFC64 random_state[RANDOM_STATES];
@@ -1555,7 +1561,7 @@ static double vgs_fn_randomg(void *data, double arg) {
///
/// If the coordinates are outside the frame, return NAN.
static double vgs_fn_p(void* data, double x0, double y0) {
const struct VGSEvalState *state = (struct VGSEvalState *)data;
struct VGSEvalState *state = (struct VGSEvalState *)data;
const AVFrame *frame = state->frame;
if (frame == NULL || !isfinite(x0) || !isfinite(y0))
@@ -1575,8 +1581,6 @@ static double vgs_fn_p(void* data, double x0, double y0) {
for (int c = 0; c < desc->nb_components; c++) {
uint32_t pixel;
const int depth = desc->comp[c].depth;
av_read_image_line2(
&pixel,
(void*)frame->data,
@@ -1589,14 +1593,35 @@ static double vgs_fn_p(void* data, double x0, double y0) {
4 // dst_element_size
);
if (depth != 8) {
const int depth = desc->comp[c].depth;
if (depth != 8)
pixel = pixel * 255 / ((1 << depth) - 1);
}
color[c] = pixel;
}
return color[0] << 24 | color[1] << 16 | color[2] << 8 | color[3];
// A common use-case of `p()` is to store its result in a variable, so it
// can be used later with commands like `setcolor` or `colorstop`:
//
// setvar pixel (p(0, 0))
// ...
// setcolor pixel
//
// Since we can't pass custom values through `av_expr_eval`, we store the
// color in the `VGSEvalState` instance. Then, when a variable is assigned
// in `setvar`, it checks if the value is the same as the output of `p()`.
// In such case, it copies the color components to the slot in `color_vars`.
//
// This solution is far from perfect, but it works in all the documented
// use-cases.
const double num = color[0] << 24 | color[1] << 16 | color[2] << 8 | color[3];
state->last_fn_p_color.numeric = num;
for (int i = 0; i < FF_ARRAY_ELEMS(color); i++)
state->last_fn_p_color.components[i] = (uint8_t)color[i];
return num;
}
static int vgs_eval_state_init(
@@ -1609,7 +1634,9 @@ static int vgs_eval_state_init(
state->log_ctx = log_ctx;
state->frame = frame;
state->rcp.status = RCP_NONE;
state->last_fn_p_color.numeric = NAN;
if (program->proc_names != NULL) {
state->procedures = av_calloc(sizeof(struct VGSProcedure), program->proc_names_count);
@@ -2476,9 +2503,17 @@ static int vgs_eval(
const int user_var = statement->args[0].constant;
av_assert0(user_var >= VAR_U0 && user_var < (VAR_U0 + USER_VAR_COUNT));
color_copy(&state->color_vars[user_var - VAR_U0], &colors[1]);
state->vars[user_var] = numerics[1];
// Take the color from `p()`, if any.
cairo_color *color = &state->color_vars[user_var - VAR_U0];
if (state->last_fn_p_color.numeric == numerics[1]) {
for (int i = 0; i < FF_ARRAY_ELEMS(*color); i++)
(*color)[i] = state->last_fn_p_color.components[i] / 255.0;
} else {
color_copy(color, &colors[1]);
}
break;
}

View File

@@ -617,13 +617,14 @@ fate-filter-tiltandshift-410: CMD = framecrc -c:v pgmyuv -i $(SRC) -flags +bitex
fate-filter-tiltandshift-422: CMD = framecrc -c:v pgmyuv -i $(SRC) -flags +bitexact -vf scale=sws_flags=+accurate_rnd+bitexact,format=yuv422p,tiltandshift
fate-filter-tiltandshift-444: CMD = framecrc -c:v pgmyuv -i $(SRC) -flags +bitexact -vf scale=sws_flags=+accurate_rnd+bitexact,format=yuv444p,tiltandshift
DRAWVG_SCRIPT_LINES = tests/data/fate/drawvg.lines
$(DRAWVG_SCRIPT_LINES): $(SRC_PATH)/tests/ref/lavf/drawvg.lines
DRAWVG_SCRIPT_VIDEO = tests/data/fate/drawvg.video
$(DRAWVG_SCRIPT_VIDEO): TAG = COPY
$(DRAWVG_SCRIPT_VIDEO): $(SRC_PATH)/tests/ref/lavf/drawvg.video
$(M)cp $< $@
FATE_FILTER_VSYNTH_VIDEO_FILTER-$(CONFIG_DRAWVG_FILTER) += fate-filter-drawvg-video
fate-filter-drawvg-video: $(DRAWVG_SCRIPT_LINES)
fate-filter-drawvg-video: CMD = video_filter scale,format=bgr0,drawvg=file=$(DRAWVG_SCRIPT_LINES)
fate-filter-drawvg-video: $(DRAWVG_SCRIPT_VIDEO)
fate-filter-drawvg-video: CMD = video_filter scale,format=bgr0,drawvg=file=$(DRAWVG_SCRIPT_VIDEO)
tests/pixfmts.mak: TAG = GEN
tests/pixfmts.mak: ffmpeg$(PROGSSUF)$(EXESUF) | tests

View File

@@ -1 +1 @@
drawvg-video caa7642950ab2fb1367bd28c287f31bd
drawvg-video 0f73962365b69779a604c5d41a4b7ae3

View File

@@ -1,10 +0,0 @@
// Render a square, for `make fate-filter-drawvg-video`.
M 10 10
l 0 10
h 10
v -10
h -10
z
setcolor blue
stroke

View File

@@ -0,0 +1,13 @@
// Render a square, for `make fate-filter-drawvg-video`.
setvar pixel (p(10, 10))
M 10 10
l 0 100
h 100
v -100
h -100
z
setcolor pixel
fill