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 <benjamin.cheng@amd.com>
(cherry picked from commit 5134d37e7d)

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40752>
This commit is contained in:
David Rosca 2026-03-19 09:49:39 +01:00 committed by Eric Engestrom
parent 123322b8ae
commit 9c88f72f8c
2 changed files with 48 additions and 44 deletions

View file

@ -5304,7 +5304,7 @@
"description": "frontends/va: Fix leaking H264/5 PPS/SPS objects when decoder wasn't created",
"nominated": true,
"nomination_type": 1,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": null,
"notes": null

View file

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