Skip to content

Commit 8eae65d

Browse files
committed
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 <[email protected]>
1 parent d028cf0 commit 8eae65d

File tree

3 files changed

+78
-35
lines changed

3 files changed

+78
-35
lines changed

libavcodec/decode.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,22 +1590,49 @@ static void update_frame_props(AVCodecContext *avctx, AVFrame *frame)
15901590
}
15911591
}
15921592

1593-
static void attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
1593+
static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
15941594
{
15951595
AVCodecInternal *avci = avctx->internal;
15961596
DecodeContext *dc = decode_ctx(avci);
15971597

15981598
if (dc->lcevc_frame) {
15991599
FrameDecodeData *fdd = frame->private_ref;
1600+
FFLCEVCFrame *frame_ctx;
1601+
int ret;
16001602

1601-
fdd->post_process_opaque = av_refstruct_ref(dc->lcevc);
1602-
fdd->post_process_opaque_free = ff_lcevc_unref;
1603-
fdd->post_process = ff_lcevc_process;
1603+
frame_ctx = av_mallocz(sizeof(*frame_ctx));
1604+
if (!frame_ctx)
1605+
return AVERROR(ENOMEM);
1606+
1607+
frame_ctx->frame = av_frame_alloc();
1608+
if (!frame_ctx->frame) {
1609+
av_free(frame_ctx);
1610+
return AVERROR(ENOMEM);
1611+
}
1612+
1613+
frame_ctx->lcevc = av_refstruct_ref(dc->lcevc);
1614+
frame_ctx->frame->width = frame->width;
1615+
frame_ctx->frame->height = frame->height;
1616+
frame_ctx->frame->format = frame->format;
16041617

16051618
frame->width = dc->width;
16061619
frame->height = dc->height;
1620+
1621+
ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0);
1622+
if (ret < 0) {
1623+
ff_lcevc_unref(frame_ctx);
1624+
return ret;
1625+
}
1626+
1627+
validate_avframe_allocation(avctx, frame_ctx->frame);
1628+
1629+
fdd->post_process_opaque = frame_ctx;
1630+
fdd->post_process_opaque_free = ff_lcevc_unref;
1631+
fdd->post_process = ff_lcevc_process;
16071632
}
16081633
dc->lcevc_frame = 0;
1634+
1635+
return 0;
16091636
}
16101637

16111638
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
@@ -1666,7 +1693,9 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
16661693
if (ret < 0)
16671694
goto fail;
16681695

1669-
attach_post_process_data(avctx, frame);
1696+
ret = attach_post_process_data(avctx, frame);
1697+
if (ret < 0)
1698+
goto fail;
16701699

16711700
end:
16721701
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&

libavcodec/lcevcdec.c

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static LCEVC_ColorFormat map_format(int format)
4747
return LCEVC_ColorFormat_Unknown;
4848
}
4949

50-
static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
50+
static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
5151
const AVFrame *frame, LCEVC_PictureHandle *picture)
5252
{
5353
LCEVC_PictureDesc desc;
@@ -70,22 +70,22 @@ static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
7070
desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den;
7171

7272
/* Allocate LCEVC Picture */
73-
res = LCEVC_AllocPicture(decoder, &desc, picture);
73+
res = LCEVC_AllocPicture(lcevc->decoder, &desc, picture);
7474
if (res != LCEVC_Success) {
7575
return AVERROR_EXTERNAL;
7676
}
77-
res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock);
77+
res = LCEVC_LockPicture(lcevc->decoder, *picture, LCEVC_Access_Write, &lock);
7878
if (res != LCEVC_Success)
7979
return AVERROR_EXTERNAL;
8080

81-
res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes);
81+
res = LCEVC_GetPicturePlaneCount(lcevc->decoder, *picture, &planes);
8282
if (res != LCEVC_Success)
8383
return AVERROR_EXTERNAL;
8484

8585
for (unsigned i = 0; i < planes; i++) {
8686
LCEVC_PicturePlaneDesc plane;
8787

88-
res = LCEVC_GetPictureLockPlaneDesc(decoder, lock, i, &plane);
88+
res = LCEVC_GetPictureLockPlaneDesc(lcevc->decoder, lock, i, &plane);
8989
if (res != LCEVC_Success)
9090
return AVERROR_EXTERNAL;
9191

@@ -96,43 +96,43 @@ static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
9696
av_image_copy2(data, linesizes, frame->data, frame->linesize,
9797
frame->format, frame->width, frame->height);
9898

99-
res = LCEVC_UnlockPicture(decoder, lock);
99+
res = LCEVC_UnlockPicture(lcevc->decoder, lock);
100100
if (res != LCEVC_Success)
101101
return AVERROR_EXTERNAL;
102102

103103
return 0;
104104
}
105105

106-
static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder,
107-
const AVFrame *frame, LCEVC_PictureHandle *picture)
106+
static int alloc_enhanced_frame(void *logctx, FFLCEVCFrame *frame_ctx,
107+
LCEVC_PictureHandle *picture)
108108
{
109+
FFLCEVCContext *lcevc = frame_ctx->lcevc;
109110
LCEVC_PictureDesc desc ;
110-
LCEVC_ColorFormat fmt = map_format(frame->format);
111+
LCEVC_ColorFormat fmt = map_format(frame_ctx->frame->format);
111112
LCEVC_PicturePlaneDesc planes[4] = { 0 };
112-
int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
113-
int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
114113
LCEVC_ReturnCode res;
115114

116-
res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
115+
res = LCEVC_DefaultPictureDesc(&desc, fmt, frame_ctx->frame->width, frame_ctx->frame->height);
117116
if (res != LCEVC_Success)
118117
return AVERROR_EXTERNAL;
119118

120119
/* Set plane description */
121120
for (int i = 0; i < 4; i++) {
122-
planes[i].firstSample = frame->data[i];
123-
planes[i].rowByteStride = frame->linesize[i];
121+
planes[i].firstSample = frame_ctx->frame->data[i];
122+
planes[i].rowByteStride = frame_ctx->frame->linesize[i];
124123
}
125124

126125
/* Allocate LCEVC Picture */
127-
res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture);
126+
res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture);
128127
if (res != LCEVC_Success) {
129128
return AVERROR_EXTERNAL;
130129
}
131130
return 0;
132131
}
133132

134-
static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in)
133+
static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame *in)
135134
{
135+
FFLCEVCContext *lcevc = frame_ctx->lcevc;
136136
const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
137137
LCEVC_PictureHandle picture;
138138
LCEVC_ReturnCode res;
@@ -145,7 +145,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
145145
if (res != LCEVC_Success)
146146
return AVERROR_EXTERNAL;
147147

148-
ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture);
148+
ret = alloc_base_frame(logctx, lcevc, in, &picture);
149149
if (ret < 0)
150150
return ret;
151151

@@ -154,7 +154,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
154154
return AVERROR_EXTERNAL;
155155

156156
memset(&picture, 0, sizeof(picture));
157-
ret = alloc_enhanced_frame(logctx, lcevc->decoder, in, &picture);
157+
ret = alloc_enhanced_frame(logctx, frame_ctx, &picture);
158158
if (ret < 0)
159159
return ret;
160160

@@ -165,8 +165,9 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
165165
return 0;
166166
}
167167

168-
static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
168+
static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
169169
{
170+
FFLCEVCContext *lcevc = frame_ctx->lcevc;
170171
LCEVC_PictureDesc desc;
171172
LCEVC_DecodeInformation info;
172173
LCEVC_PictureHandle picture;
@@ -186,6 +187,11 @@ static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
186187
out->crop_right = desc.cropRight;
187188
out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
188189
out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
190+
191+
av_frame_copy_props(frame_ctx->frame, out);
192+
av_frame_unref(out);
193+
av_frame_move_ref(out, frame_ctx->frame);
194+
189195
out->width = desc.width + out->crop_left + out->crop_right;
190196
out->height = desc.height + out->crop_top + out->crop_bottom;
191197

@@ -196,13 +202,14 @@ static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
196202
return 0;
197203
}
198204

199-
static int lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
205+
static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
200206
{
207+
FFLCEVCContext *lcevc = frame_ctx->lcevc;
201208
LCEVC_PictureHandle picture;
202209
LCEVC_ReturnCode res;
203210
int ret;
204211

205-
ret = generate_output(logctx, lcevc, out);
212+
ret = generate_output(logctx, frame_ctx, out);
206213
if (ret < 0)
207214
return ret;
208215

@@ -249,12 +256,7 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
249256
#if CONFIG_LIBLCEVC_DEC
250257
LCEVC_AccelContextHandle dummy = { 0 };
251258
const int32_t event = LCEVC_Log;
252-
#endif
253259

254-
if (lcevc->initialized)
255-
return 0;
256-
257-
#if CONFIG_LIBLCEVC_DEC
258260
if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
259261
av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
260262
return AVERROR_EXTERNAL;
@@ -279,7 +281,8 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
279281
int ff_lcevc_process(void *logctx, AVFrame *frame)
280282
{
281283
FrameDecodeData *fdd = frame->private_ref;
282-
FFLCEVCContext *lcevc = fdd->post_process_opaque;
284+
FFLCEVCFrame *frame_ctx = fdd->post_process_opaque;
285+
FFLCEVCContext *lcevc = frame_ctx->lcevc;
283286
int ret;
284287

285288
if (!lcevc->initialized) {
@@ -289,11 +292,14 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
289292
}
290293

291294
#if CONFIG_LIBLCEVC_DEC
292-
ret = lcevc_send_frame(logctx, lcevc, frame);
295+
av_assert0(frame_ctx->frame);
296+
297+
298+
ret = lcevc_send_frame(logctx, frame_ctx, frame);
293299
if (ret)
294300
return ret < 0 ? ret : 0;
295301

296-
lcevc_receive_frame(logctx, lcevc, frame);
302+
lcevc_receive_frame(logctx, frame_ctx, frame);
297303
if (ret < 0)
298304
return ret;
299305

@@ -317,5 +323,8 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc)
317323

318324
void ff_lcevc_unref(void *opaque)
319325
{
320-
av_refstruct_unref(&opaque);
326+
FFLCEVCFrame *lcevc = opaque;
327+
av_refstruct_unref(&lcevc->lcevc);
328+
av_frame_free(&lcevc->frame);
329+
av_free(opaque);
321330
}

libavcodec/lcevcdec.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ typedef struct FFLCEVCContext {
3535

3636
struct AVFrame;
3737

38+
typedef struct FFLCEVCFrame {
39+
FFLCEVCContext *lcevc;
40+
struct AVFrame *frame;
41+
} FFLCEVCFrame;
42+
3843
int ff_lcevc_alloc(FFLCEVCContext **plcevc);
3944
int ff_lcevc_process(void *logctx, struct AVFrame *frame);
4045
void ff_lcevc_unref(void *opaque);

0 commit comments

Comments
 (0)