h265parse: Allow partially broken hvcC data
authorSeungha Yang <seungha@centricular.com>
Mon, 21 Aug 2023 17:57:24 +0000 (02:57 +0900)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 23 Aug 2023 11:20:33 +0000 (11:20 +0000)
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>

subprojects/gst-plugins-bad/gst/videoparsers/gsth265parse.c
subprojects/gst-plugins-bad/tests/check/elements/h265parse.c

index 3c7380a..0fb4652 100644 (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 */
index a2c4f3d..7cd941f 100644 (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;
 }