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".