gst_plugins_base/gst-libs/gst/rtp/gstrtpbuffer.c
changeset 16 8e837d1bf446
parent 0 0e761a78d257
child 30 7e817e7e631c
--- a/gst_plugins_base/gst-libs/gst/rtp/gstrtpbuffer.c	Wed Mar 24 17:58:42 2010 -0500
+++ b/gst_plugins_base/gst-libs/gst/rtp/gstrtpbuffer.c	Wed Mar 24 18:04:17 2010 -0500
@@ -69,20 +69,19 @@
   guint8 csrclist[4];           /* optional CSRC list, 32 bits each */
 } GstRTPHeader;
 
-#define GST_RTP_HEADER_VERSION(buf)     (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->version)
-#define GST_RTP_HEADER_PADDING(buf)     (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->padding)
-#define GST_RTP_HEADER_EXTENSION(buf)   (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->extension)
-#define GST_RTP_HEADER_CSRC_COUNT(buf)  (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->csrc_count)
-#define GST_RTP_HEADER_MARKER(buf)      (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->marker)
-#define GST_RTP_HEADER_PAYLOAD_TYPE(buf)(((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->payload_type)
-#define GST_RTP_HEADER_SEQ(buf)         (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->seq)
-#define GST_RTP_HEADER_TIMESTAMP(buf)   (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->timestamp)
-#define GST_RTP_HEADER_SSRC(buf)        (((GstRTPHeader *)(GST_BUFFER_DATA (buf)))->ssrc)
-#define GST_RTP_HEADER_CSRC_LIST_OFFSET(buf,i)  \
-    GST_BUFFER_DATA (buf) +                     \
-    G_STRUCT_OFFSET(GstRTPHeader, csrclist) +   \
+#define GST_RTP_HEADER_VERSION(data)      (((GstRTPHeader *)(data))->version)
+#define GST_RTP_HEADER_PADDING(data)      (((GstRTPHeader *)(data))->padding)
+#define GST_RTP_HEADER_EXTENSION(data)    (((GstRTPHeader *)(data))->extension)
+#define GST_RTP_HEADER_CSRC_COUNT(data)   (((GstRTPHeader *)(data))->csrc_count)
+#define GST_RTP_HEADER_MARKER(data)       (((GstRTPHeader *)(data))->marker)
+#define GST_RTP_HEADER_PAYLOAD_TYPE(data) (((GstRTPHeader *)(data))->payload_type)
+#define GST_RTP_HEADER_SEQ(data)          (((GstRTPHeader *)(data))->seq)
+#define GST_RTP_HEADER_TIMESTAMP(data)    (((GstRTPHeader *)(data))->timestamp)
+#define GST_RTP_HEADER_SSRC(data)         (((GstRTPHeader *)(data))->ssrc)
+#define GST_RTP_HEADER_CSRC_LIST_OFFSET(data,i)        \
+    data + G_STRUCT_OFFSET(GstRTPHeader, csrclist) +   \
     ((i) * sizeof(guint32))
-#define GST_RTP_HEADER_CSRC_SIZE(buf)   (GST_RTP_HEADER_CSRC_COUNT(buf) * sizeof (guint32))
+#define GST_RTP_HEADER_CSRC_SIZE(data)   (GST_RTP_HEADER_CSRC_COUNT(data) * sizeof (guint32))
 
 /**
  * gst_rtp_buffer_allocate_data:
@@ -105,6 +104,7 @@
     guint8 pad_len, guint8 csrc_count)
 {
   guint len;
+  guint8 *data;
 
   g_return_if_fail (csrc_count <= 15);
   g_return_if_fail (GST_IS_BUFFER (buffer));
@@ -112,22 +112,23 @@
   len = GST_RTP_HEADER_LEN + csrc_count * sizeof (guint32)
       + payload_len + pad_len;
 
-  GST_BUFFER_MALLOCDATA (buffer) = g_malloc (len);
-  GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
+  data = g_malloc (len);
+  GST_BUFFER_MALLOCDATA (buffer) = data;
+  GST_BUFFER_DATA (buffer) = data;
   GST_BUFFER_SIZE (buffer) = len;
 
   /* fill in defaults */
-  GST_RTP_HEADER_VERSION (buffer) = GST_RTP_VERSION;
-  GST_RTP_HEADER_PADDING (buffer) = FALSE;
-  GST_RTP_HEADER_EXTENSION (buffer) = FALSE;
-  GST_RTP_HEADER_CSRC_COUNT (buffer) = csrc_count;
-  memset (GST_RTP_HEADER_CSRC_LIST_OFFSET (buffer, 0), 0,
+  GST_RTP_HEADER_VERSION (data) = GST_RTP_VERSION;
+  GST_RTP_HEADER_PADDING (data) = FALSE;
+  GST_RTP_HEADER_EXTENSION (data) = FALSE;
+  GST_RTP_HEADER_CSRC_COUNT (data) = csrc_count;
+  memset (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, 0), 0,
       csrc_count * sizeof (guint32));
-  GST_RTP_HEADER_MARKER (buffer) = FALSE;
-  GST_RTP_HEADER_PAYLOAD_TYPE (buffer) = 0;
-  GST_RTP_HEADER_SEQ (buffer) = 0;
-  GST_RTP_HEADER_TIMESTAMP (buffer) = 0;
-  GST_RTP_HEADER_SSRC (buffer) = 0;
+  GST_RTP_HEADER_MARKER (data) = FALSE;
+  GST_RTP_HEADER_PAYLOAD_TYPE (data) = 0;
+  GST_RTP_HEADER_SEQ (data) = 0;
+  GST_RTP_HEADER_TIMESTAMP (data) = 0;
+  GST_RTP_HEADER_SSRC (data) = 0;
 }
 
 /**
@@ -316,23 +317,18 @@
 }
 
 /**
- * gst_rtp_buffer_validate_data:
+ * validate_data:
  * @data: the data to validate
  * @len: the length of @data to validate
+ * @payload: the payload if @data represents the header only
+ * @payload_len: the len of the payload
  *
- * Check if the @data and @size point to the data of a valid RTP packet.
- * This function checks the length, version and padding of the packet data.
- * Use this function to validate a packet before using the other functions in
- * this module.
+ * Checks if @data is a valid RTP packet.
  *
- * Returns: TRUE if the data points to a valid RTP packet.
+ * Returns: TRUE if @data is a valid RTP packet
  */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-gboolean
-gst_rtp_buffer_validate_data (guint8 * data, guint len)
+static gboolean
+validate_data (guint8 * data, guint len, guint8 * payload, guint payload_len)
 {
   guint8 padding;
   guint8 csrc_count;
@@ -346,8 +342,8 @@
     goto wrong_length;
 
   /* check version */
-  version = (data[0] & 0xc0) >> 6;
-  if (G_UNLIKELY (version != GST_RTP_VERSION))
+  version = (data[0] & 0xc0);
+  if (G_UNLIKELY (version != (GST_RTP_VERSION << 6)))
     goto wrong_version;
 
   /* calc header length with csrc */
@@ -376,13 +372,17 @@
   }
 
   /* check for padding */
-  if (data[0] & 0x20)
-    padding = data[len - 1];
-  else
+  if (data[0] & 0x20) {
+    if (payload)
+      padding = payload[payload_len - 1];
+    else
+      padding = data[len - 1];
+  } else {
     padding = 0;
+  }
 
-  /* check if padding not bigger than packet and header */
-  if (G_UNLIKELY (len - header_len < padding))
+  /* check if padding and header not bigger than packet length */
+  if (G_UNLIKELY (len < padding + header_len))
     goto wrong_padding;
 
   return TRUE;
@@ -406,11 +406,35 @@
 }
 
 /**
+ * gst_rtp_buffer_validate_data:
+ * @data: the data to validate
+ * @len: the length of @data to validate
+ *
+ * Check if the @data and @size point to the data of a valid RTP packet.
+ * This function checks the length, version and padding of the packet data.
+ * Use this function to validate a packet before using the other functions in
+ * this module.
+ *
+ * Returns: TRUE if the data points to a valid RTP packet.
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+gboolean
+gst_rtp_buffer_validate_data (guint8 * data, guint len)
+{
+  return validate_data (data, len, NULL, 0);
+}
+
+/**
  * gst_rtp_buffer_validate:
  * @buffer: the buffer to validate
  *
  * Check if the data pointed to by @buffer is a valid RTP packet using
- * gst_rtp_buffer_validate_data().
+ * validate_data().
+ * Use this function to validate a packet before using the other functions in
+ * this module.
  *
  * Returns: TRUE if @buffer is a valid RTP packet.
  */
@@ -429,7 +453,99 @@
   data = GST_BUFFER_DATA (buffer);
   len = GST_BUFFER_SIZE (buffer);
 
-  return gst_rtp_buffer_validate_data (data, len);
+  return validate_data (data, len, NULL, 0);
+}
+
+/**
+ * gst_rtp_buffer_list_validate:
+ * @list: the buffer list to validate
+ *
+ * Check if all RTP packets in the @list are valid using validate_data().
+ * Use this function to validate an list before using the other functions in
+ * this module.
+ *
+ * Returns: TRUE if @list consists only of valid RTP packets.
+ *
+ * Since: 0.10.24
+ */
+ 
+ #ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+gboolean
+gst_rtp_buffer_list_validate (GstBufferList * list)
+{
+  guint16 prev_seqnum = 0;
+  GstBufferListIterator *it;
+  guint i = 0;
+
+  g_return_val_if_fail (GST_IS_BUFFER_LIST (list), FALSE);
+
+  it = gst_buffer_list_iterate (list);
+  g_return_val_if_fail (it != NULL, FALSE);
+
+  /* iterate through all the RTP packets in the list */
+  while (gst_buffer_list_iterator_next_group (it)) {
+    GstBuffer *rtpbuf;
+    GstBuffer *paybuf;
+    guint8 *packet_header;
+    guint8 *packet_payload;
+    guint payload_size;
+    guint packet_size;
+
+    /* each group should consists of 2 buffers: one containing the RTP header
+     * and the other one the payload, FIXME, relax the requirement of only one
+     * payload buffer. */
+    if (gst_buffer_list_iterator_n_buffers (it) != 2)
+      goto invalid_list;
+
+    /* get the RTP header */
+    rtpbuf = gst_buffer_list_iterator_next (it);
+    packet_header = GST_BUFFER_DATA (rtpbuf);
+    if (packet_header == NULL)
+      goto invalid_list;
+
+    /* get the payload */
+    paybuf = gst_buffer_list_iterator_next (it);
+    packet_payload = GST_BUFFER_DATA (paybuf);
+    if (packet_payload == NULL) {
+      goto invalid_list;
+    }
+    payload_size = GST_BUFFER_SIZE (paybuf);
+    if (payload_size == 0) {
+      goto invalid_list;
+    }
+
+    /* the size of the RTP packet within the current group */
+    packet_size = GST_BUFFER_SIZE (rtpbuf) + payload_size;
+
+    /* check the sequence number */
+    if (G_UNLIKELY (i == 0)) {
+      prev_seqnum = g_ntohs (GST_RTP_HEADER_SEQ (packet_header));
+      i++;
+    } else {
+      if (++prev_seqnum != g_ntohs (GST_RTP_HEADER_SEQ (packet_header)))
+        goto invalid_list;
+    }
+
+    /* validate packet */
+    if (!validate_data (packet_header, packet_size, packet_payload,
+            payload_size)) {
+      goto invalid_list;
+    }
+  }
+
+  gst_buffer_list_iterator_free (it);
+
+  return TRUE;
+
+  /* ERRORS */
+invalid_list:
+  {
+    gst_buffer_list_iterator_free (it);
+    return FALSE;
+  }
 }
 
 /**
@@ -448,22 +564,20 @@
 gst_rtp_buffer_set_packet_len (GstBuffer * buffer, guint len)
 {
   guint oldlen;
-
-  g_return_if_fail (GST_IS_BUFFER (buffer));
+  guint8 *data;
 
   oldlen = GST_BUFFER_SIZE (buffer);
+  data = GST_BUFFER_DATA (buffer);
 
   if (oldlen < len) {
-    guint8 *newdata;
-
-    newdata = g_realloc (GST_BUFFER_MALLOCDATA (buffer), len);
-    GST_BUFFER_MALLOCDATA (buffer) = newdata;
-    GST_BUFFER_DATA (buffer) = newdata;
+    data = g_realloc (GST_BUFFER_MALLOCDATA (buffer), len);
+    GST_BUFFER_MALLOCDATA (buffer) = data;
+    GST_BUFFER_DATA (buffer) = data;
   }
   GST_BUFFER_SIZE (buffer) = len;
 
   /* remove any padding */
-  GST_RTP_HEADER_PADDING (buffer) = FALSE;
+  GST_RTP_HEADER_PADDING (data) = FALSE;
 }
 
 /**
@@ -481,8 +595,6 @@
 guint
 gst_rtp_buffer_get_packet_len (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-
   return GST_BUFFER_SIZE (buffer);
 }
 
@@ -503,12 +615,13 @@
 gst_rtp_buffer_get_header_len (GstBuffer * buffer)
 {
   guint len;
+  guint8 *data;
 
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
+  data = GST_BUFFER_DATA (buffer);
 
-  len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (buffer);
-  if (GST_RTP_HEADER_EXTENSION (buffer))
-    len += GST_READ_UINT16_BE (GST_BUFFER_DATA (buffer) + len + 2) * 4 + 4;
+  len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
+  if (GST_RTP_HEADER_EXTENSION (data))
+    len += GST_READ_UINT16_BE (data + len + 2) * 4 + 4;
 
   return len;
 }
@@ -528,10 +641,7 @@
 guint8
 gst_rtp_buffer_get_version (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
-
-  return GST_RTP_HEADER_VERSION (buffer);
+  return GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer));
 }
 
 /**
@@ -548,11 +658,9 @@
 void
 gst_rtp_buffer_set_version (GstBuffer * buffer, guint8 version)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
   g_return_if_fail (version < 0x04);
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
 
-  GST_RTP_HEADER_VERSION (buffer) = version;
+  GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer)) = version;
 }
 
 /**
@@ -570,10 +678,7 @@
 gboolean
 gst_rtp_buffer_get_padding (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, FALSE);
-
-  return GST_RTP_HEADER_PADDING (buffer);
+  return GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer));
 }
 
 /**
@@ -590,10 +695,7 @@
 void
 gst_rtp_buffer_set_padding (GstBuffer * buffer, gboolean padding)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
-
-  GST_RTP_HEADER_PADDING (buffer) = padding;
+  GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer)) = padding;
 }
 
 /**
@@ -613,13 +715,14 @@
 void
 gst_rtp_buffer_pad_to (GstBuffer * buffer, guint len)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
+  guint8 *data;
+
+  data = GST_BUFFER_DATA (buffer);
 
   if (len > 0)
-    GST_RTP_HEADER_PADDING (buffer) = TRUE;
+    GST_RTP_HEADER_PADDING (data) = TRUE;
   else
-    GST_RTP_HEADER_PADDING (buffer) = FALSE;
+    GST_RTP_HEADER_PADDING (data) = FALSE;
 
   /* FIXME, set the padding byte at the end of the payload data */
 }
@@ -639,10 +742,7 @@
 gboolean
 gst_rtp_buffer_get_extension (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, FALSE);
-
-  return GST_RTP_HEADER_EXTENSION (buffer);
+  return GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer));
 }
 
 /**
@@ -659,10 +759,7 @@
 void
 gst_rtp_buffer_set_extension (GstBuffer * buffer, gboolean extension)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
-
-  GST_RTP_HEADER_EXTENSION (buffer) = extension;
+  GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer)) = extension;
 }
 
 /**
@@ -694,15 +791,14 @@
   guint len;
   guint8 *pdata;
 
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, FALSE);
+  pdata = GST_BUFFER_DATA (buffer);
 
-  if (!GST_RTP_HEADER_EXTENSION (buffer))
+  if (!GST_RTP_HEADER_EXTENSION (pdata))
     return FALSE;
 
   /* move to the extension */
-  len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (buffer);
-  pdata = GST_BUFFER_DATA (buffer) + len;
+  len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (pdata);
+  pdata += len;
 
   if (bits)
     *bits = GST_READ_UINT16_BE (pdata);
@@ -740,27 +836,32 @@
   guint32 min_size = 0;
   guint8 *data;
 
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, FALSE);
+  data = GST_BUFFER_DATA (buffer);
 
-  gst_rtp_buffer_set_extension (buffer, TRUE);
+  /* check if the buffer is big enough to hold the extension */
   min_size =
-      GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (buffer) + 4 +
+      GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data) + 4 +
       length * sizeof (guint32);
+  if (G_UNLIKELY (min_size > GST_BUFFER_SIZE (buffer)))
+    goto too_small;
+
+  /* now we can set the extension bit */
+  gst_rtp_buffer_set_extension (buffer, TRUE);
 
-  if (min_size > GST_BUFFER_SIZE (buffer)) {
-    GST_WARNING_OBJECT (buffer,
-        "rtp buffer too small: need more than %d bytes but only have %d bytes",
+  data += GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
+  GST_WRITE_UINT16_BE (data, bits);
+  GST_WRITE_UINT16_BE (data + 2, length);
+
+  return TRUE;
+
+  /* ERRORS */
+too_small:
+  {
+    g_warning
+        ("rtp buffer too small: need more than %d bytes but only have %d bytes",
         min_size, GST_BUFFER_SIZE (buffer));
     return FALSE;
   }
-
-  data =
-      GST_BUFFER_DATA (buffer) + GST_RTP_HEADER_LEN +
-      GST_RTP_HEADER_CSRC_SIZE (buffer);
-  GST_WRITE_UINT16_BE (data, bits);
-  GST_WRITE_UINT16_BE (data + 2, length);
-  return TRUE;
 }
 
 /**
@@ -778,10 +879,34 @@
 guint32
 gst_rtp_buffer_get_ssrc (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
+  return g_ntohl (GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)));
+}
 
-  return g_ntohl (GST_RTP_HEADER_SSRC (buffer));
+/**
+ * gst_rtp_buffer_list_get_ssrc:
+ * @list: the buffer list
+ *
+ * Get the SSRC of the first RTP packet in @list.
+ * All RTP packets within @list have the same SSRC.
+ *
+ * Returns: the SSRC of @list in host order.
+ *
+ * Since: 0.10.24
+ */
+ 
+ #ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+guint32
+gst_rtp_buffer_list_get_ssrc (GstBufferList * list)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_list_get (list, 0, 0);
+  g_return_val_if_fail (buffer != NULL, 0);
+
+  return g_ntohl (GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)));
 }
 
 /**
@@ -798,10 +923,32 @@
 void
 gst_rtp_buffer_set_ssrc (GstBuffer * buffer, guint32 ssrc)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
+  GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)) = g_htonl (ssrc);
+}
+
+static GstBufferListItem
+set_ssrc_header (GstBuffer ** buffer, guint group, guint idx, guint32 * ssrc)
+{
+  GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (*buffer)) = g_htonl (*ssrc);
+  return GST_BUFFER_LIST_SKIP_GROUP;
+}
 
-  GST_RTP_HEADER_SSRC (buffer) = g_htonl (ssrc);
+/**
+ * gst_rtp_buffer_list_set_ssrc:
+ * @list: the buffer list
+ * @ssrc: the new SSRC
+ *
+ * Set the SSRC on each RTP packet in @list to @ssrc.
+ *
+ * Since: 0.10.24
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+void
+gst_rtp_buffer_list_set_ssrc (GstBufferList * list, guint32 ssrc)
+{
+  gst_buffer_list_foreach (list, (GstBufferListFunc) set_ssrc_header, &ssrc);
 }
 
 /**
@@ -819,10 +966,7 @@
 guint8
 gst_rtp_buffer_get_csrc_count (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
-
-  return GST_RTP_HEADER_CSRC_COUNT (buffer);
+  return GST_RTP_HEADER_CSRC_COUNT (GST_BUFFER_DATA (buffer));
 }
 
 /**
@@ -841,11 +985,13 @@
 guint32
 gst_rtp_buffer_get_csrc (GstBuffer * buffer, guint8 idx)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
-  g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (buffer), 0);
+  guint8 *data;
+
+  data = GST_BUFFER_DATA (buffer);
 
-  return GST_READ_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (buffer, idx));
+  g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data), 0);
+
+  return GST_READ_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx));
 }
 
 /**
@@ -863,11 +1009,13 @@
 void
 gst_rtp_buffer_set_csrc (GstBuffer * buffer, guint8 idx, guint32 csrc)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
-  g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (buffer));
+  guint8 *data;
+
+  data = GST_BUFFER_DATA (buffer);
 
-  GST_WRITE_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (buffer, idx), csrc);
+  g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data));
+
+  GST_WRITE_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx), csrc);
 }
 
 /**
@@ -885,10 +1033,7 @@
 gboolean
 gst_rtp_buffer_get_marker (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, FALSE);
-
-  return GST_RTP_HEADER_MARKER (buffer);
+  return GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer));
 }
 
 /**
@@ -905,10 +1050,7 @@
 void
 gst_rtp_buffer_set_marker (GstBuffer * buffer, gboolean marker)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
-
-  GST_RTP_HEADER_MARKER (buffer) = marker;
+  GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer)) = marker;
 }
 
 /**
@@ -926,10 +1068,34 @@
 guint8
 gst_rtp_buffer_get_payload_type (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
+  return GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer));
+}
 
-  return GST_RTP_HEADER_PAYLOAD_TYPE (buffer);
+/**
+ * gst_rtp_buffer_list_get_payload_type:
+ * @list: the buffer list
+ *
+ * Get the payload type of the first RTP packet in @list.
+ * All packets in @list should have the same payload type.
+ *
+ * Returns: The payload type.
+ *
+ * Since: 0.10.24
+ */
+ 
+ #ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+guint8
+gst_rtp_buffer_list_get_payload_type (GstBufferList * list)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_list_get (list, 0, 0);
+  g_return_val_if_fail (buffer != NULL, 0);
+
+  return GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer));
 }
 
 /**
@@ -946,11 +1112,39 @@
 void
 gst_rtp_buffer_set_payload_type (GstBuffer * buffer, guint8 payload_type)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
   g_return_if_fail (payload_type < 0x80);
 
-  GST_RTP_HEADER_PAYLOAD_TYPE (buffer) = payload_type;
+  GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer)) = payload_type;
+}
+
+static GstBufferListItem
+set_pt_header (GstBuffer ** buffer, guint group, guint idx, guint8 * pt)
+{
+  GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (*buffer)) = *pt;
+  return GST_BUFFER_LIST_SKIP_GROUP;
+}
+
+/**
+ * gst_rtp_buffer_list_set_payload_type:
+ * @list: the buffer list
+ * @payload_type: the new type
+ *
+ * Set the payload type of each RTP packet in @list to @payload_type.
+ *
+ * Since: 0.10.24
+ */
+ 
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+ 
+void
+gst_rtp_buffer_list_set_payload_type (GstBufferList * list, guint8 payload_type)
+{
+  g_return_if_fail (payload_type < 0x80);
+
+  gst_buffer_list_foreach (list, (GstBufferListFunc) set_pt_header,
+      &payload_type);
 }
 
 /**
@@ -968,10 +1162,7 @@
 guint16
 gst_rtp_buffer_get_seq (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
-
-  return g_ntohs (GST_RTP_HEADER_SEQ (buffer));
+  return g_ntohs (GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)));
 }
 
 /**
@@ -988,13 +1179,69 @@
 void
 gst_rtp_buffer_set_seq (GstBuffer * buffer, guint16 seq)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
+  GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)) = g_htons (seq);
+}
+
+static GstBufferListItem
+set_seq_header (GstBuffer ** buffer, guint group, guint idx, guint16 * seq)
+{
+  GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (*buffer)) = g_htons (*seq);
+  (*seq)++;
+  return GST_BUFFER_LIST_SKIP_GROUP;
+}
+
+/**
+ * gst_rtp_buffer_list_set_seq:
+ * @list: the buffer list
+ * @seq: the new sequence number
+ *
+ * Set the sequence number of each RTP packet in @list to @seq.
+ *
+ * Returns: The seq number of the last packet in the list + 1.
+ *
+ * Since: 0.10.24
+ */
+ 
+ #ifdef __SYMBIAN32__
+EXPORT_C
+#endif
 
-  GST_RTP_HEADER_SEQ (buffer) = g_htons (seq);
+guint16
+gst_rtp_buffer_list_set_seq (GstBufferList * list, guint16 seq)
+{
+  gst_buffer_list_foreach (list, (GstBufferListFunc) set_seq_header, &seq);
+  return seq;
 }
 
 /**
+ * gst_rtp_buffer_list_get_seq:
+ * @list: the buffer list
+ *
+ * Get the sequence number of the first RTP packet in @list.
+ * All packets within @list have the same sequence number.
+ *
+ * Returns: The seq number
+ *
+ * Since: 0.10.24
+ */
+ 
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+ 
+guint16
+gst_rtp_buffer_list_get_seq (GstBufferList * list)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_list_get (list, 0, 0);
+  g_return_val_if_fail (buffer != NULL, 0);
+
+  return g_ntohl (GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)));
+}
+
+
+/**
  * gst_rtp_buffer_get_timestamp:
  * @buffer: the buffer
  *
@@ -1009,10 +1256,34 @@
 guint32
 gst_rtp_buffer_get_timestamp (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
+  return g_ntohl (GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)));
+}
 
-  return g_ntohl (GST_RTP_HEADER_TIMESTAMP (buffer));
+/**
+ * gst_rtp_buffer_list_get_timestamp:
+ * @list: the buffer list
+ *
+ * Get the timestamp of the first RTP packet in @list.
+ * All packets within @list have the same timestamp.
+ *
+ * Returns: The timestamp in host order.
+ *
+ * Since: 0.10.24
+ */
+ 
+ #ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+guint32
+gst_rtp_buffer_list_get_timestamp (GstBufferList * list)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_list_get (list, 0, 0);
+  g_return_val_if_fail (buffer != NULL, 0);
+
+  return g_ntohl (GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)));
 }
 
 /**
@@ -1029,10 +1300,37 @@
 void
 gst_rtp_buffer_set_timestamp (GstBuffer * buffer, guint32 timestamp)
 {
-  g_return_if_fail (GST_IS_BUFFER (buffer));
-  g_return_if_fail (GST_BUFFER_DATA (buffer) != NULL);
+  GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)) = g_htonl (timestamp);
+}
+
+
+static GstBufferListItem
+set_timestamp_header (GstBuffer ** buffer, guint group, guint idx,
+    guint32 * timestamp)
+{
+  GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (*buffer)) = g_htonl (*timestamp);
+  return GST_BUFFER_LIST_SKIP_GROUP;
+}
 
-  GST_RTP_HEADER_TIMESTAMP (buffer) = g_htonl (timestamp);
+/**
+ * gst_rtp_buffer_list_set_timestamp:
+ * @list: the buffer list
+ * @timestamp: the new timestamp
+ *
+ * Set the timestamp of each RTP packet in @list to @timestamp.
+ *
+ * Since: 0.10.24
+ */
+ 
+ #ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+void
+gst_rtp_buffer_list_set_timestamp (GstBufferList * list, guint32 timestamp)
+{
+  gst_buffer_list_foreach (list, (GstBufferListFunc) set_timestamp_header,
+      &timestamp);
 }
 
 /**
@@ -1059,15 +1357,10 @@
 {
   guint poffset, plen;
 
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, NULL);
-
   plen = gst_rtp_buffer_get_payload_len (buffer);
   /* we can't go past the length */
-  if (G_UNLIKELY (offset >= plen)) {
-    GST_WARNING ("offset=%u should be less then plen=%u", offset, plen);
-    return (NULL);
-  }
+  if (G_UNLIKELY (offset >= plen))
+    goto wrong_offset;
 
   /* apply offset */
   poffset = gst_rtp_buffer_get_header_len (buffer) + offset;
@@ -1078,6 +1371,13 @@
     plen = len;
 
   return gst_buffer_create_sub (buffer, poffset, plen);
+
+  /* ERRORS */
+wrong_offset:
+  {
+    g_warning ("offset=%u should be less then plen=%u", offset, plen);
+    return NULL;
+  }
 }
 
 /**
@@ -1116,16 +1416,58 @@
 gst_rtp_buffer_get_payload_len (GstBuffer * buffer)
 {
   guint len, size;
-
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);
+  guint8 *data;
 
   size = GST_BUFFER_SIZE (buffer);
+  data = GST_BUFFER_DATA (buffer);
 
   len = size - gst_rtp_buffer_get_header_len (buffer);
 
-  if (GST_RTP_HEADER_PADDING (buffer))
-    len -= GST_BUFFER_DATA (buffer)[size - 1];
+  if (GST_RTP_HEADER_PADDING (data))
+    len -= data[size - 1];
+
+  return len;
+}
+
+/**
+ * gst_rtp_buffer_list_get_payload_len:
+ * @list: the buffer list
+ *
+ * Get the length of the payload of the RTP packet in @list.
+ *
+ * Returns: The length of the payload in @list.
+ *
+ * Since: 0.10.24
+ */
+ 
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+ 
+guint
+gst_rtp_buffer_list_get_payload_len (GstBufferList * list)
+{
+  guint len;
+  GstBufferListIterator *it;
+
+  it = gst_buffer_list_iterate (list);
+  len = 0;
+
+  while (gst_buffer_list_iterator_next_group (it)) {
+    guint i;
+    GstBuffer *buf;
+
+    i = 0;
+    while ((buf = gst_buffer_list_iterator_next (it))) {
+      /* skip the RTP header */
+      if (!i++)
+        continue;
+      /* take the size of the current buffer */
+      len += GST_BUFFER_SIZE (buf);
+    }
+  }
+
+  gst_buffer_list_iterator_free (it);
 
   return len;
 }
@@ -1146,9 +1488,6 @@
 gpointer
 gst_rtp_buffer_get_payload (GstBuffer * buffer)
 {
-  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
-  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, NULL);
-
   return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer);
 }
 
@@ -1190,10 +1529,11 @@
  * @seqnum1: a sequence number
  * @seqnum2: a sequence number
  *
- * Compare two sequence numbers, taking care of wraparounds.
+ * Compare two sequence numbers, taking care of wraparounds. This function
+ * returns the difference between @seqnum1 and @seqnum2.
  *
- * Returns: -1 if @seqnum1 is before @seqnum2, 0 if they are equal or 1 if
- * @seqnum1 is bigger than @segnum2.
+ * Returns: a negative value if @seqnum1 is bigger than @seqnum2, 0 if they
+ * are equal or a positive value if @seqnum1 is smaller than @segnum2.
  *
  * Since: 0.10.15
  */
@@ -1204,13 +1544,7 @@
 gint
 gst_rtp_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
 {
-  /* check if diff more than half of the 16bit range */
-  if (abs (seqnum2 - seqnum1) > (1 << 15)) {
-    /* one of a/b has wrapped */
-    return seqnum1 - seqnum2;
-  } else {
-    return seqnum2 - seqnum1;
-  }
+  return (gint16) (seqnum2 - seqnum1);
 }
 
 /**