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