On Wed, 1 Feb 2017 21:36:04 +0000
Mark Thompson <[email protected]> wrote:

> 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;

This should be ok. I suppose the frame pool is only allocated or
saved/reused if the user sets the device context.
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to