From 5134d37e7d7e7b75f513916e2027014a4a30d09d Mon Sep 17 00:00:00 2001 From: David Rosca Date: Thu, 19 Mar 2026 09:49:39 +0100 Subject: [PATCH] frontends/va: Fix leaking H264/5 PPS/SPS objects when decoder wasn't created When destroying H264/5 decode context we check the profile from decoder to free the H264/5 PPS/SPS objects, but decoder is only created when decoding first frame so these objects will never get freed in case decoder is NULL. Cc: mesa-stable Reviewed-by: Benjamin Cheng Part-of: --- src/gallium/frontends/va/context.c | 90 ++++++++++++++++-------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/gallium/frontends/va/context.c b/src/gallium/frontends/va/context.c index 0ed67c3b629..05324f2f59f 100644 --- a/src/gallium/frontends/va/context.c +++ b/src/gallium/frontends/va/context.c @@ -490,53 +490,57 @@ vlVaDestroyContext(VADriverContextP ctx, VAContextID context_id) } _mesa_set_destroy(context->buffers, NULL); - if (context->decoder) { - if (context->desc.base.entry_point == PIPE_VIDEO_ENTRYPOINT_ENCODE) { - if (u_reduce_video_profile(context->decoder->profile) == - PIPE_VIDEO_FORMAT_MPEG4_AVC) { - if (context->desc.h264enc.frame_idx) - _mesa_hash_table_destroy(context->desc.h264enc.frame_idx, NULL); - for (uint32_t i = 0; i < ARRAY_SIZE(context->desc.h264enc.dpb); i++) { - struct pipe_video_buffer *buf = context->desc.h264enc.dpb[i].buffer; - if (buf && !context->desc.h264enc.dpb[i].id) - buf->destroy(buf); - } - util_dynarray_fini(&context->desc.h264enc.raw_headers); - } - if (u_reduce_video_profile(context->decoder->profile) == - PIPE_VIDEO_FORMAT_HEVC) { - if (context->desc.h265enc.frame_idx) - _mesa_hash_table_destroy(context->desc.h265enc.frame_idx, NULL); - for (uint32_t i = 0; i < ARRAY_SIZE(context->desc.h265enc.dpb); i++) { - struct pipe_video_buffer *buf = context->desc.h265enc.dpb[i].buffer; - if (buf && !context->desc.h265enc.dpb[i].id) - buf->destroy(buf); - } - util_dynarray_fini(&context->desc.h265enc.raw_headers); - } - if (u_reduce_video_profile(context->decoder->profile) == - PIPE_VIDEO_FORMAT_AV1) { - for (uint32_t i = 0; i < ARRAY_SIZE(context->desc.av1enc.dpb); i++) { - struct pipe_video_buffer *buf = context->desc.av1enc.dpb[i].buffer; - if (buf && !context->desc.av1enc.dpb[i].id) - buf->destroy(buf); - } - util_dynarray_fini(&context->desc.av1enc.raw_headers); + bool is_encode = context->desc.base.entry_point == PIPE_VIDEO_ENTRYPOINT_ENCODE; + switch (u_reduce_video_profile(context->desc.base.profile)) { + case PIPE_VIDEO_FORMAT_MPEG4_AVC: + if (is_encode) { + if (context->desc.h264enc.frame_idx) + _mesa_hash_table_destroy(context->desc.h264enc.frame_idx, NULL); + for (uint32_t i = 0; i < ARRAY_SIZE(context->desc.h264enc.dpb); i++) { + struct pipe_video_buffer *buf = context->desc.h264enc.dpb[i].buffer; + if (buf && !context->desc.h264enc.dpb[i].id) + buf->destroy(buf); } + util_dynarray_fini(&context->desc.h264enc.raw_headers); } else { - if (u_reduce_video_profile(context->decoder->profile) == - PIPE_VIDEO_FORMAT_MPEG4_AVC) { - FREE(context->desc.h264.pps->sps); - FREE(context->desc.h264.pps); - } - if (u_reduce_video_profile(context->decoder->profile) == - PIPE_VIDEO_FORMAT_HEVC) { - FREE(context->desc.h265.pps->sps); - FREE(context->desc.h265.pps); - } + FREE(context->desc.h264.pps->sps); + FREE(context->desc.h264.pps); } - context->decoder->destroy(context->decoder); + break; + + case PIPE_VIDEO_FORMAT_HEVC: + if (is_encode) { + if (context->desc.h265enc.frame_idx) + _mesa_hash_table_destroy(context->desc.h265enc.frame_idx, NULL); + for (uint32_t i = 0; i < ARRAY_SIZE(context->desc.h265enc.dpb); i++) { + struct pipe_video_buffer *buf = context->desc.h265enc.dpb[i].buffer; + if (buf && !context->desc.h265enc.dpb[i].id) + buf->destroy(buf); + } + util_dynarray_fini(&context->desc.h265enc.raw_headers); + } else { + FREE(context->desc.h265.pps->sps); + FREE(context->desc.h265.pps); + } + break; + + case PIPE_VIDEO_FORMAT_AV1: + if (is_encode) { + for (uint32_t i = 0; i < ARRAY_SIZE(context->desc.av1enc.dpb); i++) { + struct pipe_video_buffer *buf = context->desc.av1enc.dpb[i].buffer; + if (buf && !context->desc.av1enc.dpb[i].id) + buf->destroy(buf); + } + util_dynarray_fini(&context->desc.av1enc.raw_headers); + } + break; + + default: + break; } + + if (context->decoder) + context->decoder->destroy(context->decoder); if (context->deint) { vl_deint_filter_cleanup(context->deint); FREE(context->deint);