---
Saves the VA config, the frame pool, and the VA context (in that order).  The 
device reference is held so that freeing the persistent data is possible (the 
transient context is already gone when it happens).


 libavcodec/vaapi_decode.c | 241 +++++++++++++++++++++++++++++++++-------------
 libavcodec/vaapi_decode.h |  18 ++++
 2 files changed, 192 insertions(+), 67 deletions(-)

diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index 847db1a42..52e9b5c3a 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -273,7 +273,8 @@ static const struct {
 
 static int vaapi_decode_make_config(AVCodecContext *avctx)
 {
-    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+    VAAPIDecodeContext   *ctx = avctx->internal->hwaccel_priv_data;
+    VAAPIDecodePersistent *pc = NULL;
 
     AVVAAPIHWConfig       *hwconfig    = NULL;
     AVHWFramesConstraints *constraints = NULL;
@@ -359,14 +360,28 @@ static int vaapi_decode_make_config(AVCodecContext *avctx)
     ctx->va_profile    = profile;
     ctx->va_entrypoint = VAEntrypointVLD;
 
-    vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile,
-                         ctx->va_entrypoint, NULL, 0,
-                         &ctx->va_config);
-    if (vas != VA_STATUS_SUCCESS) {
-        av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
-               "configuration: %d (%s).\n", vas, vaErrorStr(vas));
-        err = AVERROR(EIO);
-        goto fail;
+    if (avctx->internal->hwaccel_priv_persistent) {
+        pc = (VAAPIDecodePersistent*)
+            avctx->internal->hwaccel_priv_persistent->data;
+    }
+    if (pc && pc->va_profile == ctx->va_profile &&
+        pc->va_entrypoint == ctx->va_entrypoint) {
+        av_log(avctx, AV_LOG_DEBUG, "Reusing VA config %#x.\n",
+               pc->va_config);
+        ctx->va_config = pc->va_config;
+        pc->va_config  = VA_INVALID_ID;
+    } else {
+        av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
+
+        vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile,
+                             ctx->va_entrypoint, NULL, 0,
+                             &ctx->va_config);
+        if (vas != VA_STATUS_SUCCESS) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
+                   "configuration: %d (%s).\n", vas, vaErrorStr(vas));
+            err = AVERROR(EIO);
+            goto fail;
+        }
     }
 
     hwconfig = av_hwdevice_hwconfig_alloc(avctx->hw_device_ctx ?
@@ -467,9 +482,47 @@ fail:
     return err;
 }
 
+static void vaapi_decode_free_persistent(void *opaque, uint8_t *data)
+{
+    AVCodecContext     *avctx = opaque;
+    VAAPIDecodePersistent *pc = (VAAPIDecodePersistent*)data;
+    VAStatus vas;
+
+    if (pc->device_ref) {
+        AVHWDeviceContext *device =
+            (AVHWDeviceContext*)pc->device_ref->data;
+        AVVAAPIDeviceContext *hwctx = device->hwctx;
+
+        if (pc->va_context != VA_INVALID_ID) {
+            vas = vaDestroyContext(hwctx->display, pc->va_context);
+            if (vas != VA_STATUS_SUCCESS) {
+                av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
+                       "context %#x: %d (%s).\n",
+                       pc->va_context, vas, vaErrorStr(vas));
+            }
+        }
+
+        av_buffer_unref(&pc->frames_ref);
+
+        if (pc->va_config != VA_INVALID_ID) {
+            vas = vaDestroyConfig(hwctx->display, pc->va_config);
+            if (vas != VA_STATUS_SUCCESS) {
+                av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
+                       "configuration %#x: %d (%s).\n",
+                       pc->va_config, vas, vaErrorStr(vas));
+            }
+        }
+
+        av_buffer_unref(&pc->device_ref);
+    }
+
+    av_free(data);
+}
+
 int ff_vaapi_decode_init(AVCodecContext *avctx)
 {
-    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+    VAAPIDecodeContext   *ctx = avctx->internal->hwaccel_priv_data;
+    VAAPIDecodePersistent *pc = NULL;
     VAStatus vas;
     int err;
 
@@ -549,48 +602,78 @@ int ff_vaapi_decode_init(AVCodecContext *avctx)
         goto fail;
 
     if (!avctx->hw_frames_ctx) {
-        avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx);
-        if (!avctx->hw_frames_ctx) {
-            err = AVERROR(ENOMEM);
-            goto fail;
+        if (avctx->internal->hwaccel_priv_persistent) {
+            pc = (VAAPIDecodePersistent*)
+                avctx->internal->hwaccel_priv_persistent->data;
         }
-        ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+        if (pc &&
+            pc->surface_width  == avctx->coded_width  &&
+            pc->surface_height == avctx->coded_height &&
+            pc->surface_format == ctx->surface_format &&
+            pc->surface_count  == ctx->surface_count) {
+            av_log(avctx, AV_LOG_DEBUG, "Reusing hardware frames context "
+                   "(%dx%d, %d surfaces of type %s).\n",
+                   pc->surface_width, pc->surface_height, pc->surface_count,
+                   av_get_pix_fmt_name(pc->surface_format));
+
+            avctx->hw_frames_ctx = pc->frames_ref;
+            pc->frames_ref = NULL;
+
+            ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+        } else {
+            av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
+            pc = NULL;
 
-        ctx->frames->format = AV_PIX_FMT_VAAPI;
-        ctx->frames->width  = avctx->coded_width;
-        ctx->frames->height = avctx->coded_height;
+            avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx);
+            if (!avctx->hw_frames_ctx) {
+                err = AVERROR(ENOMEM);
+                goto fail;
+            }
+            ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
 
-        ctx->frames->sw_format         = ctx->surface_format;
-        ctx->frames->initial_pool_size = ctx->surface_count;
+            ctx->frames->format = AV_PIX_FMT_VAAPI;
+            ctx->frames->width  = avctx->coded_width;
+            ctx->frames->height = avctx->coded_height;
 
-        err = ff_init_hw_frames(avctx);
-        if (err < 0) {
-            av_log(avctx, AV_LOG_ERROR, "User initialisation of internal "
-                   "frames context failed: %d.\n", err);
-            goto fail;
-        }
+            ctx->frames->sw_format         = ctx->surface_format;
+            ctx->frames->initial_pool_size = ctx->surface_count;
 
-        err = av_hwframe_ctx_init(avctx->hw_frames_ctx);
-        if (err < 0) {
-            av_log(avctx, AV_LOG_ERROR, "Failed to initialise internal "
-                   "frames context: %d.\n", err);
-            goto fail;
+            err = ff_init_hw_frames(avctx);
+            if (err < 0) {
+                av_log(avctx, AV_LOG_ERROR, "User initialisation of internal "
+                       "frames context failed: %d.\n", err);
+                goto fail;
+            }
+
+            err = av_hwframe_ctx_init(avctx->hw_frames_ctx);
+            if (err < 0) {
+                av_log(avctx, AV_LOG_ERROR, "Failed to initialise internal "
+                       "frames context: %d.\n", err);
+                goto fail;
+            }
         }
 
         ctx->hwfc = ctx->frames->hwctx;
     }
 
-    vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
-                          avctx->coded_width, avctx->coded_height,
-                          VA_PROGRESSIVE,
-                          ctx->hwfc->surface_ids,
-                          ctx->hwfc->nb_surfaces,
-                          &ctx->va_context);
-    if (vas != VA_STATUS_SUCCESS) {
-        av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
-               "context: %d (%s).\n", vas, vaErrorStr(vas));
-        err = AVERROR(EIO);
-        goto fail;
+    if (pc) {
+        av_log(avctx, AV_LOG_DEBUG, "Reusing VA context %#x.\n",
+               pc->va_context);
+        ctx->va_context = pc->va_context;
+        pc->va_context  = VA_INVALID_ID;
+    } else {
+        vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
+                              avctx->coded_width, avctx->coded_height,
+                              VA_PROGRESSIVE,
+                              ctx->hwfc->surface_ids,
+                              ctx->hwfc->nb_surfaces,
+                              &ctx->va_context);
+        if (vas != VA_STATUS_SUCCESS) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
+                   "context: %d (%s).\n", vas, vaErrorStr(vas));
+            err = AVERROR(EIO);
+            goto fail;
+        }
     }
 
     av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: "
@@ -599,6 +682,53 @@ int ff_vaapi_decode_init(AVCodecContext *avctx)
     }
 #endif
 
+    av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
+    if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_REUSE_CONTEXT) {
+        AVBufferRef *pc_ref;
+
+        pc = av_mallocz(sizeof(*pc));
+        if (!pc) {
+            err = AVERROR(ENOMEM);
+            goto fail;
+        }
+
+        pc_ref = av_buffer_create((uint8_t*)pc, sizeof(*pc),
+                                  &vaapi_decode_free_persistent,
+                                  avctx, 0);
+        if (!pc_ref) {
+            av_free(pc);
+            err = AVERROR(ENOMEM);
+            goto fail;
+        }
+        pc = (VAAPIDecodePersistent*)pc_ref->data;
+
+        pc->device_ref = av_buffer_ref(ctx->frames->device_ref);
+        if (!pc->device_ref) {
+            av_buffer_unref(&pc_ref);
+            err = AVERROR(ENOMEM);
+            goto fail;
+        }
+
+        pc->va_profile    = ctx->va_profile;
+        pc->va_entrypoint = ctx->va_entrypoint;
+        pc->va_config     = ctx->va_config;
+        pc->va_context    = ctx->va_context;
+
+        pc->frames_ref = av_buffer_ref(avctx->hw_frames_ctx);
+        if (!pc->frames_ref) {
+            av_buffer_unref(&pc_ref);
+            err = AVERROR(ENOMEM);
+            goto fail;
+        }
+
+        pc->surface_width  = avctx->coded_width;
+        pc->surface_height = avctx->coded_height;
+        pc->surface_format = ctx->surface_format;
+        pc->surface_count  = ctx->surface_count;
+
+        avctx->internal->hwaccel_priv_persistent = pc_ref;
+    }
+
     return 0;
 
 fail:
@@ -608,34 +738,11 @@ fail:
 
 int ff_vaapi_decode_uninit(AVCodecContext *avctx)
 {
+#if FF_API_VAAPI_CONTEXT
     VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-    VAStatus vas;
 
-#if FF_API_VAAPI_CONTEXT
-    if (ctx->have_old_context) {
+    if (ctx->have_old_context)
         av_buffer_unref(&ctx->device_ref);
-    } else {
-#endif
-
-    if (ctx->va_context != VA_INVALID_ID) {
-        vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context);
-        if (vas != VA_STATUS_SUCCESS) {
-            av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
-                   "context %#x: %d (%s).\n",
-                   ctx->va_context, vas, vaErrorStr(vas));
-        }
-    }
-    if (ctx->va_config != VA_INVALID_ID) {
-        vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
-        if (vas != VA_STATUS_SUCCESS) {
-            av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
-                   "configuration %#x: %d (%s).\n",
-                   ctx->va_config, vas, vaErrorStr(vas));
-        }
-    }
-
-#if FF_API_VAAPI_CONTEXT
-    }
 #endif
 
     return 0;
diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h
index 0ff400e34..baa93db97 100644
--- a/libavcodec/vaapi_decode.h
+++ b/libavcodec/vaapi_decode.h
@@ -74,6 +74,24 @@ typedef struct VAAPIDecodeContext {
     int                   surface_count;
 } VAAPIDecodeContext;
 
+typedef struct VAAPIDecodePersistent {
+    AVBufferRef          *device_ref;
+
+    VAProfile             va_profile;
+    VAEntrypoint          va_entrypoint;
+    VAConfigID            va_config;
+    VAContextID           va_context;
+
+    AVBufferRef          *frames_ref;
+
+    // Hardware frame properties used at creation - we may reuse
+    // frames_ref if these are all identical in the new context.
+    int                   surface_width;
+    int                   surface_height;
+    enum AVPixelFormat    surface_format;
+    int                   surface_count;
+} VAAPIDecodePersistent;
+
 
 int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
                                       VAAPIDecodePicture *pic,
-- 
2.11.0

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to