h265parse: Allow partially broken hvcC data

Ignores parsing error on the last nalu of the array if the nalu type
is not VPS/SPS/PPS

Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2905
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5220>
This commit is contained in:
Seungha Yang 2023-08-22 02:57:24 +09:00 committed by GStreamer Marge Bot
parent 551fe9c9b1
commit 4740a91e00
2 changed files with 77 additions and 0 deletions

View file

@ -3180,11 +3180,14 @@ gst_h265_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
off = 23;
for (i = 0; i < num_nal_arrays; i++) {
guint8 nalu_type;
if (off + 3 >= size) {
gst_buffer_unmap (codec_data, &map);
goto hvcc_too_small;
}
nalu_type = data[off] & 0x3f;
num_nals = GST_READ_UINT16_BE (data + off + 1);
off += 3;
for (j = 0; j < num_nals; j++) {
@ -3192,6 +3195,15 @@ gst_h265_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
data, off, size, 2, &nalu);
if (parseres != GST_H265_PARSER_OK) {
if (i + 1 == num_nal_arrays && j + 1 == num_nals &&
nalu_type != GST_H265_NAL_VPS && nalu_type != GST_H265_NAL_SPS &&
nalu_type != GST_H265_NAL_PPS) {
GST_WARNING_OBJECT (h265parse,
"Couldn't parse the last nalu, type %d at array %d / %d",
nalu_type, i, j);
goto codec_data_done;
}
GST_ERROR ("aaa, %d", nalu_type);
gst_buffer_unmap (codec_data, &map);
goto hvcc_too_small;
}
@ -3200,6 +3212,7 @@ gst_h265_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
off = nalu.offset + nalu.size;
}
}
codec_data_done:
gst_buffer_unmap (codec_data, &map);
/* don't confuse codec_data with inband vps/sps/pps */

View file

@ -1116,6 +1116,68 @@ GST_START_TEST (test_drain)
GST_END_TEST;
GST_START_TEST (test_invalid_sei_in_hvcc)
{
GstHarness *h;
GstCaps *caps;
GstBuffer *codec_data;
/* Consists of 4 arrays (VPS, SPS, PPS, SEI -> broken) and each array contains
* single nalu
* Captured from the log at
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2905
*/
static const guint8 hvcc_data[] = {
0x01, 0x01, 0x01, 0x01, 0x60, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf0, 0x00, 0xfc, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x0f, 0x04, 0x20,
0x00, 0x01, 0x00, 0x17, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60,
0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x7b, 0xac, 0x09, 0x21, 0x00, 0x01, 0x00, 0x42, 0x42, 0x01, 0x01, 0x01,
0x60, 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x7b, 0xa0, 0x02, 0x80, 0x80, 0x2d, 0x1f, 0xe3, 0x6b, 0xbb, 0x53,
0x77, 0x72, 0x5d, 0x60, 0x2d, 0xc0, 0x40, 0x40, 0x41, 0x00, 0x00, 0x03,
0x03, 0xe8, 0x00, 0x00, 0x4e, 0x20, 0x72, 0x1d, 0xee, 0x51, 0x00, 0x05,
0xdc, 0x00, 0x00, 0x1a, 0x5e, 0x00, 0x00, 0x2e, 0xe0, 0x00, 0x00, 0xd2,
0xf0, 0x08, 0x22, 0x00, 0x01, 0x00, 0x0b, 0x44, 0x01, 0xc1, 0x72, 0xb0,
0x9c, 0x38, 0x77, 0x06, 0x0c, 0x24, 0x27, 0x00, 0x01, 0x00, 0x00, 0x00
};
caps = gst_caps_new_simple ("video/x-h265", "stream-format", G_TYPE_STRING,
"hvc1", "alignment", G_TYPE_STRING, "au", NULL);
codec_data = gst_buffer_new_memdup (hvcc_data, sizeof (hvcc_data));
gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
gst_buffer_unref (codec_data);
h = gst_harness_new ("h265parse");
gst_harness_set_src_caps (h, caps);
gst_harness_push_event (h, gst_event_new_eos ());
while (TRUE) {
GstEvent *event = gst_harness_pull_event (h);
fail_unless (event);
if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
GstStructure *s;
gint width, height;
gst_event_parse_caps (event, &caps);
s = gst_caps_get_structure (caps, 0);
fail_unless (gst_structure_get_int (s, "width", &width));
fail_unless_equals_int (width, 1280);
fail_unless (gst_structure_get_int (s, "height", &height));
fail_unless_equals_int (height, 720);
gst_event_unref (event);
break;
}
gst_event_unref (event);
}
gst_harness_teardown (h);
}
GST_END_TEST;
static Suite *
h265parse_harnessed_suite (void)
@ -1152,6 +1214,8 @@ h265parse_harnessed_suite (void)
tcase_add_test (tc_chain, test_drain);
tcase_add_test (tc_chain, test_invalid_sei_in_hvcc);
return s;
}