From 73f863d751df84db7a0ca1bd83cdff1b95dc94dd Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Mar 2017 19:52:07 -0400 Subject: [PATCH] fic: set pict_type/key_frame after (instead of during) slice decoding. This fixes a race condition that was already documented in the source code, and is also reported by tsan in fate-fic-avi. --- libavcodec/fic.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/libavcodec/fic.c b/libavcodec/fic.c index d3952a4c01..2bec3d7b03 100644 --- a/libavcodec/fic.c +++ b/libavcodec/fic.c @@ -34,6 +34,7 @@ typedef struct FICThreadContext { int slice_h; int src_size; int y_off; + int p_frame; } FICThreadContext; typedef struct FICContext { @@ -133,16 +134,13 @@ static void fic_idct_put(uint8_t *dst, int stride, int16_t *block) } } static int fic_decode_block(FICContext *ctx, GetBitContext *gb, - uint8_t *dst, int stride, int16_t *block) + uint8_t *dst, int stride, int16_t *block, int *is_p) { int i, num_coeff; /* Is it a skip block? */ if (get_bits1(gb)) { - /* This is a P-frame. */ - ctx->frame->key_frame = 0; - ctx->frame->pict_type = AV_PICTURE_TYPE_P; - + *is_p = 1; return 0; } @@ -182,7 +180,8 @@ static int fic_decode_slice(AVCodecContext *avctx, void *tdata) for (x = 0; x < (ctx->aligned_width >> !!p); x += 8) { int ret; - if ((ret = fic_decode_block(ctx, &gb, dst + x, stride, tctx->block)) != 0) + if ((ret = fic_decode_block(ctx, &gb, dst + x, stride, + tctx->block, &tctx->p_frame)) != 0) return ret; } @@ -348,15 +347,6 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, return AVERROR_INVALIDDATA; } - /* - * Set the frametype to I initially. It will be set to P if the frame - * has any dependencies (skip blocks). There will be a race condition - * inside the slice decode function to set these, but we do not care. - * since they will only ever be set to 0/P. - */ - ctx->frame->key_frame = 1; - ctx->frame->pict_type = AV_PICTURE_TYPE_I; - /* Allocate slice data. */ av_fast_malloc(&ctx->slice_data, &ctx->slice_data_size, nslices * sizeof(ctx->slice_data[0])); @@ -398,6 +388,15 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, NULL, nslices, sizeof(ctx->slice_data[0]))) < 0) return ret; + ctx->frame->key_frame = 1; + ctx->frame->pict_type = AV_PICTURE_TYPE_I; + for (slice = 0; slice < nslices; slice++) { + if (ctx->slice_data[slice].p_frame) { + ctx->frame->key_frame = 0; + ctx->frame->pict_type = AV_PICTURE_TYPE_P; + break; + } + } av_frame_free(&ctx->final_frame); ctx->final_frame = av_frame_clone(ctx->frame); if (!ctx->final_frame) {