[FFmpeg-cvslog] avcodec/lcevcdec: don't try to write to output frames directly
James Almer
git at videolan.org
Fri May 23 03:44:16 EEST 2025
ffmpeg | branch: release/7.1 | James Almer <jamrial at gmail.com> | Fri May 16 16:54:52 2025 -0300| [4c78a357d082b1097c4269dd1af116bb01ddc83e] | committer: James Almer
avcodec/lcevcdec: don't try to write to output frames directly
The buffer references may not be writable at this point, as the decoder
calls get_buffer2() with the AV_GET_BUFFER_FLAG_REF flag.
Fixes races as reported by tsan, producing correct output regardless of
threading choices.
Signed-off-by: James Almer <jamrial at gmail.com>
(cherry picked from commit 8eae65dc5c8960c9770017737d968eca2aa7f502)
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=4c78a357d082b1097c4269dd1af116bb01ddc83e
---
libavcodec/decode.c | 39 +++++++++++++++++++++++++----
libavcodec/lcevcdec.c | 69 +++++++++++++++++++++++++++++----------------------
libavcodec/lcevcdec.h | 5 ++++
3 files changed, 78 insertions(+), 35 deletions(-)
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 148af71ac4..828013197c 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1671,22 +1671,49 @@ static void update_frame_props(AVCodecContext *avctx, AVFrame *frame)
}
}
-static void attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
+static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
{
AVCodecInternal *avci = avctx->internal;
DecodeContext *dc = decode_ctx(avci);
if (dc->lcevc_frame) {
FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
+ FFLCEVCFrame *frame_ctx;
+ int ret;
- fdd->post_process_opaque = ff_refstruct_ref(dc->lcevc);
- fdd->post_process_opaque_free = ff_lcevc_unref;
- fdd->post_process = ff_lcevc_process;
+ frame_ctx = av_mallocz(sizeof(*frame_ctx));
+ 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 = ff_refstruct_ref(dc->lcevc);
+ 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;
+
+ ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0);
+ if (ret < 0) {
+ ff_lcevc_unref(frame_ctx);
+ return ret;
+ }
+
+ 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;
+
+ return 0;
}
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
@@ -1747,7 +1774,9 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
if (ret < 0)
goto fail;
- attach_post_process_data(avctx, frame);
+ ret = attach_post_process_data(avctx, frame);
+ if (ret < 0)
+ goto fail;
end:
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index ceeece3aa9..601e97b3a1 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -45,7 +45,7 @@ static LCEVC_ColorFormat map_format(int format)
return LCEVC_ColorFormat_Unknown;
}
-static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
+static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
const AVFrame *frame, LCEVC_PictureHandle *picture)
{
LCEVC_PictureDesc desc;
@@ -68,22 +68,22 @@ static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den;
/* Allocate LCEVC Picture */
- res = LCEVC_AllocPicture(decoder, &desc, picture);
+ res = LCEVC_AllocPicture(lcevc->decoder, &desc, picture);
if (res != LCEVC_Success) {
return AVERROR_EXTERNAL;
}
- res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock);
+ res = LCEVC_LockPicture(lcevc->decoder, *picture, LCEVC_Access_Write, &lock);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
- res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes);
+ 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(decoder, lock, i, &plane);
+ res = LCEVC_GetPictureLockPlaneDesc(lcevc->decoder, lock, i, &plane);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
@@ -94,43 +94,43 @@ static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
av_image_copy2(data, linesizes, frame->data, frame->linesize,
frame->format, frame->width, frame->height);
- res = LCEVC_UnlockPicture(decoder, lock);
+ res = LCEVC_UnlockPicture(lcevc->decoder, lock);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
return 0;
}
-static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder,
- const AVFrame *frame, LCEVC_PictureHandle *picture)
+static int alloc_enhanced_frame(void *logctx, FFLCEVCFrame *frame_ctx,
+ LCEVC_PictureHandle *picture)
{
+ FFLCEVCContext *lcevc = frame_ctx->lcevc;
LCEVC_PictureDesc desc ;
- LCEVC_ColorFormat fmt = map_format(frame->format);
+ LCEVC_ColorFormat fmt = map_format(frame_ctx->frame->format);
LCEVC_PicturePlaneDesc planes[4] = { 0 };
- int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
- int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
LCEVC_ReturnCode res;
- res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
+ res = LCEVC_DefaultPictureDesc(&desc, fmt, frame_ctx->frame->width, frame_ctx->frame->height);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
/* Set plane description */
for (int i = 0; i < 4; i++) {
- planes[i].firstSample = frame->data[i];
- planes[i].rowByteStride = frame->linesize[i];
+ planes[i].firstSample = frame_ctx->frame->data[i];
+ planes[i].rowByteStride = frame_ctx->frame->linesize[i];
}
/* Allocate LCEVC Picture */
- res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture);
+ res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture);
if (res != LCEVC_Success) {
return AVERROR_EXTERNAL;
}
return 0;
}
-static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in)
+static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame *in)
{
+ FFLCEVCContext *lcevc = frame_ctx->lcevc;
const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
LCEVC_PictureHandle picture;
LCEVC_ReturnCode res;
@@ -143,7 +143,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
- ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture);
+ ret = alloc_base_frame(logctx, lcevc, in, &picture);
if (ret < 0)
return ret;
@@ -152,7 +152,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
return AVERROR_EXTERNAL;
memset(&picture, 0, sizeof(picture));
- ret = alloc_enhanced_frame(logctx, lcevc->decoder, in, &picture);
+ ret = alloc_enhanced_frame(logctx, frame_ctx, &picture);
if (ret < 0)
return ret;
@@ -163,8 +163,9 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
return 0;
}
-static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
+static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
{
+ FFLCEVCContext *lcevc = frame_ctx->lcevc;
LCEVC_PictureDesc desc;
LCEVC_DecodeInformation info;
LCEVC_PictureHandle picture;
@@ -184,6 +185,11 @@ static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
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;
@@ -194,13 +200,14 @@ static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
return 0;
}
-static int lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
+static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
{
+ FFLCEVCContext *lcevc = frame_ctx->lcevc;
LCEVC_PictureHandle picture;
LCEVC_ReturnCode res;
int ret;
- ret = generate_output(logctx, lcevc, out);
+ ret = generate_output(logctx, frame_ctx, out);
if (ret < 0)
return ret;
@@ -247,12 +254,7 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
#if CONFIG_LIBLCEVC_DEC
LCEVC_AccelContextHandle dummy = { 0 };
const int32_t event = LCEVC_Log;
-#endif
- if (lcevc->initialized)
- return 0;
-
-#if CONFIG_LIBLCEVC_DEC
if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
return AVERROR_EXTERNAL;
@@ -277,7 +279,8 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
int ff_lcevc_process(void *logctx, AVFrame *frame)
{
FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
- FFLCEVCContext *lcevc = fdd->post_process_opaque;
+ FFLCEVCFrame *frame_ctx = fdd->post_process_opaque;
+ FFLCEVCContext *lcevc = frame_ctx->lcevc;
int ret;
if (!lcevc->initialized) {
@@ -287,11 +290,14 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
}
#if CONFIG_LIBLCEVC_DEC
- ret = lcevc_send_frame(logctx, lcevc, frame);
+ av_assert0(frame_ctx->frame);
+
+
+ ret = lcevc_send_frame(logctx, frame_ctx, frame);
if (ret)
return ret < 0 ? ret : 0;
- lcevc_receive_frame(logctx, lcevc, frame);
+ lcevc_receive_frame(logctx, frame_ctx, frame);
if (ret < 0)
return ret;
@@ -315,5 +321,8 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc)
void ff_lcevc_unref(void *opaque)
{
- ff_refstruct_unref(&opaque);
+ FFLCEVCFrame *lcevc = opaque;
+ ff_refstruct_unref(&lcevc->lcevc);
+ av_frame_free(&lcevc->frame);
+ av_free(opaque);
}
diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h
index 7334d3a645..f0d17c0412 100644
--- a/libavcodec/lcevcdec.h
+++ b/libavcodec/lcevcdec.h
@@ -36,6 +36,11 @@ typedef struct FFLCEVCContext {
struct AVFrame;
+typedef struct FFLCEVCFrame {
+ FFLCEVCContext *lcevc;
+ struct AVFrame *frame;
+} FFLCEVCFrame;
+
int ff_lcevc_alloc(FFLCEVCContext **plcevc);
int ff_lcevc_process(void *logctx, struct AVFrame *frame);
void ff_lcevc_unref(void *opaque);
More information about the ffmpeg-cvslog
mailing list