rtp: also support shrinking the extension data
authorMatthew Waters <matthew@centricular.com>
Tue, 24 Aug 2021 11:26:54 +0000 (21:26 +1000)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 19 Oct 2021 03:26:57 +0000 (03:26 +0000)
Currently the extension data length specified in the RTP header would
say it was shorter then the data serialised to a packet. When
combining the resulting buffer, the underlying memory would still
contain the extra (now 0-filled) padding data.

This would mean that parsing the resulting RTP packet would potentially
start with a number of 0-filled bytes which many RTP formats are not
expecting.

Such usage is found by e.g. RTP header extension when allocating the
maximum buffer (which may be larger than the written size) and shrinking
to the required size the data once all the rtp header extension data has
been written.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1146>

subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbuffer.c
subprojects/gst-plugins-base/tests/check/libs/rtp.c

index ce3949a..399724d 100644 (file)
@@ -833,6 +833,8 @@ ensure_buffers (GstRTPBuffer * rtp)
  * extension header. If the existing extension data is not large enough, it will
  * be made larger.
  *
+ * Will also shorten the extension data from 1.20.
+ *
  * Returns: True if done.
  */
 gboolean
@@ -882,6 +884,15 @@ gst_rtp_buffer_set_extension_data (GstRTPBuffer * rtp, guint16 bits,
     gst_memory_ref (mem);
     rtp->data[1] = rtp->map[1].data;
     rtp->size[1] = rtp->map[1].size;
+  } else if (min_size < rtp->size[1]) {
+    GstMemory *mem = rtp->map[1].memory;
+
+    gst_memory_ref (mem);
+    gst_buffer_unmap (rtp->buffer, &rtp->map[1]);
+    gst_memory_resize (mem, 0, min_size);
+    gst_memory_map (mem, &rtp->map[1], GST_MAP_READWRITE);
+    rtp->data[1] = rtp->map[1].data;
+    rtp->size[1] = rtp->map[1].size;
   }
 
   /* now we can set the extension bit */
index 029260d..11eec6d 100644 (file)
@@ -421,6 +421,87 @@ GST_START_TEST (test_rtp_buffer_set_extension_data)
 
 GST_END_TEST;
 
+GST_START_TEST (test_rtp_buffer_set_extension_data_shrink_data)
+{
+  GstBuffer *buf;
+  guint16 bits;
+  guint size;
+  gpointer pointer;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  guint8 scratch_cmp[4 * 4] = { 0, };
+  GstMapInfo info = GST_MAP_INFO_INIT;
+  gsize i;
+
+  buf = gst_rtp_buffer_new_allocate (20, 0, 0);
+  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+
+  fail_unless (gst_rtp_buffer_set_extension_data (&rtp, 270, 4) == TRUE);
+  fail_unless (gst_rtp_buffer_get_extension (&rtp) == TRUE);
+  gst_rtp_buffer_get_extension_data (&rtp, &bits, &pointer, &size);
+  GST_MEMDUMP ("", pointer, size * 4);
+  fail_unless (bits == 270);
+  fail_unless (size == 4);
+  for (i = 0; i < size * 4; i++) {
+    guint8 *bytes = pointer;
+    bytes[i] = i;
+  }
+  memcpy (scratch_cmp, pointer, size * 4);
+  fail_unless_equals_int64 ((guint64) gst_buffer_get_size (buf), 52);
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* ensure that the mapped buffer size matches */
+  gst_buffer_map (buf, &info, GST_MAP_READ);
+  GST_MEMDUMP ("", info.data, info.size);
+  fail_unless_equals_int64 ((guint64) info.size, 52);
+  gst_buffer_unmap (buf, &info);
+
+  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+  /* shrinking the extension data should still succeed and only output the
+   * relevant data */
+  fail_unless (gst_rtp_buffer_set_extension_data (&rtp, 180, 2) == TRUE);
+  gst_rtp_buffer_get_extension_data (&rtp, &bits, &pointer, &size);
+  GST_MEMDUMP ("", pointer, size * 4);
+  fail_unless (bits == 180);
+  fail_unless (size == 2);
+  fail_unless_equals_int64 ((guint64) gst_buffer_get_size (buf), 44);
+  for (i = 0; i < 8; i++) {
+    guint8 *ext_data = pointer;
+    fail_unless_equals_int_hex (ext_data[i], scratch_cmp[i]);
+  }
+  gst_rtp_buffer_unmap (&rtp);
+
+  gst_buffer_map (buf, &info, GST_MAP_READ);
+  GST_MEMDUMP ("", info.data, info.size);
+  fail_unless_equals_int64 ((guint64) info.size, 44);
+  gst_buffer_unmap (buf, &info);
+
+  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+  fail_unless (gst_rtp_buffer_set_extension_data (&rtp, 308, 3) == TRUE);
+  gst_rtp_buffer_get_extension_data (&rtp, &bits, &pointer, &size);
+  GST_MEMDUMP ("", pointer, size * 4);
+  fail_unless (bits == 308);
+  fail_unless (size == 3);
+  for (i = 0; i < 8; i++) {
+    guint8 *ext_data = pointer;
+    fail_unless_equals_int_hex (ext_data[i], scratch_cmp[i]);
+  }
+  /* new data will be zero-initialized */
+  for (i = 8; i < size * 4; i++) {
+    guint8 *ext_data = pointer;
+    fail_unless_equals_int_hex (ext_data[i], 0);
+  }
+  fail_unless_equals_int64 ((guint64) gst_buffer_get_size (buf), 48);
+  gst_rtp_buffer_unmap (&rtp);
+
+  gst_buffer_map (buf, &info, GST_MAP_READ);
+  GST_MEMDUMP ("", info.data, info.size);
+  fail_unless_equals_int64 ((guint64) info.size, 48);
+  gst_buffer_unmap (buf, &info);
+  gst_buffer_unref (buf);
+}
+
+GST_END_TEST;
+
 #if 0
 GST_START_TEST (test_rtp_buffer_list_set_extension)
 {
@@ -2290,6 +2371,7 @@ rtp_suite (void)
   tcase_add_test (tc_chain, test_rtcp_compound_padding);
   tcase_add_test (tc_chain, test_rtp_buffer_extlen_wraparound);
   tcase_add_test (tc_chain, test_rtp_buffer_remove_extension_data);
+  tcase_add_test (tc_chain, test_rtp_buffer_set_extension_data_shrink_data);
 
   return s;
 }