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

Git pushed a commit to branch master
in repository ffmpeg.

The following commit(s) were added to refs/heads/master by this push:
     new 7453f6dbde avfilter/vf_mestimate{,_d3d12}: flush final frame at EOF
7453f6dbde is described below

commit 7453f6dbde4e3b55f651bc8759018d3ded734480
Author:     Edison Ling <[email protected]>
AuthorDate: Fri Aug 28 18:59:13 2026 -0400
Commit:     michaelni <[email protected]>
CommitDate: Tue Sep 8 16:35:14 2026 +0000

    avfilter/vf_mestimate{,_d3d12}: flush final frame at EOF
    
    Both mestimate filters buffer one frame so they can estimate motion
    against a future frame. At EOF, that frame remains in the next slot
    and is discarded during uninitialization, making the output one frame
    shorter than the input.
    
    Add output request callbacks that drain the buffered frame when input
    reaches EOF. Since no future reference exists while draining, emit only
    backward motion vectors and size the side data accordingly.
    
    Update the cropdetect FATE references for the newly emitted frame.
---
 libavfilter/vf_mestimate.c                 | 36 +++++++++++++++++++++++++-----
 libavfilter/vf_mestimate_d3d12.c           | 33 +++++++++++++++++++++------
 tests/ref/fate/filter-metadata-cropdetect1 |  1 +
 tests/ref/fate/filter-metadata-cropdetect2 |  1 +
 4 files changed, 59 insertions(+), 12 deletions(-)

diff --git a/libavfilter/vf_mestimate.c b/libavfilter/vf_mestimate.c
index 413838e956..759883df45 100644
--- a/libavfilter/vf_mestimate.c
+++ b/libavfilter/vf_mestimate.c
@@ -26,7 +26,6 @@
 #include "libavutil/motion_vector.h"
 #include "avfilter.h"
 #include "filters.h"
-#include "video.h"
 
 typedef struct MEContext {
     const AVClass *class;
@@ -146,7 +145,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame 
*frame)
     int32_t mv_count = 0;
     int ret;
 
-    if (frame->pts == AV_NOPTS_VALUE) {
+    if (frame && frame->pts == AV_NOPTS_VALUE) {
         ret = ff_filter_frame(ctx->outputs[0], frame);
         return ret;
     }
@@ -160,6 +159,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame 
*frame)
     s->mv_table[1] = memcpy(s->mv_table[1], s->mv_table[0], 
sizeof(*s->mv_table[0]) * s->b_count);
 
     if (!s->cur) {
+        if (!frame)
+            return 0;
         s->cur = av_frame_clone(frame);
         if (!s->cur)
             return AVERROR(ENOMEM);
@@ -172,7 +173,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame 
*frame)
     if (!out)
         return AVERROR(ENOMEM);
 
-    sd = av_frame_new_side_data(out, AV_FRAME_DATA_MOTION_VECTORS, 2 * 
s->b_count * sizeof(AVMotionVector));
+    /* The last frame has no forward reference. */
+    const int nb_dirs = s->next ? 2 : 1;
+
+    sd = av_frame_new_side_data(out, AV_FRAME_DATA_MOTION_VECTORS,
+                                nb_dirs * s->b_count * sizeof(AVMotionVector));
     if (!sd) {
         av_frame_free(&out);
         return AVERROR(ENOMEM);
@@ -181,7 +186,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame 
*frame)
     me_ctx->data_cur = s->cur->data[0];
     me_ctx->linesize = s->cur->linesize[0];
 
-    for (dir = 0; dir < 2; dir++) {
+    for (dir = 0; dir < nb_dirs; dir++) {
         me_ctx->data_ref = (dir ? s->next : s->prev)->data[0];
 
         if (s->method == AV_ME_METHOD_DS)
@@ -326,6 +331,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame 
*frame)
     return ff_filter_frame(ctx->outputs[0], out);
 }
 
+static int request_frame(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    MEContext *s = ctx->priv;
+    int ret;
+
+    ret = ff_request_frame(ctx->inputs[0]);
+    if (ret == AVERROR_EOF && s->next)
+        ret = filter_frame(ctx->inputs[0], NULL);
+
+    return ret;
+}
+
 static av_cold void uninit(AVFilterContext *ctx)
 {
     MEContext *s = ctx->priv;
@@ -348,6 +366,14 @@ static const AVFilterPad mestimate_inputs[] = {
     },
 };
 
+static const AVFilterPad mestimate_outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .request_frame = request_frame,
+    },
+};
+
 const FFFilter ff_vf_mestimate = {
     .p.name        = "mestimate",
     .p.description = NULL_IF_CONFIG_SMALL("Generate motion vectors."),
@@ -356,6 +382,6 @@ const FFFilter ff_vf_mestimate = {
     .priv_size     = sizeof(MEContext),
     .uninit        = uninit,
     FILTER_INPUTS(mestimate_inputs),
-    FILTER_OUTPUTS(ff_video_default_filterpad),
+    FILTER_OUTPUTS(mestimate_outputs),
     FILTER_PIXFMTS_ARRAY(pix_fmts),
 };
diff --git a/libavfilter/vf_mestimate_d3d12.c b/libavfilter/vf_mestimate_d3d12.c
index 710ba6ff33..6d45a93e39 100644
--- a/libavfilter/vf_mestimate_d3d12.c
+++ b/libavfilter/vf_mestimate_d3d12.c
@@ -561,6 +561,8 @@ static int mestimate_d3d12_filter_frame(AVFilterLink 
*inlink, AVFrame *frame)
     int mb_width, mb_height, mb_count;
 
     if (!s->initialized) {
+        if (!frame)
+            return 0;
         err = mestimate_d3d12_config_props(ctx->outputs[0]);
         if (err < 0) {
             av_frame_free(&frame);
@@ -575,6 +577,8 @@ static int mestimate_d3d12_filter_frame(AVFilterLink 
*inlink, AVFrame *frame)
     s->next_frame = frame;
 
     if (!s->cur_frame) {
+        if (!frame)
+            return 0;
         s->cur_frame = av_frame_clone(frame);
         if (!s->cur_frame)
             return AVERROR(ENOMEM);
@@ -588,13 +592,14 @@ static int mestimate_d3d12_filter_frame(AVFilterLink 
*inlink, AVFrame *frame)
     if (!out)
         return AVERROR(ENOMEM);
 
-    mb_width  = (frame->width + s->block_size - 1) / s->block_size;
-    mb_height = (frame->height + s->block_size - 1) / s->block_size;
+    mb_width  = (s->cur_frame->width  + s->block_size - 1) / s->block_size;
+    mb_height = (s->cur_frame->height + s->block_size - 1) / s->block_size;
     mb_count  = mb_width * mb_height;
+    /* The last frame has no forward reference. */
+    const int nb_dirs = s->next_frame ? 2 : 1;
 
-    // Allocate side data for motion vectors (2 directions)
     sd = av_frame_new_side_data(out, AV_FRAME_DATA_MOTION_VECTORS,
-                                2 * mb_count * sizeof(AVMotionVector));
+                                nb_dirs * mb_count * sizeof(AVMotionVector));
     if (!sd) {
         av_frame_free(&out);
         return AVERROR(ENOMEM);
@@ -913,6 +918,19 @@ static int mestimate_d3d12_filter_frame(AVFilterLink 
*inlink, AVFrame *frame)
     return ff_filter_frame(ctx->outputs[0], out);
 }
 
+static int mestimate_d3d12_request_frame(AVFilterLink *outlink)
+{
+    AVFilterContext     *ctx = outlink->src;
+    MEstimateD3D12Context *s = ctx->priv;
+    int ret;
+
+    ret = ff_request_frame(ctx->inputs[0]);
+    if (ret == AVERROR_EOF && s->next_frame)
+        ret = mestimate_d3d12_filter_frame(ctx->inputs[0], NULL);
+
+    return ret;
+}
+
 static av_cold void mestimate_d3d12_uninit(AVFilterContext *ctx)
 {
     MEstimateD3D12Context *s = ctx->priv;
@@ -952,9 +970,10 @@ static const AVFilterPad mestimate_d3d12_inputs[] = {
 
 static const AVFilterPad mestimate_d3d12_outputs[] = {
     {
-        .name         = "default",
-        .type         = AVMEDIA_TYPE_VIDEO,
-        .config_props = mestimate_d3d12_config_props,
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .config_props  = mestimate_d3d12_config_props,
+        .request_frame = mestimate_d3d12_request_frame,
     },
 };
 
diff --git a/tests/ref/fate/filter-metadata-cropdetect1 
b/tests/ref/fate/filter-metadata-cropdetect1
index 7deebb306c..9ec9e43e72 100644
--- a/tests/ref/fate/filter-metadata-cropdetect1
+++ b/tests/ref/fate/filter-metadata-cropdetect1
@@ -7,3 +7,4 @@ 
pts=5005|tag:lavfi.cropdetect.y=316|tag:lavfi.cropdetect.x1=20|tag:lavfi.cropdet
 
pts=6006|tag:lavfi.cropdetect.y=122|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=885|tag:lavfi.cropdetect.y1=115|tag:lavfi.cropdetect.y2=621|tag:lavfi.cropdetect.w=880|tag:lavfi.cropdetect.h=496|tag:lavfi.cropdetect.x=4|tag:lavfi.cropdetect.limit=0.094118|
 
pts=7007|tag:lavfi.cropdetect.y=122|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=885|tag:lavfi.cropdetect.y1=115|tag:lavfi.cropdetect.y2=621|tag:lavfi.cropdetect.w=880|tag:lavfi.cropdetect.h=496|tag:lavfi.cropdetect.x=4|tag:lavfi.cropdetect.limit=0.094118|
 
pts=8008|tag:lavfi.cropdetect.y=122|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=885|tag:lavfi.cropdetect.y1=115|tag:lavfi.cropdetect.y2=621|tag:lavfi.cropdetect.w=880|tag:lavfi.cropdetect.h=496|tag:lavfi.cropdetect.x=4|tag:lavfi.cropdetect.limit=0.094118|
+pts=9009|tag:lavfi.cropdetect.y=122|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=885|tag:lavfi.cropdetect.y1=115|tag:lavfi.cropdetect.y2=621|tag:lavfi.cropdetect.w=880|tag:lavfi.cropdetect.h=496|tag:lavfi.cropdetect.x=4|tag:lavfi.cropdetect.limit=0.094118|
diff --git a/tests/ref/fate/filter-metadata-cropdetect2 
b/tests/ref/fate/filter-metadata-cropdetect2
index 42806c16b7..ba6d2851c1 100644
--- a/tests/ref/fate/filter-metadata-cropdetect2
+++ b/tests/ref/fate/filter-metadata-cropdetect2
@@ -7,3 +7,4 @@ 
pts=2560|tag:lavfi.cropdetect.y=22|tag:lavfi.cropdetect.x1=21|tag:lavfi.cropdete
 
pts=3072|tag:lavfi.cropdetect.y=22|tag:lavfi.cropdetect.x1=21|tag:lavfi.cropdetect.x2=817|tag:lavfi.cropdetect.y1=15|tag:lavfi.cropdetect.y2=937|tag:lavfi.cropdetect.w=784|tag:lavfi.cropdetect.h=912|tag:lavfi.cropdetect.x=28|tag:lavfi.cropdetect.limit=0.094118|
 
pts=3584|tag:lavfi.cropdetect.y=40|tag:lavfi.cropdetect.x1=21|tag:lavfi.cropdetect.x2=817|tag:lavfi.cropdetect.y1=38|tag:lavfi.cropdetect.y2=937|tag:lavfi.cropdetect.w=784|tag:lavfi.cropdetect.h=896|tag:lavfi.cropdetect.x=28|tag:lavfi.cropdetect.limit=0.094118|
 
pts=4096|tag:lavfi.cropdetect.y=22|tag:lavfi.cropdetect.x1=21|tag:lavfi.cropdetect.x2=817|tag:lavfi.cropdetect.y1=15|tag:lavfi.cropdetect.y2=937|tag:lavfi.cropdetect.w=784|tag:lavfi.cropdetect.h=912|tag:lavfi.cropdetect.x=28|tag:lavfi.cropdetect.limit=0.094118|
+pts=4608|tag:lavfi.cropdetect.y=22|tag:lavfi.cropdetect.x1=21|tag:lavfi.cropdetect.x2=1221|tag:lavfi.cropdetect.y1=15|tag:lavfi.cropdetect.y2=1116|tag:lavfi.cropdetect.w=1200|tag:lavfi.cropdetect.h=1088|tag:lavfi.cropdetect.x=22|tag:lavfi.cropdetect.limit=0.094118|

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to