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/8.0] backport LCEVC fixes (PR #21433)
Date: Sun, 11 Jan 2026 23:42:02 -0000
Message-ID: <176817492301.25.2086506522879281262@4457048688e7> (raw)
PR #21433 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21433
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21433.patch
>From 02e30de0432aa3f988bfd2e66d12424fc9d7926f 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 1/8] 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 730d4f90fe..2178931758 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1995,9 +1995,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;
+ }
}
return 0;
--
2.49.1
>From a635df770f0c0bd6e0ad3d06cac8c5d7d6982525 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 2/8] 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 2178931758..d88d245f3d 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -93,10 +93,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)
@@ -1576,12 +1578,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);
}
@@ -1592,7 +1594,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 = frame->private_ref;
FFLCEVCFrame *frame_ctx;
int ret;
@@ -1607,13 +1609,13 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
return AVERROR(ENOMEM);
}
- frame_ctx->lcevc = av_refstruct_ref(dc->lcevc);
+ frame_ctx->lcevc = av_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) {
@@ -1627,7 +1629,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;
}
@@ -1996,7 +1998,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;
}
@@ -2239,7 +2241,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;
- av_refstruct_replace(&dst_dc->lcevc, src_dc->lcevc);
+ av_refstruct_replace(&dst_dc->lcevc.ctx, src_dc->lcevc.ctx);
}
void ff_decode_internal_uninit(AVCodecContext *avctx)
@@ -2247,5 +2249,5 @@ void ff_decode_internal_uninit(AVCodecContext *avctx)
AVCodecInternal *avci = avctx->internal;
DecodeContext *dc = decode_ctx(avci);
- av_refstruct_unref(&dc->lcevc);
+ av_refstruct_unref(&dc->lcevc.ctx);
}
--
2.49.1
>From 050da957c38851f6ee7e7fe4f6ccf478defaf459 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 3/8] 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 fb22541f8d..5a4d4d341c 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -45,7 +45,6 @@ OBJS = ac3_parser.o \
get_buffer.o \
imgconvert.o \
jni.o \
- lcevcdec.o \
mathtables.o \
mediacodec.o \
mpeg12framerate.o \
@@ -128,6 +127,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 d88d245f3d..d94232081c 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -93,12 +93,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)
@@ -1575,6 +1577,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);
@@ -1587,10 +1590,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);
@@ -1630,6 +1635,7 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
fdd->post_process = ff_lcevc_process;
}
dc->lcevc.frame = 0;
+#endif
return 0;
}
@@ -1998,9 +2004,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
}
}
@@ -2241,13 +2249,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
av_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);
av_refstruct_unref(&dc->lcevc.ctx);
+#endif
}
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index 158957abc5..45c4ad391c 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"
@@ -28,7 +26,6 @@
#include "decode.h"
#include "lcevcdec.h"
-#if CONFIG_LIBLCEVC_DEC
static LCEVC_ColorFormat map_format(int format)
{
switch (format) {
@@ -257,11 +254,9 @@ static void lcevc_free(AVRefStructOpaque 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;
@@ -280,7 +275,6 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
return AVERROR_EXTERNAL;
}
-#endif
lcevc->initialized = 1;
return 0;
@@ -299,7 +293,6 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
return ret;
}
-#if CONFIG_LIBLCEVC_DEC
av_assert0(frame_ctx->frame);
@@ -312,7 +305,6 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
return ret;
av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC);
-#endif
return 0;
}
@@ -320,11 +312,9 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
int ff_lcevc_alloc(FFLCEVCContext **plcevc)
{
FFLCEVCContext *lcevc = NULL;
-#if CONFIG_LIBLCEVC_DEC
lcevc = av_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free);
if (!lcevc)
return AVERROR(ENOMEM);
-#endif
*plcevc = lcevc;
return 0;
}
--
2.49.1
>From c92c2bc86370f9f9fde549f827feaddd62b26a58 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 22 Dec 2025 21:53:47 -0300
Subject: [PATCH 4/8] 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 45c4ad391c..d5cc2b73f3 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -49,10 +49,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);
@@ -66,36 +63,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 3db8e93a209904786c679261a38d9e1acb43d4d7 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 22 Dec 2025 21:54:43 -0300
Subject: [PATCH 5/8] 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 d5cc2b73f3..a88a6167dd 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -50,9 +50,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 c9f97fcabfbc6a7f7e9d311df6d6171c8559587c Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 22 Dec 2025 21:56:09 -0300
Subject: [PATCH 6/8] 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 a88a6167dd..97c1dfc5b7 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -134,8 +134,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);
@@ -143,8 +145,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;
}
@@ -162,8 +166,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 8a825fe4155fde5348a5b74ad4559c7160bf165a Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Wed, 7 Jan 2026 12:16:27 -0300
Subject: [PATCH 7/8] 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 97c1dfc5b7..010a7bc791 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -110,6 +110,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;
@@ -129,13 +130,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;
}
@@ -171,17 +186,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;
@@ -192,18 +206,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;
@@ -211,6 +220,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;
@@ -219,6 +231,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)
@@ -235,8 +259,11 @@ static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
static void lcevc_free(AVRefStructOpaque 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));
}
@@ -285,7 +312,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 0592be14ff099604ec2235e05f4b6b0c3b92c7cf Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Sat, 10 Jan 2026 15:48:46 -0300
Subject: [PATCH 8/8] 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 74875e1b84..203b7e2ab9 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-11 23:42 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=176817492301.25.2086506522879281262@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