rtpbuffer: Add functions to add RFC 5285 header extensions to GstBufferLists
authorOlivier CrĂȘte <olivier.crete@collabora.co.uk>
Sun, 22 Aug 2010 23:44:38 +0000 (19:44 -0400)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 5 Oct 2010 14:19:14 +0000 (16:19 +0200)
Add functions to add header extensions to buffer lists, these functions only modify
the header part of the buffer lists, so the data is not copied.

docs/libs/gst-plugins-base-libs-sections.txt
gst-libs/gst/rtp/gstrtpbuffer.c
gst-libs/gst/rtp/gstrtpbuffer.h

index b9184f8..ccd57a5 100644 (file)
@@ -1359,12 +1359,13 @@ gst_rtp_buffer_list_set_timestamp
 
 gst_rtp_buffer_get_extension_onebyte_header
 gst_rtp_buffer_get_extension_twobytes_header
-
 gst_rtp_buffer_add_extension_onebyte_header
 gst_rtp_buffer_add_extension_twobytes_header
 
 gst_rtp_buffer_list_get_extension_onebyte_header
 gst_rtp_buffer_list_get_extension_twobytes_header
+gst_rtp_buffer_list_add_extension_onebyte_header
+gst_rtp_buffer_list_add_extension_twobytes_header
 </SECTION>
 
 # rtsp
index 4919dc8..b470730 100644 (file)
@@ -1543,6 +1543,43 @@ gst_rtp_buffer_get_extension_twobytes_header (GstBuffer * buffer,
   return FALSE;
 }
 
+static guint
+get_onebyte_header_end_offset (guint8 * pdata, guint wordlen)
+{
+  guint offset = 0;
+  guint bytelen = wordlen * 4;
+  guint paddingcount = 0;
+
+  while (offset + 1 < bytelen) {
+    guint8 read_id, read_len;
+
+    read_id = GST_READ_UINT8 (pdata + offset) >> 4;
+    read_len = (GST_READ_UINT8 (pdata + offset) & 0x0F) + 1;
+    offset += 1;
+
+    /* ID 0 means its padding, skip */
+    if (read_id == 0) {
+      paddingcount++;
+      continue;
+    }
+
+    paddingcount = 0;
+
+    /* ID 15 is special and means we should stop parsing */
+    /* It also means we can't add an extra packet */
+    if (read_id == 15)
+      return 0;
+
+    /* Ignore extension headers where the size does not fit */
+    if (offset + read_len > bytelen)
+      return 0;
+
+    offset += read_len;
+  }
+
+  return offset - paddingcount;
+}
+
 /**
  * gst_rtp_buffer_add_extension_onebyte_header:
  * @buffer: the buffer
@@ -1590,32 +1627,11 @@ gst_rtp_buffer_add_extension_onebyte_header (GstBuffer * buffer, guint8 id,
     if (bits != 0xBEDE)
       return FALSE;
 
-    while (offset + 1 < bytelen) {
-      guint8 read_id, read_len;
-
-      read_id = GST_READ_UINT8 (pdata + offset) >> 4;
-      read_len = (GST_READ_UINT8 (pdata + offset) & 0x0F) + 1;
-      offset += 1;
-
-      /* ID 0 means its padding, skip */
-      if (read_id == 0)
-        continue;
-
-      /* ID 15 is special and means we should stop parsing */
-      /* It also means we can't add an extra packet */
-      if (read_id == 15)
-        return FALSE;
-
-      /* Ignore extension headers where the size does not fit */
-      if (offset + read_len > bytelen)
-        return FALSE;
-
-      offset += read_len;
-
-    }
+    offset = get_onebyte_header_end_offset (pdata, wordlen);
+    if (offset == 0)
+      return FALSE;
 
     nextext = pdata + offset;
-
     offset = nextext - GST_BUFFER_DATA (buffer);
 
     /* Don't add extra header if there isn't enough space */
@@ -1652,6 +1668,41 @@ gst_rtp_buffer_add_extension_onebyte_header (GstBuffer * buffer, guint8 id,
   return TRUE;
 }
 
+
+static guint
+get_twobytes_header_end_offset (guint8 * pdata, guint wordlen)
+{
+  guint offset = 0;
+  guint bytelen = wordlen * 4;
+  guint paddingcount = 0;
+
+  while (offset + 2 < bytelen) {
+    guint8 read_id, read_len;
+
+    read_id = GST_READ_UINT8 (pdata + offset);
+    offset += 1;
+
+    /* ID 0 means its padding, skip */
+    if (read_id == 0) {
+      paddingcount++;
+      continue;
+    }
+
+    paddingcount = 0;
+
+    read_len = GST_READ_UINT8 (pdata + offset);
+    offset += 1;
+
+    /* Ignore extension headers where the size does not fit */
+    if (offset + read_len > bytelen)
+      return 0;
+
+    offset += read_len;
+  }
+
+  return offset - paddingcount;
+}
+
 /**
  * gst_rtp_buffer_add_extension_twobytes_header:
  * @buffer: the buffer
@@ -1700,25 +1751,7 @@ gst_rtp_buffer_add_extension_twobytes_header (GstBuffer * buffer,
     if (bits != ((0x100 << 4) | (appbits & 0x0f)))
       return FALSE;
 
-    while (offset + 2 < bytelen) {
-      guint8 read_id, read_len;
-
-      read_id = GST_READ_UINT8 (pdata + offset);
-      offset += 1;
-
-      /* ID 0 means its padding, skip */
-      if (read_id == 0)
-        continue;
-
-      read_len = GST_READ_UINT8 (pdata + offset);
-      offset += 1;
-
-      /* Ignore extension headers where the size does not fit */
-      if (offset + read_len > bytelen)
-        return FALSE;
-
-      offset += read_len;
-    }
+    offset = get_twobytes_header_end_offset (pdata, wordlen);
 
     nextext = pdata + offset;
 
@@ -1827,3 +1860,165 @@ gst_rtp_buffer_list_get_extension_twobytes_header (GstBufferList * bufferlist,
   return gst_rtp_buffer_get_extension_twobytes_header (buffer, appbits, id,
       nth, data, size);
 }
+
+/**
+ * gst_rtp_buffer_list_add_extension_onebyte_header:
+ * @it: a #GstBufferListIterator pointing right after the #GstBuffer where
+ * the header extension should be added
+ * @id: The ID of the header extension (between 1 and 14).
+ * @data: location for data
+ * @size: the size of the data in bytes
+ *
+ * Adds a RFC 5285 header extension with a one byte header to the end of the
+ * RTP header. If there is already a RFC 5285 header extension with a one byte
+ * header, the new extension will be appended.
+ * It will not work if there is already a header extension that does not follow
+ * the mecanism described in RFC 5285 or if there is a header extension with
+ * a two bytes header as described in RFC 5285. In that case, use
+ * gst_rtp_buffer_list_add_extension_twobytes_header()
+ *
+ * This function will not modify the data section of the RTP buffer, only
+ * the header.
+ *
+ * Returns: %TRUE if header extension could be added
+ *
+ * Since: 0.10.31
+ */
+
+gboolean
+gst_rtp_buffer_list_add_extension_onebyte_header (GstBufferListIterator * it,
+    guint8 id, gpointer data, guint size)
+{
+  GstBuffer *buffer;
+  guint16 bits;
+  guint8 *pdata;
+  guint wordlen;
+  gboolean retval;
+  guint endoffset = 0;
+
+  g_return_val_if_fail (gst_buffer_list_iterator_n_buffers (it) == 1, FALSE);
+  g_return_val_if_fail (id > 0 && id < 15, FALSE);
+  g_return_val_if_fail (size >= 1 && size <= 16, FALSE);
+
+  buffer = gst_buffer_list_iterator_steal (it);
+
+  if (GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer))) {
+    gst_rtp_buffer_get_extension_data (buffer, &bits, (gpointer) & pdata,
+        &wordlen);
+
+    if (bits != 0xBEDE)
+      return FALSE;
+
+    endoffset = get_onebyte_header_end_offset (pdata, wordlen);
+    if (endoffset == 0)
+      return FALSE;
+    endoffset += pdata - GST_BUFFER_DATA (buffer);
+  } else {
+    endoffset = GST_BUFFER_SIZE (buffer) + 4;
+  }
+
+  if (endoffset + size + 1 > GST_BUFFER_SIZE (buffer)) {
+    guint newsize;
+    GstBuffer *newbuffer;
+
+    newsize = endoffset + size + 1;
+    if (newsize % 4)
+      newsize += 4 - (newsize % 4);
+    newbuffer = gst_buffer_new_and_alloc (newsize);
+    memcpy (GST_BUFFER_DATA (newbuffer), GST_BUFFER_DATA (buffer),
+        GST_BUFFER_SIZE (buffer));
+    gst_buffer_copy_metadata (newbuffer, buffer, GST_BUFFER_COPY_ALL);
+    gst_buffer_unref (buffer);
+    buffer = newbuffer;
+  } else {
+    buffer = gst_buffer_make_writable (buffer);
+  }
+
+  retval = gst_rtp_buffer_add_extension_onebyte_header (buffer, id, data, size);
+
+  gst_buffer_list_iterator_take (it, buffer);
+
+  return retval;
+}
+
+/**
+ * gst_rtp_buffer_list_add_extension_twobytes_header:
+ * @it: a #GstBufferListIterator pointing right after the #GstBuffer where
+ * the header extension should be added
+ * @appbits: Application specific bits
+ * @id: The ID of the header extension
+ * @data: location for data
+ * @size: the size of the data in bytes
+ *
+ * Adds a RFC 5285 header extension with a two bytes header to the end of the
+ * RTP header. If there is already a RFC 5285 header extension with a two bytes
+ * header, the new extension will be appended.
+ * It will not work if there is already a header extension that does not follow
+ * the mecanism described in RFC 5285 or if there is a header extension with
+ * a one byte header as described in RFC 5285. In that case, use
+ * gst_rtp_buffer_add_extension_onebyte_header()
+ *
+ * This function will not modify the data section of the RTP buffer, only
+ * the header.
+ *
+ * Returns: %TRUE if header extension could be added
+ *
+ * Since: 0.10.31
+ */
+
+gboolean
+gst_rtp_buffer_list_add_extension_twobytes_header (GstBufferListIterator * it,
+    guint8 appbits, guint8 id, gpointer data, guint size)
+{
+  GstBuffer *buffer;
+  guint16 bits;
+  guint8 *pdata;
+  guint wordlen;
+  gboolean retval;
+  guint endoffset;
+
+  g_return_val_if_fail ((appbits & 0xF0) == 0, FALSE);
+  g_return_val_if_fail (size < 256, FALSE);
+  g_return_val_if_fail (gst_buffer_list_iterator_n_buffers (it) == 1, FALSE);
+
+  buffer = gst_buffer_list_iterator_steal (it);
+
+  if (GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer))) {
+    gst_rtp_buffer_get_extension_data (buffer, &bits, (gpointer) & pdata,
+        &wordlen);
+
+    if (bits != ((0x100 << 4) | (appbits & 0x0f)))
+      return FALSE;
+
+    endoffset = get_twobytes_header_end_offset (pdata, wordlen);
+    if (endoffset == 0)
+      return FALSE;
+    endoffset += pdata - GST_BUFFER_DATA (buffer);
+  } else {
+    endoffset = GST_BUFFER_SIZE (buffer) + 4;
+  }
+
+  if (endoffset + size + 2 > GST_BUFFER_SIZE (buffer)) {
+    guint newsize;
+    GstBuffer *newbuffer;
+
+    newsize = endoffset + size + 2;
+    if (newsize % 4)
+      newsize += 4 - newsize % 4;
+    newbuffer = gst_buffer_new_and_alloc (newsize);
+    memcpy (GST_BUFFER_DATA (newbuffer), GST_BUFFER_DATA (buffer),
+        GST_BUFFER_SIZE (buffer));
+    gst_buffer_copy_metadata (newbuffer, buffer, GST_BUFFER_COPY_ALL);
+    gst_buffer_unref (buffer);
+    buffer = newbuffer;
+  } else {
+    buffer = gst_buffer_make_writable (buffer);
+  }
+
+  retval = gst_rtp_buffer_add_extension_twobytes_header (buffer, appbits, id,
+      data, size);
+
+  gst_buffer_list_iterator_take (it, buffer);
+
+  return retval;
+}
index a1e5ee6..064a908 100644 (file)
@@ -146,6 +146,17 @@ gboolean       gst_rtp_buffer_list_get_extension_twobytes_header (GstBufferList
                                                                   gpointer * data,
                                                                   guint * size);
 
+gboolean       gst_rtp_buffer_list_add_extension_onebyte_header (GstBufferListIterator * it,
+                                                                  guint8 id,
+                                                                  gpointer data,
+                                                                  guint size);
+gboolean       gst_rtp_buffer_list_add_extension_twobytes_header (GstBufferListIterator * it,
+                                                                  guint8 appbits,
+                                                                  guint8 id,
+                                                                  gpointer data,
+                                                                  guint size);
+
+
 G_END_DECLS
 
 #endif /* __GST_RTPBUFFER_H__ */