This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit c7a2646bc772b642167d9d2af3673fd50ae20015
Author:     Ayose <[email protected]>
AuthorDate: Fri Dec 5 14:19:49 2025 +0000
Commit:     Marton Balint <[email protected]>
CommitDate: Sun Jan 4 13:42:20 2026 +0000

    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 <[email protected]>
---
 libavfilter/vf_drawvg.c            | 49 ++++++++++++++++++++++++++++++++------
 tests/fate/filter-video.mak        |  9 +++----
 tests/ref/fate/filter-drawvg-video |  2 +-
 tests/ref/lavf/drawvg.lines        | 10 --------
 tests/ref/lavf/drawvg.video        | 13 ++++++++++
 5 files changed, 61 insertions(+), 22 deletions(-)

diff --git a/libavfilter/vf_drawvg.c b/libavfilter/vf_drawvg.c
index f89605185f..99280366f3 100644
--- a/libavfilter/vf_drawvg.c
+++ b/libavfilter/vf_drawvg.c
@@ -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;
         }
 
diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak
index 0c6cbb2ee2..07b8632c6f 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -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
diff --git a/tests/ref/fate/filter-drawvg-video 
b/tests/ref/fate/filter-drawvg-video
index 0a646f6e2e..bd339be9b2 100644
--- a/tests/ref/fate/filter-drawvg-video
+++ b/tests/ref/fate/filter-drawvg-video
@@ -1 +1 @@
-drawvg-video        caa7642950ab2fb1367bd28c287f31bd
+drawvg-video        0f73962365b69779a604c5d41a4b7ae3
diff --git a/tests/ref/lavf/drawvg.lines b/tests/ref/lavf/drawvg.lines
deleted file mode 100644
index e145052d50..0000000000
--- a/tests/ref/lavf/drawvg.lines
+++ /dev/null
@@ -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
diff --git a/tests/ref/lavf/drawvg.video b/tests/ref/lavf/drawvg.video
new file mode 100644
index 0000000000..89f6123385
--- /dev/null
+++ b/tests/ref/lavf/drawvg.video
@@ -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

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to