You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
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@gmail.com>
This commit is contained in:
@ -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;
|
AVCodecInternal *avci = avctx->internal;
|
||||||
DecodeContext *dc = decode_ctx(avci);
|
DecodeContext *dc = decode_ctx(avci);
|
||||||
|
|
||||||
if (dc->lcevc_frame) {
|
if (dc->lcevc_frame) {
|
||||||
FrameDecodeData *fdd = frame->private_ref;
|
FrameDecodeData *fdd = frame->private_ref;
|
||||||
|
FFLCEVCFrame *frame_ctx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
fdd->post_process_opaque = av_refstruct_ref(dc->lcevc);
|
frame_ctx = av_mallocz(sizeof(*frame_ctx));
|
||||||
fdd->post_process_opaque_free = ff_lcevc_unref;
|
if (!frame_ctx)
|
||||||
fdd->post_process = ff_lcevc_process;
|
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->width = dc->width;
|
||||||
frame->height = dc->height;
|
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;
|
dc->lcevc_frame = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
|
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)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
attach_post_process_data(avctx, frame);
|
ret = attach_post_process_data(avctx, frame);
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
|
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
|
||||||
|
@ -47,7 +47,7 @@ static LCEVC_ColorFormat map_format(int format)
|
|||||||
return LCEVC_ColorFormat_Unknown;
|
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)
|
const AVFrame *frame, LCEVC_PictureHandle *picture)
|
||||||
{
|
{
|
||||||
LCEVC_PictureDesc desc;
|
LCEVC_PictureDesc desc;
|
||||||
@ -70,22 +70,22 @@ static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
|
|||||||
desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den;
|
desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den;
|
||||||
|
|
||||||
/* Allocate LCEVC Picture */
|
/* Allocate LCEVC Picture */
|
||||||
res = LCEVC_AllocPicture(decoder, &desc, picture);
|
res = LCEVC_AllocPicture(lcevc->decoder, &desc, picture);
|
||||||
if (res != LCEVC_Success) {
|
if (res != LCEVC_Success) {
|
||||||
return AVERROR_EXTERNAL;
|
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)
|
if (res != LCEVC_Success)
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
|
|
||||||
res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes);
|
res = LCEVC_GetPicturePlaneCount(lcevc->decoder, *picture, &planes);
|
||||||
if (res != LCEVC_Success)
|
if (res != LCEVC_Success)
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
|
|
||||||
for (unsigned i = 0; i < planes; i++) {
|
for (unsigned i = 0; i < planes; i++) {
|
||||||
LCEVC_PicturePlaneDesc plane;
|
LCEVC_PicturePlaneDesc plane;
|
||||||
|
|
||||||
res = LCEVC_GetPictureLockPlaneDesc(decoder, lock, i, &plane);
|
res = LCEVC_GetPictureLockPlaneDesc(lcevc->decoder, lock, i, &plane);
|
||||||
if (res != LCEVC_Success)
|
if (res != LCEVC_Success)
|
||||||
return AVERROR_EXTERNAL;
|
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,
|
av_image_copy2(data, linesizes, frame->data, frame->linesize,
|
||||||
frame->format, frame->width, frame->height);
|
frame->format, frame->width, frame->height);
|
||||||
|
|
||||||
res = LCEVC_UnlockPicture(decoder, lock);
|
res = LCEVC_UnlockPicture(lcevc->decoder, lock);
|
||||||
if (res != LCEVC_Success)
|
if (res != LCEVC_Success)
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder,
|
static int alloc_enhanced_frame(void *logctx, FFLCEVCFrame *frame_ctx,
|
||||||
const AVFrame *frame, LCEVC_PictureHandle *picture)
|
LCEVC_PictureHandle *picture)
|
||||||
{
|
{
|
||||||
|
FFLCEVCContext *lcevc = frame_ctx->lcevc;
|
||||||
LCEVC_PictureDesc desc ;
|
LCEVC_PictureDesc desc ;
|
||||||
LCEVC_ColorFormat fmt = map_format(frame->format);
|
LCEVC_ColorFormat fmt = map_format(frame_ctx->frame->format);
|
||||||
LCEVC_PicturePlaneDesc planes[4] = { 0 };
|
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;
|
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)
|
if (res != LCEVC_Success)
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
|
|
||||||
/* Set plane description */
|
/* Set plane description */
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
planes[i].firstSample = frame->data[i];
|
planes[i].firstSample = frame_ctx->frame->data[i];
|
||||||
planes[i].rowByteStride = frame->linesize[i];
|
planes[i].rowByteStride = frame_ctx->frame->linesize[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate LCEVC Picture */
|
/* Allocate LCEVC Picture */
|
||||||
res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture);
|
res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture);
|
||||||
if (res != LCEVC_Success) {
|
if (res != LCEVC_Success) {
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
|
||||||
LCEVC_PictureHandle picture;
|
LCEVC_PictureHandle picture;
|
||||||
LCEVC_ReturnCode res;
|
LCEVC_ReturnCode res;
|
||||||
@ -145,7 +145,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
|
|||||||
if (res != LCEVC_Success)
|
if (res != LCEVC_Success)
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
|
|
||||||
ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture);
|
ret = alloc_base_frame(logctx, lcevc, in, &picture);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
|
|||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
|
|
||||||
memset(&picture, 0, sizeof(picture));
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -165,8 +165,9 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *
|
|||||||
return 0;
|
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_PictureDesc desc;
|
||||||
LCEVC_DecodeInformation info;
|
LCEVC_DecodeInformation info;
|
||||||
LCEVC_PictureHandle picture;
|
LCEVC_PictureHandle picture;
|
||||||
@ -186,6 +187,11 @@ static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
|
|||||||
out->crop_right = desc.cropRight;
|
out->crop_right = desc.cropRight;
|
||||||
out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
|
out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
|
||||||
out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
|
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->width = desc.width + out->crop_left + out->crop_right;
|
||||||
out->height = desc.height + out->crop_top + out->crop_bottom;
|
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;
|
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_PictureHandle picture;
|
||||||
LCEVC_ReturnCode res;
|
LCEVC_ReturnCode res;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = generate_output(logctx, lcevc, out);
|
ret = generate_output(logctx, frame_ctx, out);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -249,12 +256,7 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
|
|||||||
#if CONFIG_LIBLCEVC_DEC
|
#if CONFIG_LIBLCEVC_DEC
|
||||||
LCEVC_AccelContextHandle dummy = { 0 };
|
LCEVC_AccelContextHandle dummy = { 0 };
|
||||||
const int32_t event = LCEVC_Log;
|
const int32_t event = LCEVC_Log;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (lcevc->initialized)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
#if CONFIG_LIBLCEVC_DEC
|
|
||||||
if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
|
if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
|
||||||
av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
|
av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
@ -279,7 +281,8 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
|
|||||||
int ff_lcevc_process(void *logctx, AVFrame *frame)
|
int ff_lcevc_process(void *logctx, AVFrame *frame)
|
||||||
{
|
{
|
||||||
FrameDecodeData *fdd = frame->private_ref;
|
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;
|
int ret;
|
||||||
|
|
||||||
if (!lcevc->initialized) {
|
if (!lcevc->initialized) {
|
||||||
@ -289,11 +292,14 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_LIBLCEVC_DEC
|
#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)
|
if (ret)
|
||||||
return ret < 0 ? ret : 0;
|
return ret < 0 ? ret : 0;
|
||||||
|
|
||||||
lcevc_receive_frame(logctx, lcevc, frame);
|
lcevc_receive_frame(logctx, frame_ctx, frame);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -317,5 +323,8 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc)
|
|||||||
|
|
||||||
void ff_lcevc_unref(void *opaque)
|
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);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,11 @@ typedef struct FFLCEVCContext {
|
|||||||
|
|
||||||
struct AVFrame;
|
struct AVFrame;
|
||||||
|
|
||||||
|
typedef struct FFLCEVCFrame {
|
||||||
|
FFLCEVCContext *lcevc;
|
||||||
|
struct AVFrame *frame;
|
||||||
|
} FFLCEVCFrame;
|
||||||
|
|
||||||
int ff_lcevc_alloc(FFLCEVCContext **plcevc);
|
int ff_lcevc_alloc(FFLCEVCContext **plcevc);
|
||||||
int ff_lcevc_process(void *logctx, struct AVFrame *frame);
|
int ff_lcevc_process(void *logctx, struct AVFrame *frame);
|
||||||
void ff_lcevc_unref(void *opaque);
|
void ff_lcevc_unref(void *opaque);
|
||||||
|
Reference in New Issue
Block a user