From 478898b2bce89fca8370c51a567eb32e5e634513 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael at niedermayer.cc>
Date: Fri, 4 Jul 2025 14:57:21 +0800
Subject: [PATCH] avfilter/vf_yadif: Fix handing of tiny images

---
 libavcodec/v4l2_m2m.c       | 18 +++++++++++-------
 libavcodec/v4l2_m2m_dec.c   |  2 --
 libavfilter/af_tremolo.c    |  8 +++++---
 libavfilter/vf_vmafmotion.c |  4 ++++
 libavfilter/vf_yadif.c      | 35 +++++++++++++++++++++--------------
 libavformat/avienc.c        | 22 +++++++++++++++++-----
 libavformat/mpegenc.c       | 31 +++++++++++++++++++------------
 libavformat/nutenc.c        |  2 +-
 8 files changed, 78 insertions(+), 44 deletions(-)

diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
index 427e165..cfb4f14 100644
--- a/libavcodec/v4l2_m2m.c
+++ b/libavcodec/v4l2_m2m.c
@@ -312,7 +312,7 @@ static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
     sem_destroy(&s->refsync);
 
     close(s->fd);
-
+    ;
     av_free(s);
 }
 
@@ -322,14 +322,18 @@ int ff_v4l2_m2m_codec_end(AVCodecContext *avctx)
     V4L2m2mContext* s = priv->context;
     int ret;
 
-    ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
-    if (ret)
-            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
+   if (!s)
+        return 0;
 
-    ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
-    if (ret)
-        av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
+    if (s->fd >= 0) {
+        ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
+        if (ret)
+            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
 
+        ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
+        if (ret)
+            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
+    }
     ff_v4l2_context_release(&s->output);
 
     s->self_ref = NULL;
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index d0601f0..587d0d6 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -190,8 +190,6 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
     if (ret) {
         V4L2m2mPriv *priv = avctx->priv_data;
         av_log(avctx, AV_LOG_ERROR, "can't configure decoder\n");
-        s->self_ref = NULL;
-        av_buffer_unref(&priv->context_ref);
 
         return ret;
     }
diff --git a/libavfilter/af_tremolo.c b/libavfilter/af_tremolo.c
index 8cbc798..f55e8e2 100644
--- a/libavfilter/af_tremolo.c
+++ b/libavfilter/af_tremolo.c
@@ -28,6 +28,7 @@ typedef struct TremoloContext {
     double freq;
     double depth;
     double *table;
+    int table_size;
     int index;
 } TremoloContext;
 
@@ -72,7 +73,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         dst += channels;
         src += channels;
         s->index++;
-        if (s->index >= inlink->sample_rate / s->freq)
+        if (s->index >= s->table_size)
             s->index = 0;
     }
 
@@ -125,11 +126,12 @@ static int config_input(AVFilterLink *inlink)
     const double offset = 1. - s->depth / 2.;
     int i;
 
-    s->table = av_malloc_array(inlink->sample_rate / s->freq, sizeof(*s->table));
+    s->table_size = inlink->sample_rate / s->freq;
+    s->table = av_malloc_array(s->table_size, sizeof(*s->table));
     if (!s->table)
         return AVERROR(ENOMEM);
 
-    for (i = 0; i < inlink->sample_rate / s->freq; i++) {
+    for (i = 0; i < s->table_size; i++) {
         double env = s->freq * i / inlink->sample_rate;
         env = sin(2 * M_PI * fmod(env + 0.25, 1.0));
         s->table[i] = env * (1 - fabs(offset)) + offset;
diff --git a/libavfilter/vf_vmafmotion.c b/libavfilter/vf_vmafmotion.c
index 5c2a974..0bbb998 100644
--- a/libavfilter/vf_vmafmotion.c
+++ b/libavfilter/vf_vmafmotion.c
@@ -238,6 +238,10 @@ int ff_vmafmotion_init(VMAFMotionData *s,
     int i;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
 
+    if (w < 3 || h < 3)
+        return AVERROR(EINVAL);
+
+
     s->width = w;
     s->height = h;
     s->stride = FFALIGN(w * sizeof(uint16_t), 32);
diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c
index 3107924..3c7a46b 100644
--- a/libavfilter/vf_yadif.c
+++ b/libavfilter/vf_yadif.c
@@ -123,20 +123,23 @@ static void filter_edges(void *dst1, void *prev1, void *cur1, void *next1,
     uint8_t *next2 = parity ? cur  : next;
 
     const int edge = MAX_ALIGN - 1;
+    int offset = FFMAX(w - edge, 3);
 
     /* Only edge pixels need to be processed here.  A constant value of false
      * for is_not_edge should let the compiler ignore the whole branch. */
-    FILTER(0, 3, 0)
+    FILTER(0, FFMIN(3, w), 0)
+
+    dst  = (uint8_t*)dst1  + offset;
+    prev = (uint8_t*)prev1 + offset;
+    cur  = (uint8_t*)cur1  + offset;
+    next = (uint8_t*)next1 + offset;
 
-    dst  = (uint8_t*)dst1  + w - edge;
-    prev = (uint8_t*)prev1 + w - edge;
-    cur  = (uint8_t*)cur1  + w - edge;
-    next = (uint8_t*)next1 + w - edge;
     prev2 = (uint8_t*)(parity ? prev : cur);
     next2 = (uint8_t*)(parity ? cur  : next);
 
-    FILTER(w - edge, w - 3, 1)
-    FILTER(w - 3, w, 0)
+    FILTER(offset, w - 3, 1)
+    offset = FFMAX(offset, w - 3);
+    FILTER(offset, w, 0)
 }
 
 
@@ -170,21 +173,25 @@ static void filter_edges_16bit(void *dst1, void *prev1, void *cur1, void *next1,
     uint16_t *next2 = parity ? cur  : next;
 
     const int edge = MAX_ALIGN / 2 - 1;
+    int offset = FFMAX(w - edge, 3);
 
     mrefs /= 2;
     prefs /= 2;
 
-    FILTER(0, 3, 0)
+    FILTER(0,  FFMIN(3, w), 0)
+
+    dst   = (uint16_t*)dst1  + offset;
+    prev  = (uint16_t*)prev1 + offset;
+    cur   = (uint16_t*)cur1  + offset;
+    next  = (uint16_t*)next1 + offset;
 
-    dst   = (uint16_t*)dst1  + w - edge;
-    prev  = (uint16_t*)prev1 + w - edge;
-    cur   = (uint16_t*)cur1  + w - edge;
-    next  = (uint16_t*)next1 + w - edge;
     prev2 = (uint16_t*)(parity ? prev : cur);
     next2 = (uint16_t*)(parity ? cur  : next);
 
-    FILTER(w - edge, w - 3, 1)
-    FILTER(w - 3, w, 0)
+    FILTER(offset, w - 3, 1)
+    offset = FFMAX(offset, w - 3);
+    FILTER(offset, w, 0)
+
 }
 
 static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index 1b8904f..4170bf5 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -917,7 +917,7 @@ static int avi_write_trailer(AVFormatContext *s)
     AVIContext *avi = s->priv_data;
     AVIOContext *pb = s->pb;
     int res = 0;
-    int i, j, n, nb_frames;
+    int i, n, nb_frames;
     int64_t file_size;
 
     for (i = 0; i < s->nb_streams; i++) {
@@ -970,10 +970,6 @@ static int avi_write_trailer(AVFormatContext *s)
 
     for (i = 0; i < s->nb_streams; i++) {
         AVIStream *avist = s->streams[i]->priv_data;
-        for (j = 0; j < avist->indexes.ents_allocated / AVI_INDEX_CLUSTER_SIZE; j++)
-            av_freep(&avist->indexes.cluster[j]);
-        av_freep(&avist->indexes.cluster);
-        avist->indexes.ents_allocated = avist->indexes.entry = 0;
         if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
             avio_seek(pb, avist->frames_hdr_strm + 4, SEEK_SET);
             avio_wl32(pb, avist->max_size);
@@ -983,6 +979,21 @@ static int avi_write_trailer(AVFormatContext *s)
     return res;
 }
 
+static void avi_deinit(AVFormatContext *s)
+{
+    for (int i = 0; i < s->nb_streams; i++) {
+        AVIStream *avist = s->streams[i]->priv_data;
+        if (!avist)
+            continue;
+        for (int j = 0; j < avist->indexes.ents_allocated / AVI_INDEX_CLUSTER_SIZE; j++)
+            av_freep(&avist->indexes.cluster[j]);
+        av_freep(&avist->indexes.cluster);
+        avist->indexes.ents_allocated = avist->indexes.entry = 0;
+    }
+}
+
+
+
 #define OFFSET(x) offsetof(AVIContext, x)
 #define ENC AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
@@ -1007,6 +1018,7 @@ AVOutputFormat ff_avi_muxer = {
     .audio_codec    = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_AC3,
     .video_codec    = AV_CODEC_ID_MPEG4,
     .init           = avi_init,
+    .deinit         = avi_deinit,
     .write_header   = avi_write_header,
     .write_packet   = avi_write_packet,
     .write_trailer  = avi_write_trailer,
diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c
index 1b0b532..789431a 100644
--- a/libavformat/mpegenc.c
+++ b/libavformat/mpegenc.c
@@ -315,7 +315,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
         if (ctx->packet_size < 20 || ctx->packet_size > (1 << 23) + 10) {
             av_log(ctx, AV_LOG_ERROR, "Invalid packet size %d\n",
                    ctx->packet_size);
-            goto fail;
+            return AVERROR(EINVAL);
         }
         s->packet_size = ctx->packet_size;
     } else
@@ -343,7 +343,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
         st     = ctx->streams[i];
         stream = av_mallocz(sizeof(StreamInfo));
         if (!stream)
-            goto fail;
+            return AVERROR(EINVAL);
         st->priv_data = stream;
 
         avpriv_set_pts_info(st, 64, 1, 90000);
@@ -377,11 +377,11 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
                     for (sr = 0; sr < 4; sr++)
                          av_log(ctx, AV_LOG_INFO, " %d", lpcm_freq_tab[sr]);
                     av_log(ctx, AV_LOG_INFO, "\n");
-                    goto fail;
+                    return AVERROR(EINVAL);
                 }
                 if (st->codecpar->channels > 8) {
                     av_log(ctx, AV_LOG_ERROR, "At most 8 channels allowed for LPCM streams.\n");
-                    goto fail;
+                    return AVERROR(EINVAL);
                 }
                 stream->lpcm_header[0] = 0x0c;
                 stream->lpcm_header[1] = (st->codecpar->channels - 1) | (j << 4);
@@ -416,7 +416,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
                        st->codecpar->codec_id != AV_CODEC_ID_MP2 &&
                        st->codecpar->codec_id != AV_CODEC_ID_MP3) {
                        av_log(ctx, AV_LOG_ERROR, "Unsupported audio codec. Must be one of mp1, mp2, mp3, 16-bit pcm_dvd, pcm_s16be, ac3 or dts.\n");
-                       goto fail;
+                       return AVERROR(EINVAL);
             } else {
                 stream->id = mpa_id++;
             }
@@ -460,7 +460,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
         }
         stream->fifo = av_fifo_alloc(16);
         if (!stream->fifo)
-            goto fail;
+            return AVERROR(EINVAL);
     }
     bitrate       = 0;
     audio_bitrate = 0;
@@ -560,11 +560,6 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
     s->system_header_size = get_system_header_size(ctx);
     s->last_scr           = AV_NOPTS_VALUE;
     return 0;
-
-fail:
-    for (i = 0; i < ctx->nb_streams; i++)
-        av_freep(&ctx->streams[i]->priv_data);
-    return AVERROR(ENOMEM);
 }
 
 static inline void put_timestamp(AVIOContext *pb, int id, int64_t timestamp)
@@ -1255,11 +1250,19 @@ static int mpeg_mux_end(AVFormatContext *ctx)
         stream = ctx->streams[i]->priv_data;
 
         av_assert0(av_fifo_size(stream->fifo) == 0);
-        av_fifo_freep(&stream->fifo);
     }
     return 0;
 }
 
+static void mpeg_mux_deinit(AVFormatContext *ctx)
+{
+    for (int i = 0; i < ctx->nb_streams; i++) {
+        StreamInfo *stream = ctx->streams[i]->priv_data;
+        av_fifo_freep(&stream->fifo);
+    }
+}
+
+
 #define OFFSET(x) offsetof(MpegMuxContext, x)
 #define E AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
@@ -1289,6 +1292,7 @@ AVOutputFormat ff_mpeg1system_muxer = {
     .write_header      = mpeg_mux_init,
     .write_packet      = mpeg_mux_write_packet,
     .write_trailer     = mpeg_mux_end,
+    .deinit            = mpeg_mux_deinit,
     .priv_class        = &mpeg_class,
 };
 #endif
@@ -1305,6 +1309,7 @@ AVOutputFormat ff_mpeg1vcd_muxer = {
     .write_header      = mpeg_mux_init,
     .write_packet      = mpeg_mux_write_packet,
     .write_trailer     = mpeg_mux_end,
+    .deinit            = mpeg_mux_deinit,
     .priv_class        = &vcd_class,
 };
 #endif
@@ -1322,6 +1327,7 @@ AVOutputFormat ff_mpeg2vob_muxer = {
     .write_header      = mpeg_mux_init,
     .write_packet      = mpeg_mux_write_packet,
     .write_trailer     = mpeg_mux_end,
+    .deinit            = mpeg_mux_deinit,
     .priv_class        = &vob_class,
 };
 #endif
@@ -1340,6 +1346,7 @@ AVOutputFormat ff_mpeg2svcd_muxer = {
     .write_header      = mpeg_mux_init,
     .write_packet      = mpeg_mux_write_packet,
     .write_trailer     = mpeg_mux_end,
+    .deinit            = mpeg_mux_deinit,
     .priv_class        = &svcd_class,
 };
 #endif
diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c
index 2c2334a..f828102 100644
--- a/libavformat/nutenc.c
+++ b/libavformat/nutenc.c
@@ -1172,7 +1172,7 @@ static int nut_write_trailer(AVFormatContext *s)
         write_headers(s, bc);
 
     ret = avio_open_dyn_buf(&dyn_bc);
-    if (ret >= 0 && nut->sp_count) {
+    if (ret >= 0) {
         av_assert1(nut->write_index); // sp_count should be 0 if no index is going to be written
         write_index(nut, dyn_bc);
         put_packet(nut, bc, dyn_bc, 1, INDEX_STARTCODE);
-- 
2.43.0