Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: James Almer via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: James Almer <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PR] [release/7.1] backport LCEVC fixes (PR #21443)
Date: Tue, 13 Jan 2026 00:47:58 -0000
Message-ID: <176826527967.25.17890061173258586806@4457048688e7> (raw)

PR #21443 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21443
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21443.patch


>From 75c42f558bdd609ca8f625769c10afdb2c55779a Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 25 Aug 2025 10:36:10 -0300
Subject: [PATCH 01/10] avcodec/lcevcdec: support LCEVCdec version 4

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavcodec/lcevcdec.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index 601e97b3a1..ba1887499a 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -139,7 +139,11 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
     if (!sd)
         return 1;
 
+#ifdef LCEVC_DEC_VERSION_MAJOR
+    res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, sd->data, sd->size);
+#else
     res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
+#endif
     if (res != LCEVC_Success)
         return AVERROR_EXTERNAL;
 
@@ -147,7 +151,11 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
     if (ret < 0)
         return ret;
 
+#ifdef LCEVC_DEC_VERSION_MAJOR
+    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, NULL);
+#else
     res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
+#endif
     if (res != LCEVC_Success)
         return AVERROR_EXTERNAL;
 
-- 
2.49.1


>From 4ef4474d65d7d5fde0805e6e0848a9a03ab97066 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 2 Nov 2025 15:29:59 +0100
Subject: [PATCH 02/10] avcodec/decode: Don't allocate LCEVC context for
 non-video

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
(cherry picked from commit 182b9c7a4a7117371d51caa917f26162db53cc56)
---
 libavcodec/decode.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index d8d3bd4d11..4f98945bcf 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -2084,9 +2084,11 @@ int ff_decode_preinit(AVCodecContext *avctx)
         return ret;
 
     if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) {
-        ret = ff_lcevc_alloc(&dc->lcevc);
-        if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
-            return ret;
+        if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+            ret = ff_lcevc_alloc(&dc->lcevc);
+            if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
+                return ret;
+        }
     }
 
 #if FF_API_DROPCHANGED
-- 
2.49.1


>From 4fff1187ac31f151b3b153ff8b2f3250e1ee56b8 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 2 Nov 2025 16:00:06 +0100
Subject: [PATCH 03/10] avcodec/decode: Put lcevc fields into structure of
 their own

Makes it easier to see that width and height in DecodeContext is
actually a lcevc field.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
(cherry picked from commit 2786e5a9ad32920fccee9352161e81c8e733563b)
---
 libavcodec/decode.c | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 4f98945bcf..9621f3dc7b 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -92,10 +92,12 @@ typedef struct DecodeContext {
      */
     uint64_t side_data_pref_mask;
 
-    FFLCEVCContext *lcevc;
-    int lcevc_frame;
-    int width;
-    int height;
+    struct {
+        FFLCEVCContext *ctx;
+        int frame;
+        int width;
+        int height;
+    } lcevc;
 } DecodeContext;
 
 static DecodeContext *decode_ctx(AVCodecInternal *avci)
@@ -1660,12 +1662,12 @@ static void update_frame_props(AVCodecContext *avctx, AVFrame *frame)
     AVCodecInternal    *avci = avctx->internal;
     DecodeContext        *dc = decode_ctx(avci);
 
-    dc->lcevc_frame = dc->lcevc && avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
+    dc->lcevc.frame = dc->lcevc.ctx && avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
                       av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC);
 
-    if (dc->lcevc_frame) {
-        dc->width     = frame->width;
-        dc->height    = frame->height;
+    if (dc->lcevc.frame) {
+        dc->lcevc.width  = frame->width;
+        dc->lcevc.height = frame->height;
         frame->width  = frame->width  * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
         frame->height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
     }
@@ -1676,7 +1678,7 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
     AVCodecInternal    *avci = avctx->internal;
     DecodeContext        *dc = decode_ctx(avci);
 
-    if (dc->lcevc_frame) {
+    if (dc->lcevc.frame) {
         FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
         FFLCEVCFrame *frame_ctx;
         int ret;
@@ -1691,13 +1693,13 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
             return AVERROR(ENOMEM);
         }
 
-        frame_ctx->lcevc = ff_refstruct_ref(dc->lcevc);
+        frame_ctx->lcevc = ff_refstruct_ref(dc->lcevc.ctx);
         frame_ctx->frame->width  = frame->width;
         frame_ctx->frame->height = frame->height;
         frame_ctx->frame->format = frame->format;
 
-        frame->width  = dc->width;
-        frame->height = dc->height;
+        frame->width  = dc->lcevc.width;
+        frame->height = dc->lcevc.height;
 
         ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0);
         if (ret < 0) {
@@ -1711,7 +1713,7 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
         fdd->post_process_opaque_free = ff_lcevc_unref;
         fdd->post_process = ff_lcevc_process;
     }
-    dc->lcevc_frame = 0;
+    dc->lcevc.frame = 0;
 
     return 0;
 }
@@ -2085,7 +2087,7 @@ int ff_decode_preinit(AVCodecContext *avctx)
 
     if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) {
         if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
-            ret = ff_lcevc_alloc(&dc->lcevc);
+            ret = ff_lcevc_alloc(&dc->lcevc.ctx);
             if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
                 return ret;
         }
@@ -2333,7 +2335,7 @@ void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext *src)
 
     dst_dc->initial_pict_type = src_dc->initial_pict_type;
     dst_dc->intra_only_flag   = src_dc->intra_only_flag;
-    ff_refstruct_replace(&dst_dc->lcevc, src_dc->lcevc);
+    ff_refstruct_replace(&dst_dc->lcevc.ctx, src_dc->lcevc.ctx);
 }
 
 void ff_decode_internal_uninit(AVCodecContext *avctx)
@@ -2341,5 +2343,5 @@ void ff_decode_internal_uninit(AVCodecContext *avctx)
     AVCodecInternal *avci = avctx->internal;
     DecodeContext *dc = decode_ctx(avci);
 
-    ff_refstruct_unref(&dc->lcevc);
+    ff_refstruct_unref(&dc->lcevc.ctx);
 }
-- 
2.49.1


>From 4007d2a532722e935675d5c9e0dc3de4dfaba1d5 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 2 Nov 2025 16:50:36 +0100
Subject: [PATCH 04/10] avcodec/decode: Optimize lcevc away if disabled

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
(cherry picked from commit 8e90f150ebccf3f30fe139245b7d22fd6f1ee4a9)
---
 libavcodec/Makefile   |  2 +-
 libavcodec/decode.c   | 12 ++++++++++++
 libavcodec/lcevcdec.c | 10 ----------
 3 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 153a9e3881..9d1c1fc30f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -46,7 +46,6 @@ OBJS = ac3_parser.o                                                     \
        get_buffer.o                                                     \
        imgconvert.o                                                     \
        jni.o                                                            \
-       lcevcdec.o                                                       \
        mathtables.o                                                     \
        mediacodec.o                                                     \
        mpeg12framerate.o                                                \
@@ -124,6 +123,7 @@ OBJS-$(CONFIG_IVIDSP)                  += ivi_dsp.o
 OBJS-$(CONFIG_JNI)                     += ffjni.o jni.o
 OBJS-$(CONFIG_JPEGTABLES)              += jpegtables.o
 OBJS-$(CONFIG_LCMS2)                   += fflcms2.o
+OBJS-$(CONFIG_LIBLCEVC_DEC)            += lcevcdec.o
 OBJS-$(CONFIG_LLAUDDSP)                += lossless_audiodsp.o
 OBJS-$(CONFIG_LLVIDDSP)                += lossless_videodsp.o
 OBJS-$(CONFIG_LLVIDENCDSP)             += lossless_videoencdsp.o
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 9621f3dc7b..0ab0f4bb4d 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -92,12 +92,14 @@ typedef struct DecodeContext {
      */
     uint64_t side_data_pref_mask;
 
+#if CONFIG_LIBLCEVC_DEC
     struct {
         FFLCEVCContext *ctx;
         int frame;
         int width;
         int height;
     } lcevc;
+#endif
 } DecodeContext;
 
 static DecodeContext *decode_ctx(AVCodecInternal *avci)
@@ -1659,6 +1661,7 @@ int ff_attach_decode_data(AVFrame *frame)
 
 static void update_frame_props(AVCodecContext *avctx, AVFrame *frame)
 {
+#if CONFIG_LIBLCEVC_DEC
     AVCodecInternal    *avci = avctx->internal;
     DecodeContext        *dc = decode_ctx(avci);
 
@@ -1671,10 +1674,12 @@ static void update_frame_props(AVCodecContext *avctx, AVFrame *frame)
         frame->width  = frame->width  * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
         frame->height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
     }
+#endif
 }
 
 static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
 {
+#if CONFIG_LIBLCEVC_DEC
     AVCodecInternal    *avci = avctx->internal;
     DecodeContext        *dc = decode_ctx(avci);
 
@@ -1714,6 +1719,7 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
         fdd->post_process = ff_lcevc_process;
     }
     dc->lcevc.frame = 0;
+#endif
 
     return 0;
 }
@@ -2087,9 +2093,11 @@ int ff_decode_preinit(AVCodecContext *avctx)
 
     if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) {
         if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+#if CONFIG_LIBLCEVC_DEC
             ret = ff_lcevc_alloc(&dc->lcevc.ctx);
             if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
                 return ret;
+#endif
         }
     }
 
@@ -2335,13 +2343,17 @@ void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext *src)
 
     dst_dc->initial_pict_type = src_dc->initial_pict_type;
     dst_dc->intra_only_flag   = src_dc->intra_only_flag;
+#if CONFIG_LIBLCEVC_DEC
     ff_refstruct_replace(&dst_dc->lcevc.ctx, src_dc->lcevc.ctx);
+#endif
 }
 
 void ff_decode_internal_uninit(AVCodecContext *avctx)
 {
+#if CONFIG_LIBLCEVC_DEC
     AVCodecInternal *avci = avctx->internal;
     DecodeContext *dc = decode_ctx(avci);
 
     ff_refstruct_unref(&dc->lcevc.ctx);
+#endif
 }
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index ba1887499a..41049f72fc 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -16,8 +16,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "config_components.h"
-
 #include "libavutil/avassert.h"
 #include "libavutil/frame.h"
 #include "libavutil/imgutils.h"
@@ -26,7 +24,6 @@
 #include "decode.h"
 #include "lcevcdec.h"
 
-#if CONFIG_LIBLCEVC_DEC
 static LCEVC_ColorFormat map_format(int format)
 {
     switch (format) {
@@ -255,11 +252,9 @@ static void lcevc_free(FFRefStructOpaque unused, void *obj)
         LCEVC_DestroyDecoder(lcevc->decoder);
     memset(lcevc, 0, sizeof(*lcevc));
 }
-#endif
 
 static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
 {
-#if CONFIG_LIBLCEVC_DEC
     LCEVC_AccelContextHandle dummy = { 0 };
     const int32_t event = LCEVC_Log;
 
@@ -278,7 +273,6 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
         return AVERROR_EXTERNAL;
     }
 
-#endif
     lcevc->initialized = 1;
 
     return 0;
@@ -297,7 +291,6 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
             return ret;
     }
 
-#if CONFIG_LIBLCEVC_DEC
     av_assert0(frame_ctx->frame);
 
 
@@ -310,7 +303,6 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
         return ret;
 
     av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC);
-#endif
 
     return 0;
 }
@@ -318,11 +310,9 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
 int ff_lcevc_alloc(FFLCEVCContext **plcevc)
 {
     FFLCEVCContext *lcevc = NULL;
-#if CONFIG_LIBLCEVC_DEC
     lcevc = ff_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free);
     if (!lcevc)
         return AVERROR(ENOMEM);
-#endif
     *plcevc = lcevc;
     return 0;
 }
-- 
2.49.1


>From 044ca5f5ef0e7a7770069d10da86cc64bf9feaa1 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 22 Dec 2025 21:53:47 -0300
Subject: [PATCH 05/10] avcodec/lcevcdec: avoid copying the input frame

Based on the lcevc filter implementation.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit b392d75cf72cca90b5476e0c1b2e0876f3aff4ab)
---
 libavcodec/lcevcdec.c | 37 +++++++------------------------------
 1 file changed, 7 insertions(+), 30 deletions(-)

diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index 41049f72fc..5f0c41b52d 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -47,10 +47,7 @@ static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
 {
     LCEVC_PictureDesc desc;
     LCEVC_ColorFormat fmt = map_format(frame->format);
-    LCEVC_PictureLockHandle lock;
-    uint8_t *data[4] = { NULL };
-    int linesizes[4] = { 0 };
-    uint32_t planes;
+    LCEVC_PicturePlaneDesc planes[AV_VIDEO_MAX_PLANES] = { 0 };
     LCEVC_ReturnCode res;
 
     res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height);
@@ -64,36 +61,16 @@ static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
     desc.sampleAspectRatioNum  = frame->sample_aspect_ratio.num;
     desc.sampleAspectRatioDen  = frame->sample_aspect_ratio.den;
 
+    for (int i = 0; i < AV_VIDEO_MAX_PLANES; i++) {
+        planes[i].firstSample = frame->data[i];
+        planes[i].rowByteStride = frame->linesize[i];
+    }
+
     /* Allocate LCEVC Picture */
-    res = LCEVC_AllocPicture(lcevc->decoder, &desc, picture);
+    res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture);
     if (res != LCEVC_Success) {
         return AVERROR_EXTERNAL;
     }
-    res = LCEVC_LockPicture(lcevc->decoder, *picture, LCEVC_Access_Write, &lock);
-    if (res != LCEVC_Success)
-        return AVERROR_EXTERNAL;
-
-    res = LCEVC_GetPicturePlaneCount(lcevc->decoder, *picture, &planes);
-    if (res != LCEVC_Success)
-        return AVERROR_EXTERNAL;
-
-    for (unsigned i = 0; i < planes; i++) {
-        LCEVC_PicturePlaneDesc plane;
-
-        res = LCEVC_GetPictureLockPlaneDesc(lcevc->decoder, lock, i, &plane);
-        if (res != LCEVC_Success)
-            return AVERROR_EXTERNAL;
-
-        data[i] = plane.firstSample;
-        linesizes[i] = plane.rowByteStride;
-    }
-
-    av_image_copy2(data, linesizes, frame->data, frame->linesize,
-                   frame->format, frame->width, frame->height);
-
-    res = LCEVC_UnlockPicture(lcevc->decoder, lock);
-    if (res != LCEVC_Success)
-        return AVERROR_EXTERNAL;
 
     return 0;
 }
-- 
2.49.1


>From 0d9b8bfc0ef68424630855feb93e1b19b517cecb Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 22 Dec 2025 21:54:43 -0300
Subject: [PATCH 06/10] avcodec/lcevcdec: fix input dimensions for the base
 picture

Fixes crashes with some samples.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 4f86ebfe940cd11de8f5ccf39e2b45da8354269d)
---
 libavcodec/lcevcdec.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index 5f0c41b52d..cea396325e 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -48,9 +48,11 @@ static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
     LCEVC_PictureDesc desc;
     LCEVC_ColorFormat fmt = map_format(frame->format);
     LCEVC_PicturePlaneDesc planes[AV_VIDEO_MAX_PLANES] = { 0 };
+    int width = frame->width - frame->crop_left - frame->crop_right;
+    int height = frame->height - frame->crop_top - frame->crop_bottom;
     LCEVC_ReturnCode res;
 
-    res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height);
+    res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
     if (res != LCEVC_Success)
         return AVERROR_EXTERNAL;
 
-- 
2.49.1


>From c74b4512e09eb7cdbb05772faaef7bd4ce6be089 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 22 Dec 2025 21:56:09 -0300
Subject: [PATCH 07/10] avcodec/lcevcdec: free pictures on error

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit fe1dae1e1857ebda9624f4be3f93f447097ae942)
---
 libavcodec/lcevcdec.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index cea396325e..76bdbdbe07 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -132,8 +132,10 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
 #else
     res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
 #endif
-    if (res != LCEVC_Success)
+    if (res != LCEVC_Success) {
+        LCEVC_FreePicture(lcevc->decoder, picture);
         return AVERROR_EXTERNAL;
+    }
 
     memset(&picture, 0, sizeof(picture));
     ret = alloc_enhanced_frame(logctx, frame_ctx, &picture);
@@ -141,8 +143,10 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
         return ret;
 
     res = LCEVC_SendDecoderPicture(lcevc->decoder, picture);
-    if (res != LCEVC_Success)
+    if (res != LCEVC_Success) {
+        LCEVC_FreePicture(lcevc->decoder, picture);
         return AVERROR_EXTERNAL;
+    }
 
     return 0;
 }
@@ -160,8 +164,10 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
         return AVERROR_EXTERNAL;
 
     res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
-    if (res != LCEVC_Success)
+    if (res != LCEVC_Success) {
+        LCEVC_FreePicture(lcevc->decoder, picture);
         return AVERROR_EXTERNAL;
+    }
 
     out->crop_top = desc.cropTop;
     out->crop_bottom = desc.cropBottom;
-- 
2.49.1


>From 0e1dd337013996536a1e136128f47e572d092c60 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Wed, 7 Jan 2026 12:16:27 -0300
Subject: [PATCH 08/10] avcodec/lcevc: attach a reference to the source frame
 to each passed in base picture

This way we can ensure a frame reference will always exists for as long as the
external library needs the base picture.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 188521c7ad9e2a82d913770c3102593ebcd3454d)
---
 libavcodec/lcevcdec.c | 59 +++++++++++++++++++++++++++++++------------
 1 file changed, 43 insertions(+), 16 deletions(-)

diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index 76bdbdbe07..1bfb7c78c5 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -108,6 +108,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
 {
     FFLCEVCContext *lcevc = frame_ctx->lcevc;
     const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
+    AVFrame *opaque;
     LCEVC_PictureHandle picture;
     LCEVC_ReturnCode res;
     int ret = 0;
@@ -127,13 +128,27 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
     if (ret < 0)
         return ret;
 
+    opaque = av_frame_clone(in);
+    if (!opaque) {
+        LCEVC_FreePicture(lcevc->decoder, picture);
+        return AVERROR(ENOMEM);
+    }
+
+    res = LCEVC_SetPictureUserData(lcevc->decoder, picture, opaque);
+    if (res != LCEVC_Success) {
+        LCEVC_FreePicture(lcevc->decoder, picture);
+        av_frame_free(&opaque);
+        return AVERROR_EXTERNAL;
+    }
+
 #ifdef LCEVC_DEC_VERSION_MAJOR
-    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, NULL);
+    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, opaque);
 #else
-    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
+    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, opaque);
 #endif
     if (res != LCEVC_Success) {
         LCEVC_FreePicture(lcevc->decoder, picture);
+        av_frame_free(&opaque);
         return AVERROR_EXTERNAL;
     }
 
@@ -169,17 +184,16 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
         return AVERROR_EXTERNAL;
     }
 
+    av_frame_unref(out);
+    av_frame_copy_props(frame_ctx->frame, (AVFrame *)info.baseUserData);
+    av_frame_move_ref(out, frame_ctx->frame);
+
     out->crop_top = desc.cropTop;
     out->crop_bottom = desc.cropBottom;
     out->crop_left = desc.cropLeft;
     out->crop_right = desc.cropRight;
     out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
     out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
-
-    av_frame_copy_props(frame_ctx->frame, out);
-    av_frame_unref(out);
-    av_frame_move_ref(out, frame_ctx->frame);
-
     out->width = desc.width + out->crop_left + out->crop_right;
     out->height = desc.height + out->crop_top + out->crop_bottom;
 
@@ -190,18 +204,13 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
     return 0;
 }
 
-static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
+static int lcevc_flush_pictures(FFLCEVCContext *lcevc)
 {
-    FFLCEVCContext *lcevc = frame_ctx->lcevc;
     LCEVC_PictureHandle picture;
     LCEVC_ReturnCode res;
-    int ret;
-
-    ret = generate_output(logctx, frame_ctx, out);
-    if (ret < 0)
-        return ret;
 
     while (1) {
+        AVFrame *base = NULL;
         res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture);
         if (res != LCEVC_Success && res != LCEVC_Again)
             return AVERROR_EXTERNAL;
@@ -209,6 +218,9 @@ static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *o
         if (res == LCEVC_Again)
             break;
 
+        LCEVC_GetPictureUserData(lcevc->decoder, picture, (void **)&base);
+        av_frame_free(&base);
+
         res = LCEVC_FreePicture(lcevc->decoder, picture);
         if (res != LCEVC_Success)
             return AVERROR_EXTERNAL;
@@ -217,6 +229,18 @@ static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *o
     return 0;
 }
 
+static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
+{
+    FFLCEVCContext *lcevc = frame_ctx->lcevc;
+    int ret;
+
+    ret = generate_output(logctx, frame_ctx, out);
+    if (ret < 0)
+        return ret;
+
+    return lcevc_flush_pictures(lcevc);
+}
+
 static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
     LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info,
     const uint8_t *data, uint32_t size, void *logctx)
@@ -233,8 +257,11 @@ static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
 static void lcevc_free(FFRefStructOpaque unused, void *obj)
 {
     FFLCEVCContext *lcevc = obj;
-    if (lcevc->initialized)
+    if (lcevc->initialized) {
+        LCEVC_FlushDecoder(lcevc->decoder);
+        lcevc_flush_pictures(lcevc);
         LCEVC_DestroyDecoder(lcevc->decoder);
+    }
     memset(lcevc, 0, sizeof(*lcevc));
 }
 
@@ -283,7 +310,7 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
     if (ret)
         return ret < 0 ? ret : 0;
 
-    lcevc_receive_frame(logctx, frame_ctx, frame);
+    ret = lcevc_receive_frame(logctx, frame_ctx, frame);
     if (ret < 0)
         return ret;
 
-- 
2.49.1


>From e95d47ad5f87fb681415e7ac45e5f26d4023c169 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 25 Aug 2025 10:36:26 -0300
Subject: [PATCH 09/10] avfilter/vf_lcevc: support LCEVCdec version 4

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavfilter/vf_lcevc.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/libavfilter/vf_lcevc.c b/libavfilter/vf_lcevc.c
index b83dc94e02..5fe8a0a868 100644
--- a/libavfilter/vf_lcevc.c
+++ b/libavfilter/vf_lcevc.c
@@ -139,7 +139,11 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in)
         return ret;
 
     if (sd) {
+#ifdef LCEVC_DEC_VERSION_MAJOR
+        res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, sd->data, sd->size);
+#else
         res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
+#endif
         if (res == LCEVC_Again)
             return AVERROR(EAGAIN);
         else if (res != LCEVC_Success) {
@@ -148,7 +152,11 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in)
         }
     }
 
+#ifdef LCEVC_DEC_VERSION_MAJOR
+    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, in);
+#else
     res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, in);
+#endif
     if (res != LCEVC_Success) {
         av_log(ctx, AV_LOG_ERROR, "LCEVC_SendDecoderBase failed\n");
         LCEVC_FreePicture(lcevc->decoder, picture);
-- 
2.49.1


>From 09dc319bf3de78803f7f6a637e2cafdc441499e5 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Sat, 10 Jan 2026 15:48:46 -0300
Subject: [PATCH 10/10] avfilter/vf_lcevc: attach a reference to the source
 frame to each passed in base picture

And free them once they are guaranteed to be no longer needed, instead of freeing them
when returned with an enhanced output.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit af136db1c3c5d72c4a71cedaf7b06d2f8ae3819e)
---
 libavfilter/vf_lcevc.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/libavfilter/vf_lcevc.c b/libavfilter/vf_lcevc.c
index 5fe8a0a868..318b144374 100644
--- a/libavfilter/vf_lcevc.c
+++ b/libavfilter/vf_lcevc.c
@@ -152,6 +152,13 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in)
         }
     }
 
+    res = LCEVC_SetPictureUserData(lcevc->decoder, picture, in);
+    if (res != LCEVC_Success) {
+        av_log(ctx, AV_LOG_ERROR, "LCEVC_SetPictureUserData failed\n");
+        LCEVC_FreePicture(lcevc->decoder, picture);
+        return AVERROR_EXTERNAL;
+    }
+
 #ifdef LCEVC_DEC_VERSION_MAJOR
     res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, in);
 #else
@@ -223,8 +230,6 @@ static int generate_output(AVFilterLink *inlink, AVFrame *out)
     av_frame_copy_props(out, (AVFrame *)info.baseUserData);
     av_frame_remove_side_data(out, AV_FRAME_DATA_LCEVC);
 
-    av_frame_free((AVFrame **)&info.baseUserData);
-
     res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
     LCEVC_FreePicture(lcevc->decoder, picture);
 
@@ -292,8 +297,12 @@ static void flush_bases(AVFilterContext *ctx)
     LCEVCContext *lcevc = ctx->priv;
     LCEVC_PictureHandle picture;
 
-    while (LCEVC_ReceiveDecoderBase(lcevc->decoder, &picture) == LCEVC_Success)
+    while (LCEVC_ReceiveDecoderBase(lcevc->decoder, &picture) == LCEVC_Success) {
+        AVFrame *base = NULL;
+        LCEVC_GetPictureUserData(lcevc->decoder, picture, (void **)&base);
         LCEVC_FreePicture(lcevc->decoder, picture);
+        av_frame_free(&base);
+    }
 }
 
 static int activate(AVFilterContext *ctx)
@@ -407,6 +416,8 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     LCEVCContext *lcevc = ctx->priv;
 
+    LCEVC_FlushDecoder(lcevc->decoder);
+    flush_bases(ctx);
     LCEVC_DestroyDecoder(lcevc->decoder);
 }
 
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

                 reply	other threads:[~2026-01-13  0:49 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=176826527967.25.17890061173258586806@4457048688e7 \
    --to=ffmpeg-devel@ffmpeg.org \
    --cc=code@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git