[vlc-commits] [Git][videolan/vlc][master] avcodec: vaapi: use a sem to pace frames allocation

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Sat Nov 20 19:19:44 UTC 2021



Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC


Commits:
f5b6d9d3 by Thomas Guillem at 2021-11-20T18:51:27+00:00
avcodec: vaapi: use a sem to pace frames allocation

Recover the hw pool size from the first Get() call (after the
AVCodecContext has been initialized) and use a semaphore to pace the
picture allocation from Get().

That way, we don't rely anymore av_hwframe_get_buffer() return values,
that returned the same error for internal error or when the pool was
full.

Fixes #26166

- - - - -


1 changed file:

- modules/codec/avcodec/vaapi.c


Changes:

=====================================
modules/codec/avcodec/vaapi.c
=====================================
@@ -54,8 +54,8 @@ struct vaapi_vctx
 {
     VADisplay va_dpy;
     AVBufferRef *hwdev_ref;
-    vlc_mutex_t lock;
-    vlc_cond_t wait;
+    bool pool_sem_init;
+    vlc_sem_t pool_sem;
 };
 
 static int GetVaProfile(const AVCodecContext *ctx, const es_format_t *fmt_in,
@@ -129,16 +129,22 @@ static int GetVaProfile(const AVCodecContext *ctx, const es_format_t *fmt_in,
 typedef struct {
     struct vaapi_pic_context ctx;
     AVFrame *avframe;
+    bool cloned;
 } vaapi_dec_pic_context;
 
 static void vaapi_dec_pic_context_destroy(picture_context_t *context)
 {
     vaapi_dec_pic_context *pic_ctx = container_of(context, vaapi_dec_pic_context, ctx.s);
-    av_frame_free(&pic_ctx->avframe);
 
     struct vaapi_vctx *vaapi_vctx =
         vlc_video_context_GetPrivate(pic_ctx->ctx.s.vctx, VLC_VIDEO_CONTEXT_VAAPI);
-    vlc_cond_signal(&vaapi_vctx->wait);
+
+    assert(vaapi_vctx->pool_sem_init);
+
+    av_frame_free(&pic_ctx->avframe);
+
+    if (!pic_ctx->cloned)
+        vlc_sem_post(&vaapi_vctx->pool_sem);
 
     free(pic_ctx);
 }
@@ -158,6 +164,7 @@ static picture_context_t *vaapi_dec_pic_context_copy(picture_context_t *src)
         free(pic_ctx);
         return NULL;
     }
+    pic_ctx->cloned = true;
 
     vlc_video_context_Hold(pic_ctx->ctx.s.vctx);
     return &pic_ctx->ctx.s;
@@ -166,26 +173,42 @@ static picture_context_t *vaapi_dec_pic_context_copy(picture_context_t *src)
 static int Get(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx, AVFrame *frame)
 {
     vlc_video_context *vctx = va->sys;
+    AVHWFramesContext *hwframes = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
     struct vaapi_vctx *vaapi_vctx =
         vlc_video_context_GetPrivate(vctx, VLC_VIDEO_CONTEXT_VAAPI);
 
     assert(ctx->hw_frames_ctx);
 
-    int ret;
-    vlc_mutex_lock(&vaapi_vctx->lock);
-    while ((ret = av_hwframe_get_buffer(ctx->hw_frames_ctx, frame, 0)) == AVERROR(ENOMEM))
-        vlc_cond_wait(&vaapi_vctx->wait, &vaapi_vctx->lock);
-    vlc_mutex_unlock(&vaapi_vctx->lock);
+    /* The pool size can only be known after the hw context has been
+     * initialized (internally by ffmpeg), so between Create() and the first
+     * Get() */
+    if (!vaapi_vctx->pool_sem_init)
+    {
+        vlc_sem_init(&vaapi_vctx->pool_sem,
+                     hwframes->initial_pool_size +
+                     ctx->thread_count +
+                     3 /* cf. ff_decode_get_hw_frames_ctx */);
+        vaapi_vctx->pool_sem_init = true;
+    }
+
+    /* If all frames are out, wait for a frame to be released. */
+    vlc_sem_wait(&vaapi_vctx->pool_sem);
 
+    int ret = av_hwframe_get_buffer(ctx->hw_frames_ctx, frame, 0);
     if (ret)
     {
         msg_Err(va, "vaapi_va: av_hwframe_get_buffer failed: %d\n", ret);
+        vlc_sem_post(&vaapi_vctx->pool_sem);
         return ret;
     }
 
     vaapi_dec_pic_context *vaapi_pic_ctx = malloc(sizeof(*vaapi_pic_ctx));
     if (unlikely(vaapi_pic_ctx == NULL))
+    {
+        vlc_sem_post(&vaapi_vctx->pool_sem);
         return VLC_ENOMEM;
+    }
+
     vaapi_pic_ctx->ctx.s = (picture_context_t) {
         vaapi_dec_pic_context_destroy, vaapi_dec_pic_context_copy, vctx,
     };
@@ -193,6 +216,7 @@ static int Get(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx, AVFrame *frame
     vaapi_pic_ctx->ctx.surface = (uintptr_t) frame->data[3];
     vaapi_pic_ctx->ctx.va_dpy = vaapi_vctx->va_dpy;
     vaapi_pic_ctx->avframe = av_frame_clone(frame);
+    vaapi_pic_ctx->cloned = false;
     vlc_vaapi_PicSetContext(pic, &vaapi_pic_ctx->ctx);
 
     return VLC_SUCCESS;
@@ -257,8 +281,7 @@ static int Create(vlc_va_t *va, AVCodecContext *ctx, enum AVPixelFormat hwfmt,
 
     vaapi_vctx->va_dpy = va_dpy;
     vaapi_vctx->hwdev_ref = hwdev_ref;
-    vlc_mutex_init(&vaapi_vctx->lock);
-    vlc_cond_init(&vaapi_vctx->wait);
+    vaapi_vctx->pool_sem_init = false;
 
     msg_Info(va, "Using %s", vaQueryVendorString(va_dpy));
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/f5b6d9d3467373af2338c37d046f945cedae4be1

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/f5b6d9d3467373af2338c37d046f945cedae4be1
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list