PR #22822 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22822
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22822.patch


>From 8ae06df5cf512b51d2eca1498b0932b1f2f07e44 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 14:49:56 +0200
Subject: [PATCH 1/8] avcodec/lcevcdec: Use pool to avoid allocations of
 FFLCEVCFrame

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/decode.c   | 10 ++--------
 libavcodec/lcevcdec.c | 39 ++++++++++++++++++++++++++++++++++++---
 libavcodec/lcevcdec.h |  1 +
 3 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 206b711390..892f6fce1d 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1726,16 +1726,10 @@ int ff_attach_decode_data(AVCodecContext *avctx, 
AVFrame *frame)
             return 0;
         }
 
-        frame_ctx = av_mallocz(sizeof(*frame_ctx));
+        frame_ctx = av_refstruct_pool_get(dc->lcevc.ctx->frame_pool);
         if (!frame_ctx)
             return AVERROR(ENOMEM);
 
-        frame_ctx->frame = av_frame_alloc();
-        if (!frame_ctx->frame) {
-            av_free(frame_ctx);
-            return AVERROR(ENOMEM);
-        }
-
         frame_ctx->lcevc = av_refstruct_ref(dc->lcevc.ctx);
         frame_ctx->frame->width  = dc->lcevc.width;
         frame_ctx->frame->height = dc->lcevc.height;
@@ -1747,7 +1741,7 @@ int ff_attach_decode_data(AVCodecContext *avctx, AVFrame 
*frame)
 
         ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0);
         if (ret < 0) {
-            ff_lcevc_unref(frame_ctx);
+            av_refstruct_unref(&frame_ctx);
             return ret;
         }
 
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index 013cae9147..70e6733909 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -300,9 +300,35 @@ static void lcevc_free(AVRefStructOpaque unused, void *obj)
         ff_cbs_fragment_free(lcevc->frag);
     av_freep(&lcevc->frag);
     ff_cbs_close(&lcevc->cbc);
+    av_refstruct_pool_uninit(&lcevc->frame_pool);
     memset(lcevc, 0, sizeof(*lcevc));
 }
 
+static av_cold int lcevc_frame_init_cb(AVRefStructOpaque unused, void *obj)
+{
+    FFLCEVCFrame *frame = obj;
+
+    frame->frame = av_frame_alloc();
+    if (!frame->frame)
+        return AVERROR(ENOMEM);
+    return 0;
+}
+
+static void lcevc_frame_reset_cb(AVRefStructOpaque unused, void *obj)
+{
+    FFLCEVCFrame *frame = obj;
+
+    av_frame_unref(frame->frame);
+    av_refstruct_unref(&frame->lcevc);
+}
+
+static av_cold void lcevc_frame_free_entry_cb(AVRefStructOpaque unused, void 
*obj)
+{
+    FFLCEVCFrame *frame = obj;
+
+    av_frame_free(&frame->frame);
+}
+
 static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
 {
     LCEVC_AccelContextHandle dummy = { 0 };
@@ -423,6 +449,15 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc, void *logctx)
     lcevc->cbc->decompose_unit_types    = decompose_unit_types;
     lcevc->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types);
 
+    lcevc->frame_pool = av_refstruct_pool_alloc_ext(sizeof(FFLCEVCFrame), 0, 
NULL,
+                                                    lcevc_frame_init_cb,
+                                                    lcevc_frame_reset_cb,
+                                                    lcevc_frame_free_entry_cb, 
NULL);
+    if (!lcevc->frame_pool) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
     *plcevc = lcevc;
     return 0;
 fail:
@@ -433,7 +468,5 @@ fail:
 void ff_lcevc_unref(void *opaque)
 {
     FFLCEVCFrame *lcevc = opaque;
-    av_refstruct_unref(&lcevc->lcevc);
-    av_frame_free(&lcevc->frame);
-    av_free(opaque);
+    av_refstruct_unref(&lcevc);
 }
diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h
index 0a255d2951..5aed07f999 100644
--- a/libavcodec/lcevcdec.h
+++ b/libavcodec/lcevcdec.h
@@ -35,6 +35,7 @@ typedef struct FFLCEVCContext {
     LCEVC_DecoderHandle decoder;
     struct CodedBitstreamContext *cbc;
     struct CodedBitstreamFragment *frag;
+    struct AVRefStructPool *frame_pool; ///< pool of FFLCEVCFrame
     int initialized;
 } FFLCEVCContext;
 
-- 
2.52.0


>From 0e78b552d2341bdf1a096184ed58eac9f0a45e50 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 15:02:04 +0200
Subject: [PATCH 2/8] avcodec/decode: Make post_process_opaque a RefStruct
 reference

Avoids the post_process_opaque_free callback; the only user of
this is already a RefStruct reference and presumably other users
would want to use a pool for this, too, so they would use
RefStruct-objects, too.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/decode.c   | 4 +---
 libavcodec/decode.h   | 3 +--
 libavcodec/lcevcdec.c | 6 ------
 libavcodec/lcevcdec.h | 2 +-
 4 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 892f6fce1d..b7392cae23 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1676,8 +1676,7 @@ static void decode_data_free(AVRefStructOpaque unused, 
void *obj)
 {
     FrameDecodeData *fdd = obj;
 
-    if (fdd->post_process_opaque_free)
-        fdd->post_process_opaque_free(fdd->post_process_opaque);
+    av_refstruct_unref(&fdd->post_process_opaque);
 
     if (fdd->hwaccel_priv_free)
         fdd->hwaccel_priv_free(fdd->hwaccel_priv);
@@ -1748,7 +1747,6 @@ int ff_attach_decode_data(AVCodecContext *avctx, AVFrame 
*frame)
         validate_avframe_allocation(avctx, frame_ctx->frame);
 
         fdd->post_process_opaque = frame_ctx;
-        fdd->post_process_opaque_free = ff_lcevc_unref;
         fdd->post_process = ff_lcevc_process;
     }
     dc->lcevc.frame = 0;
diff --git a/libavcodec/decode.h b/libavcodec/decode.h
index 5a7ab64c29..b4ae0ba8fe 100644
--- a/libavcodec/decode.h
+++ b/libavcodec/decode.h
@@ -42,8 +42,7 @@ typedef struct FrameDecodeData {
      * stored in the post_process_opaque object.
      */
     int (*post_process)(void *logctx, AVFrame *frame);
-    void *post_process_opaque;
-    void (*post_process_opaque_free)(void *opaque);
+    void *post_process_opaque;                        ///< RefStruct reference
 
     /**
      * Per-frame private data for hwaccels.
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index 70e6733909..3aba6f6aeb 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -464,9 +464,3 @@ fail:
     av_refstruct_unref(&lcevc);
     return ret;
 }
-
-void ff_lcevc_unref(void *opaque)
-{
-    FFLCEVCFrame *lcevc = opaque;
-    av_refstruct_unref(&lcevc);
-}
diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h
index 5aed07f999..3120f423d1 100644
--- a/libavcodec/lcevcdec.h
+++ b/libavcodec/lcevcdec.h
@@ -50,5 +50,5 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc, void *logctx);
 int ff_lcevc_process(void *logctx, struct AVFrame *frame);
 int ff_lcevc_parse_frame(FFLCEVCContext *lcevc, const struct AVFrame *frame,
                          enum AVPixelFormat *format, int *width, int *height, 
void *logctx);
-void ff_lcevc_unref(void *opaque);
+
 #endif /* AVCODEC_LCEVCDEC_H */
-- 
2.52.0


>From f9a3f4440b64c6922b513161da150d0e76f83dba Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 15:06:00 +0200
Subject: [PATCH 3/8] avcodec/decode: Remove always-true checks

dc->lcevc.ctx is only != NULL for video.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/decode.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index b7392cae23..c1f3d6d6d9 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1626,7 +1626,7 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame 
*frame)
     AVCodecInternal    *avci = avctx->internal;
     DecodeContext        *dc = decode_ctx(avci);
 
-    dc->lcevc.frame = dc->lcevc.ctx && avctx->codec_type == AVMEDIA_TYPE_VIDEO 
&&
+    dc->lcevc.frame = dc->lcevc.ctx &&
                       av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC);
 
     if (dc->lcevc.frame) {
@@ -1700,7 +1700,7 @@ int ff_attach_decode_data(AVCodecContext *avctx, AVFrame 
*frame)
     DecodeContext        *dc = decode_ctx(avci);
 
     if (!dc->lcevc.frame) {
-        dc->lcevc.frame = dc->lcevc.ctx && avctx->codec_type == 
AVMEDIA_TYPE_VIDEO &&
+        dc->lcevc.frame = dc->lcevc.ctx &&
                           av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC);
 
         if (dc->lcevc.frame) {
-- 
2.52.0


>From ac6ccbee9190bc9715f6111cf30115cf7178cd6a Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 15:10:18 +0200
Subject: [PATCH 4/8] avcodec/decode: Optimize call away if possible

post_process_opaque is only used by LCEVC, so it is unused
on most builds.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/decode.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index c1f3d6d6d9..735ee3bf91 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1676,7 +1676,10 @@ static void decode_data_free(AVRefStructOpaque unused, 
void *obj)
 {
     FrameDecodeData *fdd = obj;
 
-    av_refstruct_unref(&fdd->post_process_opaque);
+    if (CONFIG_LIBLCEVC_DEC)
+        av_refstruct_unref(&fdd->post_process_opaque);
+    else
+        av_assert1(!fdd->post_process_opaque);
 
     if (fdd->hwaccel_priv_free)
         fdd->hwaccel_priv_free(fdd->hwaccel_priv);
-- 
2.52.0


>From a882ccbefc2216d5367d7aef37ed2dada4fd050b Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 15:12:54 +0200
Subject: [PATCH 5/8] avcodec/decode: Fix shadowing

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/decode.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 735ee3bf91..a49395c9b3 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1570,7 +1570,7 @@ int ff_decode_frame_props_from_pkt(const AVCodecContext 
*avctx,
     }
 
     if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
-        int ret = av_buffer_replace(&frame->opaque_ref, pkt->opaque_ref);
+        ret = av_buffer_replace(&frame->opaque_ref, pkt->opaque_ref);
         if (ret < 0)
             return ret;
         frame->opaque = pkt->opaque;
@@ -1630,7 +1630,7 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame 
*frame)
                       av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC);
 
     if (dc->lcevc.frame) {
-        int ret = ff_lcevc_parse_frame(dc->lcevc.ctx, frame, &dc->lcevc.format,
+        ret = ff_lcevc_parse_frame(dc->lcevc.ctx, frame, &dc->lcevc.format,
                                        &dc->lcevc.width, &dc->lcevc.height, 
avctx);
         if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
             return ret;
-- 
2.52.0


>From 629b68d41ec6d04511c061922846ed47b2c37c73 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 15:58:48 +0200
Subject: [PATCH 6/8] avcodec/decode: Avoid temporary frame in
 ff_reget_buffer()

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/decode.c | 39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index a49395c9b3..7ad3077521 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <assert.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <string.h>
@@ -1833,7 +1834,6 @@ fail:
 
 static int reget_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int 
flags)
 {
-    AVFrame *tmp;
     int ret;
 
     av_assert0(avctx->codec_type == AVMEDIA_TYPE_VIDEO);
@@ -1855,22 +1855,37 @@ static int reget_buffer_internal(AVCodecContext *avctx, 
AVFrame *frame, int flag
     if ((flags & FF_REGET_BUFFER_FLAG_READONLY) || av_frame_is_writable(frame))
         return ff_decode_frame_props(avctx, frame);
 
-    tmp = av_frame_alloc();
-    if (!tmp)
-        return AVERROR(ENOMEM);
+    uint8_t *data[AV_VIDEO_MAX_PLANES];
+    AVBufferRef *buf[AV_VIDEO_MAX_PLANES];
+    int linesize[AV_VIDEO_MAX_PLANES];
 
-    av_frame_move_ref(tmp, frame);
+    static_assert(AV_VIDEO_MAX_PLANES <= FF_ARRAY_ELEMS(frame->data) &&
+                  AV_VIDEO_MAX_PLANES <= FF_ARRAY_ELEMS(frame->buf)  &&
+                  AV_VIDEO_MAX_PLANES <= FF_ARRAY_ELEMS(frame->linesize),
+                  "Copying code needs to be adjusted");
+    static_assert(sizeof(frame->linesize[0]) == sizeof(linesize[0]),
+                  "linesize needs to be switched to ptrdiff_t");
+
+    for (int i = 0; i < AV_VIDEO_MAX_PLANES; ++i) {
+        data[i]       = frame->data[i];
+        linesize[i]   = frame->linesize[i];
+        buf[i]        = frame->buf[i];
+        frame->buf[i] = NULL;
+    }
+    av_assert1(!frame->buf[AV_VIDEO_MAX_PLANES] && !frame->extended_buf);
+
+    av_frame_unref(frame);
 
     ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF);
-    if (ret < 0) {
-        av_frame_free(&tmp);
-        return ret;
+    if (ret >= 0) {
+        av_image_copy2(frame->data, frame->linesize,
+                       data, linesize,
+                       frame->format, frame->width, frame->height);
     }
+    for (int i = 0; i < AV_VIDEO_MAX_PLANES; ++i)
+        av_buffer_unref(&buf[i]);
 
-    av_frame_copy(frame, tmp);
-    av_frame_free(&tmp);
-
-    return 0;
+    return ret;
 }
 
 int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
-- 
2.52.0


>From fe0c6460bb7e70d3b6528b08a2f0d7ba1966098f Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 16:21:28 +0200
Subject: [PATCH 7/8] avcodec/decode: Short-circuit side-data processing

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/decode.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 7ad3077521..ac654f1f4c 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1556,15 +1556,17 @@ int ff_decode_frame_props_from_pkt(const AVCodecContext 
*avctx,
     frame->pts          = pkt->pts;
     frame->duration     = pkt->duration;
 
-    ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, 
ff_sd_global_map);
-    if (ret < 0)
-        return ret;
+    if (pkt->side_data_elems) {
+        ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, 
ff_sd_global_map);
+        if (ret < 0)
+            return ret;
 
-    ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, sd);
-    if (ret < 0)
-        return ret;
+        ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, sd);
+        if (ret < 0)
+            return ret;
 
-    add_metadata_from_side_data(pkt, frame);
+        add_metadata_from_side_data(pkt, frame);
+    }
 
     if (pkt->flags & AV_PKT_FLAG_DISCARD) {
         frame->flags |= AV_FRAME_FLAG_DISCARD;
-- 
2.52.0


>From fa4697a805122ceb992e703248cb2780be4b8012 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 15 Apr 2026 16:22:45 +0200
Subject: [PATCH 8/8] avcodec/packet: Remove always-true check

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/packet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/packet.c b/libavcodec/packet.c
index 348159f7f7..a2d453a4b3 100644
--- a/libavcodec/packet.c
+++ b/libavcodec/packet.c
@@ -358,7 +358,7 @@ int av_packet_unpack_dictionary(const uint8_t *data, size_t 
size,
     if (!dict || !data || !size)
         return 0;
     end = data + size;
-    if (size && end[-1])
+    if (end[-1])
         return AVERROR_INVALIDDATA;
     while (data < end) {
         const uint8_t *key = data;
-- 
2.52.0

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

Reply via email to