Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docker/build-gstreamer/compile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ git apply /compile-patch/0001-pad-Check-data-NULL-ness-when-probes-are-stopped-f
git apply /compile-patch/0001-Reduce-logs-verbosity-in-webrtcbin-when-a-FEC-decode.patch
git apply /compile-patch/0001-glvideomixer-update-API-to-be-compatible-with-versio.patch
git apply /compile-patch/0001-GstAudioAggregator-fix-structure-unref.patch
git apply /compile-patch/0001-gsth264parser-fix-uint32-to-int32-truncation.patch

# This is needed for other plugins to be built properly
ninja -C build install
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
From 282a528c7234d1cb89422db0fcce56385b0507b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Le=20Page?= <llepage@igalia.com>
Date: Fri, 31 Oct 2025 13:27:47 +0100
Subject: [PATCH] gsth264parser: fix uint32 to int32 truncation

The H264 parser is using int32 to compute the framerate numerator and
denominator while the SPS block holding the original values used for
this computation are stored on uint32. On corner cases it may lead to a
truncation of the final values leading to an invalid framerate.

This patch is shifting right the numerator and denominator until both
values may be stored on int32. It may introduce a small computation
error with odd values but negligeable taking into account the huge
initial values > max_int32.
---
.../gst-libs/gst/codecparsers/gsth264parser.c | 9 +++-
.../tests/check/libs/h264parser.c | 48 +++++++++++++++++++
2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth264parser.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth264parser.c
index ea3c6fb995..5095bcea73 100644
--- a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth264parser.c
+++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gsth264parser.c
@@ -2946,8 +2946,8 @@ void
gst_h264_video_calculate_framerate (const GstH264SPS * sps,
guint field_pic_flag, guint pic_struct, gint * fps_num, gint * fps_den)
{
- gint num = 0;
- gint den = 1;
+ gint64 num = 0;
+ gint64 den = 1;

/* To calculate framerate, we use this formula:
* time_scale 1 1
@@ -2998,6 +2998,11 @@ gst_h264_video_calculate_framerate (const GstH264SPS * sps,
}
}

+ while (num > G_MAXINT32 || den > G_MAXINT32) {
+ num >>= 1;
+ den >>= 1;
+ }
+
*fps_num = num;
*fps_den = den;
}
diff --git a/subprojects/gst-plugins-bad/tests/check/libs/h264parser.c b/subprojects/gst-plugins-bad/tests/check/libs/h264parser.c
index ddf4fe50d4..1ddab3bea7 100644
--- a/subprojects/gst-plugins-bad/tests/check/libs/h264parser.c
+++ b/subprojects/gst-plugins-bad/tests/check/libs/h264parser.c
@@ -1023,6 +1023,53 @@ GST_START_TEST (test_h264_split_avc)

GST_END_TEST;

+// This SPS block with vui parameters defines:
+// - frame_mbs_only_flag: 1 (progressive)
+// - time_scale: 4294967294 (overflows int32 capacity)
+// - num_units_in_tick: 71834980
+// The expected framerate is 29,894678707 fps.
+static const guint8 nalu_sps_with_overflow_framerate[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x27, 0x64, 0x00, 0x1f,
+ 0xac, 0x72, 0x14, 0x05, 0x00, 0x5b, 0xb0, 0x11,
+ 0x04, 0x48, 0x1d, 0x64, 0xff, 0xff, 0xff, 0xfe,
+ 0xe2, 0x20, 0x00, 0x74, 0xc1, 0x00, 0x00, 0x74,
+ 0xc1, 0x3b, 0xde, 0xe0, 0x3e, 0x10, 0x08, 0x32,
+ 0xc0
+};
+
+GST_START_TEST (test_h264_parse_overflow_framerate)
+{
+ GstH264ParserResult res;
+ GstH264NalUnit nalu;
+ GstH264SPS sps;
+ gint fps_num, fps_den;
+ GstH264NalParser *const parser = gst_h264_nal_parser_new ();
+
+ res = gst_h264_parser_identify_nalu (parser, nalu_sps_with_overflow_framerate,
+ 0, sizeof (nalu_sps_with_overflow_framerate), &nalu);
+ assert_equals_int (res, GST_H264_PARSER_NO_NAL_END);
+ assert_equals_int (nalu.type, GST_H264_NAL_SPS);
+ assert_equals_int (nalu.size, 37);
+
+ res = gst_h264_parser_parse_sps (parser, &nalu, &sps);
+ assert_equals_int (res, GST_H264_PARSER_OK);
+ fail_unless (sps.valid);
+ fail_unless (sps.frame_mbs_only_flag);
+ fail_unless (sps.vui_parameters_present_flag);
+ fail_unless (sps.vui_parameters.timing_info_present_flag);
+ assert_equals_uint64 (sps.vui_parameters.time_scale, 4294967294);
+ assert_equals_uint64 (sps.vui_parameters.num_units_in_tick, 71834980);
+
+ gst_h264_video_calculate_framerate (&sps, 0, 0, &fps_num, &fps_den);
+ assert_equals_int (fps_num, 2147483647);
+ assert_equals_int (fps_den, 71834980);
+
+ gst_h264_sps_clear (&sps);
+ gst_h264_nal_parser_free (parser);
+}
+
+GST_END_TEST;
+
static Suite *
h264parser_suite (void)
{
@@ -1039,6 +1086,7 @@ h264parser_suite (void)
tcase_add_test (tc_chain, test_h264_create_sei);
tcase_add_test (tc_chain, test_h264_decoder_config_record);
tcase_add_test (tc_chain, test_h264_split_avc);
+ tcase_add_test (tc_chain, test_h264_parse_overflow_framerate);

return s;
}
--
2.43.0