[FFmpeg-devel] [PATCH] lavc/phtread_frame: update hwaccel_priv_data in time for multithread

Linjie Fu linjie.fu at intel.com
Fri Jul 19 00:35:28 EEST 2019


When resolution/format changes, hwaccel_uninit/hwaccel_init will
be called to destroy and re-create the hwaccel_priv_data. When output
frame number meets the constraints for vframes, the hwaccel_priv_data
modified in decoding thread won't be update to user-thread due to the
delay mechanism. It will lead to:
    1. memory leak in child-thread.
    2. double free in user-thread while calling avcodec_close().

Can be reproduced with a resolution change case, and use -vframes
to terminate the decode during dynamic resolution changing:

ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -v verbose
-i ./reinit-large_420_8-to-small_420_8.h264 -pix_fmt nv12 -f rawvideo
-vsync passthrough -vframes 45 -y out.yuv

The root cause is the conflict between delay mechanism and -vframes.
FFmpeg won't output a frame if it's still receiving the initial packets,
so there is async between decode process and output. hwaccel_priv_data
in user thread won't be updated until the resolution changing
frame is output.

As user context should reflect the state of the last frame that
was output to the user, hwaccel_priv_data should be updated
separately from decoding thread in time.

Signed-off-by: Linjie Fu <linjie.fu at intel.com>
---
 libavcodec/pthread_frame.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 36ac0ac..cf7a575 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -282,7 +282,6 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
         dst->sample_rate    = src->sample_rate;
         dst->sample_fmt     = src->sample_fmt;
         dst->channel_layout = src->channel_layout;
-        dst->internal->hwaccel_priv_data = src->internal->hwaccel_priv_data;
 
         if (!!dst->hw_frames_ctx != !!src->hw_frames_ctx ||
             (dst->hw_frames_ctx && dst->hw_frames_ctx->data != src->hw_frames_ctx->data)) {
@@ -410,6 +409,7 @@ static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx,
             pthread_mutex_unlock(&prev_thread->progress_mutex);
         }
 
+        p->avctx->internal->hwaccel_priv_data = prev_thread->avctx->internal->hwaccel_priv_data;
         err = update_context_from_thread(p->avctx, prev_thread->avctx, 0);
         if (err) {
             pthread_mutex_unlock(&p->mutex);
@@ -476,7 +476,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
     FrameThreadContext *fctx = avctx->internal->thread_ctx;
     int finished = fctx->next_finished;
     PerThreadContext *p;
-    int err;
+    int err, cur_decoding;
 
     /* release the async lock, permitting blocked hwaccel threads to
      * go forward while we are in this function */
@@ -544,6 +544,13 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
 
     if (fctx->next_decoding >= avctx->thread_count) fctx->next_decoding = 0;
 
+    /* update hwaccel_priv_data from decoding thread */
+    cur_decoding = fctx->next_decoding - 1;
+    if (cur_decoding < 0) cur_decoding += avctx->thread_count;
+
+    p = &fctx->threads[cur_decoding];
+    avctx->internal->hwaccel_priv_data = p->avctx->internal->hwaccel_priv_data;
+
     fctx->next_finished = finished;
 
     /* return the size of the consumed packet if no error occurred */
-- 
2.7.4



More information about the ffmpeg-devel mailing list