Currently in ff_thread_decode_frame, context is updated from child thread to main thread, and main thread releases the context in avcodec_close() when decode finishes.
However, when resolution/format change in vp9, ff_get_format was called, and hwaccel_uninit() and hwaccel_init will be used to destroy and re-create the context. Due to the async between main-thread and child-thread, main-thread updated its context from child earlier than the context was refreshed in child-thread. And it will lead to: 1. memory leak in child-thread. 2. double free in main-thread while calling avcodec_close(). Can be reproduced with a resolution change case in vp9, and use -vframes to terminate the decode between the dynamic resolution change frames: ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -v verbose -i ./test2360_1672_4980.ivf -pix_fmt p010le -f rawvideo -vsync passthrough -vframes 6 -y out.yuv Move update_context_from_thread from ff_thread_decode_frame(main thread) to frame_worker_thread(child thread), update the context in child thread right after the context was updated to avoid the async issue. Signed-off-by: Linjie Fu <linjie...@intel.com> --- Request for Comments, not quite familiar with the constraints. Thanks in advance. libavcodec/internal.h | 5 +++++ libavcodec/pthread_frame.c | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 5096ffa..9f4ed0b 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -162,6 +162,11 @@ typedef struct AVCodecInternal { void *thread_ctx; + /** + * Main thread AVCodecContext pointer + */ + void *main_thread; + DecodeSimpleContext ds; DecodeFilterContext filter; diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 36ac0ac..2730a8c 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -140,6 +140,8 @@ typedef struct FrameThreadContext { #define THREAD_SAFE_CALLBACKS(avctx) \ ((avctx)->thread_safe_callbacks || (avctx)->get_buffer2 == avcodec_default_get_buffer2) +static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, int for_user); + static void async_lock(FrameThreadContext *fctx) { pthread_mutex_lock(&fctx->async_mutex); @@ -157,7 +159,6 @@ static void async_unlock(FrameThreadContext *fctx) pthread_cond_broadcast(&fctx->async_cond); pthread_mutex_unlock(&fctx->async_mutex); } - /** * Codec worker thread. * @@ -200,6 +201,10 @@ static attribute_align_arg void *frame_worker_thread(void *arg) p->got_frame = 0; p->result = codec->decode(avctx, p->frame, &p->got_frame, &p->avpkt); + if (p->avctx->internal->main_thread) + update_context_from_thread((AVCodecContext *)p->avctx->internal->main_thread, + p->avctx, 1); + if ((p->result < 0 || !p->got_frame) && p->frame->buf[0]) { if (avctx->internal->allocate_progress) av_log(avctx, AV_LOG_ERROR, "A frame threaded decoder did not " @@ -540,8 +545,6 @@ int ff_thread_decode_frame(AVCodecContext *avctx, if (finished >= avctx->thread_count) finished = 0; } while (!avpkt->size && !*got_picture_ptr && err >= 0 && finished != fctx->next_finished); - update_context_from_thread(avctx, p->avctx, 1); - if (fctx->next_decoding >= avctx->thread_count) fctx->next_decoding = 0; fctx->next_finished = finished; @@ -728,6 +731,8 @@ int ff_frame_thread_init(AVCodecContext *avctx) FrameThreadContext *fctx; int i, err = 0; + avctx->internal->main_thread = avctx; + if (!thread_count) { int nb_cpus = av_cpu_count(); #if FF_API_DEBUG_MV @@ -800,6 +805,7 @@ int ff_frame_thread_init(AVCodecContext *avctx) *copy->internal = *src->internal; copy->internal->thread_ctx = p; copy->internal->last_pkt_props = &p->avpkt; + copy->internal->main_thread = avctx; if (!i) { src = copy; -- 2.7.4 _______________________________________________ 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".