rtcpbuffer: Add profile-specific extension API.
authorHaakon Sporsheim <haakon@pexip.com>
Tue, 29 Jul 2014 13:37:12 +0000 (15:37 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Thu, 24 Mar 2016 12:22:54 +0000 (14:22 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=761950

gst-libs/gst/rtp/gstrtcpbuffer.c
gst-libs/gst/rtp/gstrtcpbuffer.h
tests/check/libs/rtp.c
win32/common/libgstrtp.def

index e5e4ca7..8fb31c3 100644 (file)
@@ -956,6 +956,9 @@ gst_rtcp_packet_add_rb (GstRTCPPacket * packet, guint32 ssrc,
       packet->type == GST_RTCP_TYPE_SR, FALSE);
   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
+  /* if profile-specific extension is added, fail for now!? */
+  g_return_val_if_fail (
+      gst_rtcp_packet_get_profile_specific_ext_length (packet) == 0, FALSE);
 
   if (packet->count >= GST_RTCP_MAX_RB_COUNT)
     goto no_space;
@@ -1040,6 +1043,156 @@ gst_rtcp_packet_set_rb (GstRTCPPacket * packet, guint nth, guint32 ssrc,
 
 
 /**
+ * gst_rtcp_packet_set_profile_specific_ext:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ * @data: (array length=len) (transfer none): profile-specific data
+ * @len: length of the profile-specific data in bytes
+ *
+ * Add profile-specific extension @data to @packet. If @packet already
+ * contains profile-specific extension @data will be appended to the existing
+ * extension.
+ *
+ * Returns: %TRUE if the profile specific extension data was added.
+ */
+gboolean
+gst_rtcp_packet_add_profile_specific_ext (GstRTCPPacket * packet,
+    const guint8 * data, guint len)
+{
+  guint8 *bdata;
+  guint maxsize, offset;
+
+  g_return_val_if_fail (packet != NULL, FALSE);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
+      packet->type == GST_RTCP_TYPE_SR, FALSE);
+  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
+  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
+  g_return_val_if_fail ((len & 0x03) == 0, FALSE);
+
+  bdata = packet->rtcp->map.data;
+  maxsize = packet->rtcp->map.maxsize;
+
+  /* skip to the end of the packet */
+  offset = packet->offset + (packet->length << 2) + 4;
+
+  /* we need 'len' free bytes now */
+  if (G_UNLIKELY (offset + len > maxsize))
+    return FALSE;
+
+  memcpy (&bdata[offset], data, len);
+  packet->length += len >> 2;
+  bdata[packet->offset + 2] = (packet->length) >> 8;
+  bdata[packet->offset + 3] = (packet->length) & 0xff;
+  packet->rtcp->map.size += len;
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_get_profile_specific_ext_length:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ *
+ * Returns: The number of 32-bit words containing profile-specific extension
+ *          data from @packet.
+ */
+guint16
+gst_rtcp_packet_get_profile_specific_ext_length (GstRTCPPacket * packet)
+{
+  guint pse_offset = 2;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
+      packet->type == GST_RTCP_TYPE_SR, 0);
+  g_return_val_if_fail (packet->rtcp != NULL, 0);
+  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
+
+  if (packet->type == GST_RTCP_TYPE_SR)
+    pse_offset += 5;
+  pse_offset += (packet->count * 6);
+
+  if (pse_offset <= (packet->length + 1))
+    return packet->length + 1 - pse_offset;
+
+  /* This means that the packet is invalid! */
+  return 0;
+}
+
+/**
+ * gst_rtcp_packet_get_profile_specific_ext:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ * @data: (out) (array length=len) (transfer none): result profile-specific data
+ * @len: (out): result length of the profile-specific data
+ *
+ * Returns: %TRUE if there was valid data.
+ */
+gboolean
+gst_rtcp_packet_get_profile_specific_ext (GstRTCPPacket * packet,
+    guint8 ** data, guint * len)
+{
+  guint16 pse_len;
+
+  g_return_val_if_fail (packet != NULL, FALSE);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
+      packet->type == GST_RTCP_TYPE_SR, FALSE);
+  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
+  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
+
+  pse_len = gst_rtcp_packet_get_profile_specific_ext_length (packet);
+  if (pse_len > 0) {
+    if (len != NULL)
+      *len = pse_len * sizeof (guint32);
+    if (data != NULL) {
+      *data = packet->rtcp->map.data;
+      *data += packet->offset;
+      *data += ((packet->length + 1 - pse_len) * sizeof (guint32));
+    }
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+ * gst_rtcp_packet_copy_profile_specific_ext:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ * @data: (out) (array length=len): result profile-specific data
+ * @len: (out): length of the profile-specific extension data
+ *
+ * The profile-specific extension data is copied into a new allocated
+ * memory area @data. This must be freed with g_free() after usage.
+ *
+ * Returns: %TRUE if there was valid data.
+ */
+gboolean
+gst_rtcp_packet_copy_profile_specific_ext (GstRTCPPacket * packet,
+    guint8 ** data, guint * len)
+{
+  guint16 pse_len;
+
+  g_return_val_if_fail (packet != NULL, FALSE);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
+      packet->type == GST_RTCP_TYPE_SR, FALSE);
+  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
+  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
+
+  pse_len = gst_rtcp_packet_get_profile_specific_ext_length (packet);
+  if (pse_len > 0) {
+    if (len != NULL)
+      *len = pse_len * sizeof (guint32);
+    if (data != NULL) {
+      guint8 * ptr = packet->rtcp->map.data + packet->offset;
+      ptr += ((packet->length + 1 - pse_len) * sizeof (guint32));
+      *data = g_memdup (ptr, pse_len * sizeof (guint32));
+    }
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+/**
  * gst_rtcp_packet_sdes_get_item_count:
  * @packet: a valid SDES #GstRTCPPacket
  *
index 328ecdd..c7cfe6a 100644 (file)
@@ -279,6 +279,15 @@ void            gst_rtcp_packet_set_rb                (GstRTCPPacket *packet, gu
                                                        guint32 exthighestseq, guint32 jitter,
                                                        guint32 lsr, guint32 dlsr);
 
+/* profile-specific extensions for SR and RR */
+gboolean        gst_rtcp_packet_add_profile_specific_ext        (GstRTCPPacket * packet,
+                                                                 const guint8 * data, guint len);
+guint16         gst_rtcp_packet_get_profile_specific_ext_length (GstRTCPPacket * packet);
+gboolean        gst_rtcp_packet_get_profile_specific_ext        (GstRTCPPacket * packet,
+                                                                 guint8 ** data, guint * len);
+gboolean        gst_rtcp_packet_copy_profile_specific_ext       (GstRTCPPacket * packet,
+                                                                 guint8 ** data, guint * len);
+
 /* source description packet */
 guint           gst_rtcp_packet_sdes_get_item_count   (GstRTCPPacket *packet);
 gboolean        gst_rtcp_packet_sdes_first_item       (GstRTCPPacket *packet);
index d69357a..d802855 100644 (file)
@@ -991,6 +991,95 @@ GST_START_TEST (test_rtcp_validate_reduced_with_padding)
 
 GST_END_TEST;
 
+GST_START_TEST (test_rtcp_buffer_profile_specific_extension)
+{
+  GstBuffer *buf;
+  GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+  GstRTCPPacket packet;
+  const guint8 pse[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
+  const guint8 pse2[] = { 0x01, 0x23, 0x45, 0x67 };
+
+  fail_unless ((buf = gst_rtcp_buffer_new (1400)) != NULL);
+  gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcp);
+
+  fail_unless (gst_rtcp_buffer_validate (buf) == FALSE);
+  fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet) == FALSE);
+  fail_unless (gst_rtcp_buffer_get_packet_count (&rtcp) == 0);
+
+  /* add an SR packet with sender info */
+  fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_SR, &packet));
+  gst_rtcp_packet_sr_set_sender_info (&packet, 0x44556677,
+      G_GUINT64_CONSTANT (1), 0x11111111, 101, 123456);
+  fail_unless_equals_int (0,
+      gst_rtcp_packet_get_profile_specific_ext_length (&packet));
+  fail_unless_equals_int (6, gst_rtcp_packet_get_length (&packet));
+
+  /* add profile-specific extension */
+  fail_unless (gst_rtcp_packet_add_profile_specific_ext (&packet,
+          pse, sizeof (pse)));
+  {
+    guint8 *data = NULL;
+    guint len = 0;
+
+    fail_unless_equals_int (8, gst_rtcp_packet_get_length (&packet));
+    fail_unless_equals_int (sizeof (pse) / 4,
+        gst_rtcp_packet_get_profile_specific_ext_length (&packet));
+
+    /* gst_rtcp_packet_get_profile_specific_ext */
+    fail_unless (gst_rtcp_packet_get_profile_specific_ext (&packet, &data, &len));
+    fail_unless_equals_int (sizeof (pse), len);
+    fail_unless (data != NULL);
+    fail_unless_equals_int (0, memcmp (pse, data, sizeof (pse)));
+
+    /* gst_rtcp_packet_copy_profile_specific_ext */
+    fail_unless (gst_rtcp_packet_copy_profile_specific_ext (&packet, &data, &len));
+    fail_unless_equals_int (sizeof (pse), len);
+    fail_unless (data != NULL);
+    fail_unless_equals_int (0, memcmp (pse, data, sizeof (pse)));
+    g_free (data);
+  }
+
+  /* append more profile-specific extension */
+  fail_unless (gst_rtcp_packet_add_profile_specific_ext (&packet,
+          pse2, sizeof (pse2)));
+  {
+    guint8 *data = NULL;
+    guint len = 0;
+    guint concat_len;
+    guint8 *concat_pse;
+
+    /* Expect the second extension to be appended to the first */
+    concat_len = sizeof (pse) + sizeof (pse2);
+    concat_pse = g_malloc (concat_len);
+    memcpy (concat_pse, pse, sizeof (pse));
+    memcpy (concat_pse + sizeof (pse), pse2, sizeof (pse2));
+
+    fail_unless_equals_int (9, gst_rtcp_packet_get_length (&packet));
+    fail_unless_equals_int (concat_len / 4,
+        gst_rtcp_packet_get_profile_specific_ext_length (&packet));
+
+    /* gst_rtcp_packet_get_profile_specific_ext */
+    fail_unless (gst_rtcp_packet_get_profile_specific_ext (&packet, &data, &len));
+    fail_unless_equals_int (concat_len, len);
+    fail_unless (data != NULL);
+    fail_unless_equals_int (0, memcmp (concat_pse, data, len));
+
+    /* gst_rtcp_packet_copy_profile_specific_ext */
+    fail_unless (gst_rtcp_packet_copy_profile_specific_ext (&packet, &data, &len));
+    fail_unless_equals_int (concat_len, len);
+    fail_unless (data != NULL);
+    fail_unless_equals_int (0, memcmp (concat_pse, data, len));
+    g_free (data);
+    g_free (concat_pse);
+  }
+
+  /* close and validate */
+  gst_rtcp_buffer_unmap (&rtcp);
+  fail_unless (gst_rtcp_buffer_validate (buf) == TRUE);
+  gst_buffer_unref (buf);
+}
+GST_END_TEST;
+
 GST_START_TEST (test_rtp_ntp64_extension)
 {
   GstBuffer *buf;
@@ -1231,6 +1320,8 @@ rtp_suite (void)
       test_rtcp_validate_with_padding_set_in_first_packet);
   tcase_add_test (tc_chain, test_rtcp_validate_reduced_without_padding);
   tcase_add_test (tc_chain, test_rtcp_validate_reduced_with_padding);
+  tcase_add_test (tc_chain, test_rtcp_buffer_profile_specific_extension);
+
   tcase_add_test (tc_chain, test_rtp_ntp64_extension);
   tcase_add_test (tc_chain, test_rtp_ntp56_extension);
 
index 52f654f..7a25680 100644 (file)
@@ -20,6 +20,7 @@ EXPORTS
        gst_rtcp_packet_bye_get_reason_len
        gst_rtcp_packet_bye_get_ssrc_count
        gst_rtcp_packet_bye_set_reason
+       gst_rtcp_packet_copy_profile_specific_ext
        gst_rtcp_packet_fb_get_fci
        gst_rtcp_packet_fb_get_fci_length
        gst_rtcp_packet_fb_get_media_ssrc
@@ -32,6 +33,8 @@ EXPORTS
        gst_rtcp_packet_get_count
        gst_rtcp_packet_get_length
        gst_rtcp_packet_get_padding
+       gst_rtcp_packet_get_profile_specific_ext
+       gst_rtcp_packet_get_profile_specific_ext_len
        gst_rtcp_packet_get_rb
        gst_rtcp_packet_get_rb_count
        gst_rtcp_packet_get_type
@@ -49,6 +52,7 @@ EXPORTS
        gst_rtcp_packet_sdes_get_ssrc
        gst_rtcp_packet_sdes_next_entry
        gst_rtcp_packet_sdes_next_item
+       gst_rtcp_packet_set_profile_specific_ext
        gst_rtcp_packet_set_rb
        gst_rtcp_packet_sr_get_sender_info
        gst_rtcp_packet_sr_set_sender_info