This avoids freeing and reallocating lots of surfaces when it isn't
necessary do so (for example, when seeking in the same stream).
Since all of the hwaccel data is cleared on reinitialisation, this
adds a new hw_frames_ctx member to AVCodecInternal to store the
reused frames context.  Memory use is not increased, even transiently,
because the previous frames context is always freed before a new one
is allocated.
---
An optional extra, to implement wm4's seeking request.


 libavcodec/internal.h     |  6 +++++
 libavcodec/utils.c        |  2 ++
 libavcodec/vaapi_decode.c | 61 +++++++++++++++++++++++++++++++++++++----------
 3 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 5b82504bf..d831c40aa 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -182,6 +182,12 @@ typedef struct AVCodecInternal {
      * of the packet (that should be submitted in the next decode call */
     size_t compat_decode_partial_size;
     AVFrame *compat_decode_frame;
+
+    /* A reference to the internal hardware frames context made by lavc from a
+     * user-supplied device context, which may be reused on reinitialisation
+     * which doesn't change the codec parameters (for example, seeking in the
+     * same stream). */
+    AVBufferRef *hw_frames_ctx;
 } AVCodecInternal;
 
 struct AVCodecDefault {
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 1d316bd03..903b50b44 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -792,6 +792,8 @@ av_cold int avcodec_close(AVCodecContext *avctx)
 
         ff_decode_bsfs_uninit(avctx);
 
+        av_buffer_unref(&avctx->internal->hw_frames_ctx);
+
         av_freep(&avctx->internal);
     }
 
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index 3ba07908f..82df96f97 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -564,21 +564,58 @@ 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);
-        ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+        int reuse_frames_context = 0;
+        if (avctx->internal->hw_frames_ctx) {
+            ctx->frames =
+                (AVHWFramesContext*)avctx->internal->hw_frames_ctx->data;
+            if (ctx->frames->device_ctx == ctx->device &&
+                ctx->frames->width      == avctx->coded_width  &&
+                ctx->frames->height     == avctx->coded_height &&
+                ctx->frames->sw_format  == ctx->surface_format &&
+                ctx->frames->initial_pool_size == ctx->surface_count) {
+                reuse_frames_context = 1;
+            }
+        }
 
-        ctx->frames->format = AV_PIX_FMT_VAAPI;
-        ctx->frames->width  = avctx->coded_width;
-        ctx->frames->height = avctx->coded_height;
+        if (reuse_frames_context) {
+            avctx->hw_frames_ctx =
+                av_buffer_ref(avctx->internal->hw_frames_ctx);
+            if (!avctx->hw_frames_ctx) {
+                err = AVERROR(ENOMEM);
+                goto fail;
+            }
 
-        ctx->frames->sw_format         = ctx->surface_format;
-        ctx->frames->initial_pool_size = ctx->surface_count;
+        } else {
+            av_buffer_unref(&avctx->internal->hw_frames_ctx);
 
-        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;
+            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->format = AV_PIX_FMT_VAAPI;
+            ctx->frames->width  = avctx->coded_width;
+            ctx->frames->height = avctx->coded_height;
+
+            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;
+            }
+
+            avctx->internal->hw_frames_ctx =
+                av_buffer_ref(avctx->hw_frames_ctx);
+            if (!avctx->internal->hw_frames_ctx) {
+                err = AVERROR(ENOMEM);
+                goto fail;
+            }
         }
 
         ctx->hwfc = ctx->frames->hwctx;
-- 
2.11.0
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to