[FFmpeg-devel] [PATCH, RFC, v2] lavc/phtread_frame: update context in child thread in multi-thread mode
Linjie Fu
linjie.fu at intel.com
Wed Jun 26 23:24:52 EEST 2019
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.fu at 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
More information about the ffmpeg-devel
mailing list