From 1991c79e958d881a67af6d14dbdc395b718599cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Le=20Page?= Date: Fri, 31 Oct 2025 13:38:51 +0100 Subject: [PATCH] Fix a uint32 truncation in gsth264parser --- docker/build-gstreamer/compile | 1 + ...arser-fix-uint32-to-int32-truncation.patch | 115 ++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 docker/build-gstreamer/patch/0001-gsth264parser-fix-uint32-to-int32-truncation.patch diff --git a/docker/build-gstreamer/compile b/docker/build-gstreamer/compile index db6d49e..86a9e38 100755 --- a/docker/build-gstreamer/compile +++ b/docker/build-gstreamer/compile @@ -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 diff --git a/docker/build-gstreamer/patch/0001-gsth264parser-fix-uint32-to-int32-truncation.patch b/docker/build-gstreamer/patch/0001-gsth264parser-fix-uint32-to-int32-truncation.patch new file mode 100644 index 0000000..926c670 --- /dev/null +++ b/docker/build-gstreamer/patch/0001-gsth264parser-fix-uint32-to-int32-truncation.patch @@ -0,0 +1,115 @@ +From 282a528c7234d1cb89422db0fcce56385b0507b5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lo=C3=AFc=20Le=20Page?= +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 +