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>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40504>
This commit is contained in:
David Rosca 2026-03-19 09:49:39 +01:00 committed by Marge Bot
parent e2ebcba11b
commit 5134d37e7d

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