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 <jamr...@gmail.com>
---
 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 c2b2dd6e3b..ef09568381 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1590,22 +1590,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 = frame->private_ref;
+        FFLCEVCFrame *frame_ctx;
+        int ret;
 
-        fdd->post_process_opaque = av_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 = av_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)
@@ -1666,7 +1693,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 2fe06b8800..102f6f32e9 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -47,7 +47,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;
@@ -70,22 +70,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;
 
@@ -96,43 +96,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;
@@ -145,7 +145,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;
 
@@ -154,7 +154,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;
 
@@ -165,8 +165,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;
@@ -186,6 +187,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;
 
@@ -196,13 +202,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;
 
@@ -249,12 +256,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;
@@ -279,7 +281,8 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
 int ff_lcevc_process(void *logctx, AVFrame *frame)
 {
     FrameDecodeData  *fdd = frame->private_ref;
-    FFLCEVCContext *lcevc = fdd->post_process_opaque;
+    FFLCEVCFrame *frame_ctx = fdd->post_process_opaque;
+    FFLCEVCContext *lcevc = frame_ctx->lcevc;
     int ret;
 
     if (!lcevc->initialized) {
@@ -289,11 +292,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;
 
@@ -317,5 +323,8 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc)
 
 void ff_lcevc_unref(void *opaque)
 {
-    av_refstruct_unref(&opaque);
+    FFLCEVCFrame *lcevc = opaque;
+    av_refstruct_unref(&lcevc->lcevc);
+    av_frame_free(&lcevc->frame);
+    av_free(opaque);
 }
diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h
index b21d1073c4..62014132d9 100644
--- a/libavcodec/lcevcdec.h
+++ b/libavcodec/lcevcdec.h
@@ -35,6 +35,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);
-- 
2.49.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to