Add RTCP docs.
authorWim Taymans <wim.taymans@gmail.com>
Thu, 29 Mar 2007 16:20:31 +0000 (16:20 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Thu, 29 Mar 2007 16:20:31 +0000 (16:20 +0000)
Original commit message from CVS:
* docs/libs/gst-plugins-base-libs-docs.sgml:
* docs/libs/gst-plugins-base-libs-sections.txt:
* gst-libs/gst/rtp/gstbasertpaudiopayload.c:
(gst_base_rtp_audio_payload_get_adapter):
Add RTCP docs.
Fix some more docs.
* gst-libs/gst/rtp/Makefile.am:
* gst-libs/gst/rtp/gstrtcpbuffer.c:
(gst_rtcp_buffer_new_take_data), (gst_rtcp_buffer_new_copy_data),
(gst_rtcp_buffer_validate_data), (gst_rtcp_buffer_validate),
(gst_rtcp_buffer_get_packet_count), (read_packet_header),
(gst_rtcp_buffer_get_first_packet), (gst_rtcp_packet_move_to_next),
(gst_rtcp_buffer_add_packet), (gst_rtcp_packet_remove),
(gst_rtcp_packet_get_padding), (gst_rtcp_packet_get_type),
(gst_rtcp_packet_get_count), (gst_rtcp_packet_get_length),
(gst_rtcp_packet_sr_get_sender_info),
(gst_rtcp_packet_sr_set_sender_info),
(gst_rtcp_packet_rr_get_ssrc), (gst_rtcp_packet_rr_set_ssrc),
(gst_rtcp_packet_get_rb_count), (gst_rtcp_packet_get_rb),
(gst_rtcp_packet_add_rb), (gst_rtcp_packet_set_rb),
(gst_rtcp_packet_sdes_get_chunk_count),
(gst_rtcp_packet_sdes_first_chunk),
(gst_rtcp_packet_sdes_next_chunk), (gst_rtcp_packet_sdes_get_ssrc),
(gst_rtcp_packet_sdes_first_item),
(gst_rtcp_packet_sdes_next_item), (gst_rtcp_packet_sdes_get_item),
(gst_rtcp_packet_bye_get_ssrc_count),
(gst_rtcp_packet_bye_get_nth_ssrc), (gst_rtcp_packet_bye_add_ssrc),
(gst_rtcp_packet_bye_add_ssrcs), (get_reason_offset),
(gst_rtcp_packet_bye_get_reason_len),
(gst_rtcp_packet_bye_get_reason), (gst_rtcp_packet_bye_set_reason):
* gst-libs/gst/rtp/gstrtcpbuffer.h:
Add new helper object for parsing and creating RTCP messages.

ChangeLog
docs/libs/gst-plugins-base-libs-docs.sgml
docs/libs/gst-plugins-base-libs-sections.txt
gst-libs/gst/rtp/Makefile.am
gst-libs/gst/rtp/gstbasertpaudiopayload.c
gst-libs/gst/rtp/gstrtcpbuffer.c [new file with mode: 0644]
gst-libs/gst/rtp/gstrtcpbuffer.h [new file with mode: 0644]

index 2173925..7aff435 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2007-03-29  Wim Taymans  <wim@fluendo.com>
+
+       * docs/libs/gst-plugins-base-libs-docs.sgml:
+       * docs/libs/gst-plugins-base-libs-sections.txt:
+       * gst-libs/gst/rtp/gstbasertpaudiopayload.c:
+       (gst_base_rtp_audio_payload_get_adapter):
+       Add RTCP docs.
+       Fix some more docs.
+
+       * gst-libs/gst/rtp/Makefile.am:
+       * gst-libs/gst/rtp/gstrtcpbuffer.c:
+       (gst_rtcp_buffer_new_take_data), (gst_rtcp_buffer_new_copy_data),
+       (gst_rtcp_buffer_validate_data), (gst_rtcp_buffer_validate),
+       (gst_rtcp_buffer_get_packet_count), (read_packet_header),
+       (gst_rtcp_buffer_get_first_packet), (gst_rtcp_packet_move_to_next),
+       (gst_rtcp_buffer_add_packet), (gst_rtcp_packet_remove),
+       (gst_rtcp_packet_get_padding), (gst_rtcp_packet_get_type),
+       (gst_rtcp_packet_get_count), (gst_rtcp_packet_get_length),
+       (gst_rtcp_packet_sr_get_sender_info),
+       (gst_rtcp_packet_sr_set_sender_info),
+       (gst_rtcp_packet_rr_get_ssrc), (gst_rtcp_packet_rr_set_ssrc),
+       (gst_rtcp_packet_get_rb_count), (gst_rtcp_packet_get_rb),
+       (gst_rtcp_packet_add_rb), (gst_rtcp_packet_set_rb),
+       (gst_rtcp_packet_sdes_get_chunk_count),
+       (gst_rtcp_packet_sdes_first_chunk),
+       (gst_rtcp_packet_sdes_next_chunk), (gst_rtcp_packet_sdes_get_ssrc),
+       (gst_rtcp_packet_sdes_first_item),
+       (gst_rtcp_packet_sdes_next_item), (gst_rtcp_packet_sdes_get_item),
+       (gst_rtcp_packet_bye_get_ssrc_count),
+       (gst_rtcp_packet_bye_get_nth_ssrc), (gst_rtcp_packet_bye_add_ssrc),
+       (gst_rtcp_packet_bye_add_ssrcs), (get_reason_offset),
+       (gst_rtcp_packet_bye_get_reason_len),
+       (gst_rtcp_packet_bye_get_reason), (gst_rtcp_packet_bye_set_reason):
+       * gst-libs/gst/rtp/gstrtcpbuffer.h:
+       Add new helper object for parsing and creating RTCP messages.
+
 2007-03-29  Sebastian Dröge  <slomo@circular-chaos.org>
 
        * gst-libs/gst/riff/riff-media.c: (gst_riff_create_audio_caps):
index 1ef1fed..6f3ce40 100644 (file)
@@ -41,6 +41,7 @@
 <!ENTITY GstBaseRtpDepayload SYSTEM "xml/gstbasertpdepayload.xml">
 <!ENTITY GstBaseRtpPayload SYSTEM "xml/gstbasertppayload.xml">
 <!ENTITY GstRtpBuffer SYSTEM "xml/gstrtpbuffer.xml">
+<!ENTITY GstRtcpBuffer SYSTEM "xml/gstrtcpbuffer.xml">
 <!-- tag -->
 <!ENTITY GstTag SYSTEM "xml/gsttag.xml">
 <!ENTITY GstTagVorbis SYSTEM "xml/gsttagvorbis.xml">
       &GstBaseRtpDepayload;
       &GstBaseRtpPayload;
       &GstRtpBuffer;
+      &GstRtcpBuffer;
     </chapter>
 
     <chapter id="gstreamer-tag">
index fdca573..ec065b0 100644 (file)
@@ -93,6 +93,7 @@ GST_AUDIO_SRC_GET_CLASS
 <INCLUDE>gst/audio/gstbaseaudiosink.h</INCLUDE>
 GstBaseAudioSink
 GstBaseAudioSinkClass
+GstBaseAudioSinkSlaveMethod
 
 GST_BASE_AUDIO_SINK_CLOCK
 GST_BASE_AUDIO_SINK_PAD
@@ -105,6 +106,7 @@ gst_base_audio_sink_get_type
 GST_BASE_AUDIO_SINK_CLASS
 GST_IS_BASE_AUDIO_SINK_CLASS
 GST_BASE_AUDIO_SINK_GET_CLASS
+GstBaseAudioSinkPrivate
 </SECTION>
 
 <SECTION>
@@ -745,6 +747,8 @@ gst_base_rtp_audio_payload_set_frame_based
 gst_base_rtp_audio_payload_set_frame_options
 gst_base_rtp_audio_payload_set_sample_based
 gst_base_rtp_audio_payload_set_sample_options
+gst_base_rtp_audio_payload_get_adapter
+gst_base_rtp_audio_payload_push
 <SUBSECTION Standard>
 GST_TYPE_BASE_RTP_AUDIO_PAYLOAD
 GST_BASE_RTP_AUDIO_PAYLOAD
@@ -752,6 +756,7 @@ GST_BASE_RTP_AUDIO_PAYLOAD_CLASS
 GST_IS_BASE_RTP_AUDIO_PAYLOAD
 GST_IS_BASE_RTP_AUDIO_PAYLOAD_CLASS
 gst_base_rtp_audio_payload_get_type
+GstBaseRTPAudioPayloadPrivate
 </SECTION>
 
 <SECTION>
@@ -763,7 +768,11 @@ GstBaseRTPDepayloadClass
 GST_BASE_RTP_DEPAYLOAD_SINKPAD
 GST_BASE_RTP_DEPAYLOAD_SRCPAD
 
+gst_base_rtp_depayload_push
+gst_base_rtp_depayload_push_ts
+
 <SUBSECTION Standard>
+GstBaseRTPDepayloadPrivate
 GST_TYPE_BASE_RTP_DEPAYLOAD
 GST_BASE_RTP_DEPAYLOAD
 GST_BASE_RTP_DEPAYLOAD_CLASS
@@ -799,6 +808,58 @@ gst_basertppayload_get_type
 </SECTION>
 
 <SECTION>
+<FILE>gstrtcpbuffer</FILE>
+<INCLUDE>gst/rtp/gstrtcpbuffer.h</INCLUDE>
+
+GST_RTCP_VERSION
+
+GST_RTCP_MAX_SDES
+GST_RTCP_VALID_MASK
+GST_RTCP_VALID_VALUE
+
+GstRTCPType
+GstRTCPPacket
+GstRTCPSDESType
+
+gst_rtcp_buffer_add_packet
+gst_rtcp_buffer_get_first_packet
+gst_rtcp_buffer_get_packet_count
+gst_rtcp_buffer_new_copy_data
+gst_rtcp_buffer_new_take_data
+gst_rtcp_buffer_validate
+gst_rtcp_buffer_validate_data
+gst_rtcp_packet_add_rb
+gst_rtcp_packet_bye_add_ssrc
+gst_rtcp_packet_bye_add_ssrcs
+gst_rtcp_packet_bye_get_nth_ssrc
+gst_rtcp_packet_bye_get_reason
+gst_rtcp_packet_bye_get_reason_len
+gst_rtcp_packet_bye_get_ssrc_count
+gst_rtcp_packet_bye_set_reason
+gst_rtcp_packet_get_count
+gst_rtcp_packet_get_length
+gst_rtcp_packet_get_padding
+gst_rtcp_packet_get_rb
+gst_rtcp_packet_get_rb_count
+gst_rtcp_packet_get_type
+gst_rtcp_packet_move_to_next
+gst_rtcp_packet_remove
+gst_rtcp_packet_rr_get_ssrc
+gst_rtcp_packet_rr_set_ssrc
+gst_rtcp_packet_sdes_first_chunk
+gst_rtcp_packet_sdes_first_item
+gst_rtcp_packet_sdes_get_chunk_count
+gst_rtcp_packet_sdes_get_item
+gst_rtcp_packet_sdes_get_ssrc
+gst_rtcp_packet_sdes_next_chunk
+gst_rtcp_packet_sdes_next_item
+gst_rtcp_packet_set_rb
+gst_rtcp_packet_sr_get_sender_info
+gst_rtcp_packet_sr_set_sender_info
+<SUBSECTION Standard>
+</SECTION>
+
+<SECTION>
 <FILE>gstrtpbuffer</FILE>
 <INCLUDE>gst/rtp/gstrtpbuffer.h</INCLUDE>
 GstRTPPayload
@@ -809,6 +870,7 @@ gst_rtp_buffer_allocate_data
 gst_rtp_buffer_calc_header_len
 gst_rtp_buffer_calc_packet_len
 gst_rtp_buffer_calc_payload_len
+gst_rtp_buffer_default_clock_rate
 gst_rtp_buffer_get_csrc
 gst_rtp_buffer_get_csrc_count
 gst_rtp_buffer_get_extension
@@ -857,6 +919,26 @@ GST_RTP_PAYLOAD_PCMA_STRING
 GST_RTP_PAYLOAD_PCMU_STRING
 GST_RTP_PAYLOAD_TS41_STRING
 GST_RTP_PAYLOAD_TS48_STRING
+GST_RTP_PAYLOAD_1016_STRING
+GST_RTP_PAYLOAD_CELLB_STRING
+GST_RTP_PAYLOAD_CN_STRING
+GST_RTP_PAYLOAD_DVI4_11025_STRING
+GST_RTP_PAYLOAD_DVI4_16000_STRING
+GST_RTP_PAYLOAD_DVI4_22050_STRING
+GST_RTP_PAYLOAD_DVI4_8000_STRING
+GST_RTP_PAYLOAD_G721_STRING
+GST_RTP_PAYLOAD_G722_STRING
+GST_RTP_PAYLOAD_G723_53
+GST_RTP_PAYLOAD_G723_63
+GST_RTP_PAYLOAD_G723_STRING
+GST_RTP_PAYLOAD_H261_STRING
+GST_RTP_PAYLOAD_JPEG_STRING
+GST_RTP_PAYLOAD_LPC_STRING
+GST_RTP_PAYLOAD_MP2T_STRING
+GST_RTP_PAYLOAD_NV_STRING
+GST_RTP_PAYLOAD_QCELP_STRING
+GST_RTP_PAYLOAD_TS41
+GST_RTP_PAYLOAD_TS48
 </SECTION>
 
 # tag
index e0d9d60..32d642c 100644 (file)
@@ -1,6 +1,7 @@
 libgstrtpincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtp
 
 libgstrtpinclude_HEADERS = gstrtpbuffer.h \
+                          gstrtcpbuffer.h \
                        gstbasertpaudiopayload.h \
                        gstbasertppayload.h \
                        gstbasertpdepayload.h
@@ -8,6 +9,7 @@ libgstrtpinclude_HEADERS = gstrtpbuffer.h \
 lib_LTLIBRARIES = libgstrtp-@GST_MAJORMINOR@.la
 
 libgstrtp_@GST_MAJORMINOR@_la_SOURCES = gstrtpbuffer.c \
+                               gstrtcpbuffer.c \
                                gstbasertpaudiopayload.c \
                                gstbasertppayload.c \
                                gstbasertpdepayload.c
index f683b0c..14ec4aa 100644 (file)
@@ -598,6 +598,19 @@ gst_base_rtp_audio_payload_handle_sample_based_buffer (GstBaseRTPPayload *
   return ret;
 }
 
+/**
+ * gst_base_rtp_audio_payload_push:
+ * @basepayload: a #GstBaseRTPPayload
+ * @data: data to set as payload
+ * @payload_len: length of payload
+ * @timestamp: a #GstClockTime
+ *
+ * Create an RTP buffer and store @payload_len bytes of @data as the
+ * payload. Set the timestamp on the new buffer to @timestamp before pushing
+ * the buffer downstream.
+ *
+ * Returns: a #GstFlowReturn
+ */
 GstFlowReturn
 gst_base_rtp_audio_payload_push (GstBaseRTPPayload * basepayload,
     const guint8 * data, guint payload_len, GstClockTime timestamp)
@@ -712,14 +725,22 @@ gst_base_rtp_payload_audio_handle_event (GstPad * pad, GstEvent * event,
   return res;
 }
 
+/**
+ * gst_base_rtp_audio_payload_get_adapter:
+ * @basertpaudiopayload: a #GstBaseRTPAudioPayload
+ *
+ * Gets the internal adapter used by the depayloader.
+ *
+ * Returns: a #GstAdapter.
+ */
 GstAdapter *
 gst_base_rtp_audio_payload_get_adapter (GstBaseRTPAudioPayload
     * basertpaudiopayload)
 {
-  if (basertpaudiopayload->priv->adapter == NULL) {
-    return NULL;
-  }
+  GstAdapter *adapter;
+
+  if ((adapter = basertpaudiopayload->priv->adapter))
+    g_object_ref (adapter);
 
-  g_object_ref (G_OBJECT (basertpaudiopayload->priv->adapter));
-  return basertpaudiopayload->priv->adapter;
+  return adapter;
 }
diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.c b/gst-libs/gst/rtp/gstrtcpbuffer.c
new file mode 100644 (file)
index 0000000..e3b6c0f
--- /dev/null
@@ -0,0 +1,1182 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim@fluendo.com>
+ *
+ * gstrtcpbuffer.h: various helper functions to manipulate buffers
+ *     with RTCP payload.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gstrtcpbuffer
+ * @short_description: Helper methods for dealing with RTCP buffers
+ * @see_also: gstbasertppayload, gstbasertpdepayload
+ *
+ * Note: The API in this module is not yet declared stable.
+ *
+ * <refsect2>
+ * <para>
+ * The GstRTPCBuffer helper functions makes it easy to parse and create regular 
+ * #GstBuffer objects that contain compound RTCP packets. These buffers are typically
+ * of 'application/x-rtcp' #GstCaps.
+ * </para>
+ * <para>
+ * An RTCP buffer consists of 1 or more #GstRTCPPacket structures that you can
+ * retrieve with gst_rtcp_buffer_get_first_packet(). #GstRTCPPacket acts as a pointer
+ * into the RTCP buffer; you can move to the next packet with
+ * gst_rtcp_packet_move_to_next().
+ * </para>
+ * </refsect2>
+ *
+ * Since: 0.10.13
+ *
+ * Last reviewed on 2007-03-26 (0.10.13)
+ */
+
+#include "gstrtcpbuffer.h"
+
+/**
+ * gst_rtcp_buffer_new_take_data:
+ * @data: data for the new buffer
+ * @len: the length of data
+ *
+ * Create a new buffer and set the data and size of the buffer to @data and @len
+ * respectively. @data will be freed when the buffer is unreffed, so this
+ * function transfers ownership of @data to the new buffer.
+ *
+ * Returns: A newly allocated buffer with @data and of size @len.
+ */
+GstBuffer *
+gst_rtcp_buffer_new_take_data (gpointer data, guint len)
+{
+  GstBuffer *result;
+
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail (len > 0, NULL);
+
+  result = gst_buffer_new ();
+
+  GST_BUFFER_MALLOCDATA (result) = data;
+  GST_BUFFER_DATA (result) = data;
+  GST_BUFFER_SIZE (result) = len;
+
+  return result;
+}
+
+/**
+ * gst_rtcp_buffer_new_copy_data:
+ * @data: data for the new buffer
+ * @len: the length of data
+ *
+ * Create a new buffer and set the data to a copy of @len
+ * bytes of @data and the size to @len. The data will be freed when the buffer
+ * is freed.
+ *
+ * Returns: A newly allocated buffer with a copy of @data and of size @len.
+ */
+GstBuffer *
+gst_rtcp_buffer_new_copy_data (gpointer data, guint len)
+{
+  return gst_rtcp_buffer_new_take_data (g_memdup (data, len), len);
+}
+
+/**
+ * gst_rtcp_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 RTCP (compound)
+ * packet. 
+ * Use this function to validate a packet before using the other functions in
+ * this module.
+ *
+ * Returns: TRUE if the data points to a valid RTCP packet.
+ */
+gboolean
+gst_rtcp_buffer_validate_data (guint8 * data, guint len)
+{
+  guint16 header_mask;
+  guint16 header_len;
+  guint8 version;
+  guint data_len;
+  gboolean padding;
+  guint8 pad_bytes;
+
+  g_return_val_if_fail (data != NULL, FALSE);
+
+  /* we need 4 bytes for the type and length */
+  if (G_UNLIKELY (len < 4))
+    goto wrong_length;
+
+  /* first packet must be RR or SR  and version must be 2 */
+  header_mask = ((data[0] << 8) | data[1]) & GST_RTCP_VALID_MASK;
+  if (G_UNLIKELY (header_mask != GST_RTCP_VALID_VALUE))
+    goto wrong_mask;
+
+  /* no padding when mask succeeds */
+  padding = FALSE;
+
+  /* store len */
+  data_len = len;
+
+  while (TRUE) {
+    /* get packet length */
+    header_len = (((data[2] << 8) | data[3]) + 1) << 2;
+    if (data_len < header_len)
+      goto wrong_length;
+
+    /* move to next compount packet */
+    data += header_len;
+    data_len -= header_len;
+
+    /* we are at the end now */
+    if (data_len < 4)
+      break;
+
+    /* check version of new packet */
+    version = data[0] & 0xc0;
+    if (version != (GST_RTCP_VERSION << 6))
+      goto wrong_version;
+
+    /* padding only allowed on last packet */
+    if ((padding = data[0] & 0x20))
+      break;
+  }
+  if (data_len > 0) {
+    /* some leftover bytes, check padding */
+    if (!padding)
+      goto wrong_length;
+
+    /* get padding */
+    pad_bytes = data[len - 1];
+    if (data_len != pad_bytes)
+      goto wrong_padding;
+  }
+  return TRUE;
+
+  /* ERRORS */
+wrong_length:
+  {
+    GST_DEBUG ("len check failed");
+    return FALSE;
+  }
+wrong_mask:
+  {
+    GST_DEBUG ("mask check failed (%04x != %04x)", header_mask,
+        GST_RTCP_VALID_VALUE);
+    return FALSE;
+  }
+wrong_version:
+  {
+    GST_DEBUG ("wrong version (%d < 2)", version >> 6);
+    return FALSE;
+  }
+wrong_padding:
+  {
+    GST_DEBUG ("padding check failed");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_rtcp_buffer_validate:
+ * @buffer: the buffer to validate
+ *
+ * Check if the data pointed to by @buffer is a valid RTCP packet using
+ * gst_rtcp_buffer_validate_data().
+ *  
+ * Returns: TRUE if @buffer is a valid RTCP packet.
+ */
+gboolean
+gst_rtcp_buffer_validate (GstBuffer * buffer)
+{
+  guint8 *data;
+  guint len;
+
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+
+  data = GST_BUFFER_DATA (buffer);
+  len = GST_BUFFER_SIZE (buffer);
+
+  return gst_rtcp_buffer_validate_data (data, len);
+}
+
+/**
+ * gst_rtcp_buffer_get_packet_count:
+ * @buffer: a valid RTCP buffer
+ *
+ * Get the number of RTCP packets in @buffer.
+ *
+ * Returns: the number of RTCP packets in @buffer.
+ */
+guint
+gst_rtcp_buffer_get_packet_count (GstBuffer * buffer)
+{
+  GstRTCPPacket packet;
+  guint count;
+
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
+
+  count = gst_rtcp_buffer_get_first_packet (buffer, &packet);
+  while (gst_rtcp_packet_move_to_next (&packet))
+    count++;
+
+  return count;
+}
+
+/**
+ * read_packet_header:
+ * @packet: a packet
+ *
+ * Read the packet headers for the packet pointed to by @packet.
+ *
+ * Returns: TRUE if @packet pointed to a valid header.
+ */
+static gboolean
+read_packet_header (GstRTCPPacket * packet)
+{
+  guint8 *data;
+  guint size;
+  guint offset;
+
+  g_return_val_if_fail (packet != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
+
+  data = GST_BUFFER_DATA (packet->buffer);
+  size = GST_BUFFER_SIZE (packet->buffer);
+
+  offset = packet->offset;
+
+  /* check if we are at the end of the buffer, we add 4 because we also want to
+   * ensure we can read the header. */
+  if (offset + 4 > size)
+    return FALSE;
+
+  if ((data[offset] & 0xc0) != (GST_RTCP_VERSION << 6))
+    return FALSE;
+
+  /* read count, type and length */
+  packet->padding = (data[offset] & 0x20) == 0x20;
+  packet->count = data[offset] & 0x1f;
+  packet->type = data[offset + 1];
+  packet->length = (data[offset + 2] << 8) | data[offset + 3];
+  packet->chunk_offset = 4;
+  packet->item_offset = 4;
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_buffer_get_first_packet:
+ * @buffer: a valid RTCP buffer
+ * @packet: a #GstRTCPPacket
+ *
+ * Initialize a new #GstRTCPPacket pointer that points to the first packet in
+ * @buffer.
+ *
+ * Returns: TRUE if the packet existed in @buffer.
+ */
+gboolean
+gst_rtcp_buffer_get_first_packet (GstBuffer * buffer, GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+  g_return_val_if_fail (packet != NULL, FALSE);
+
+  /* init to 0 */
+  packet->buffer = buffer;
+  packet->offset = 0;
+  packet->type = GST_RTCP_TYPE_INVALID;
+
+  if (!read_packet_header (packet))
+    return FALSE;
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_move_to_next:
+ * @packet: a #GstRTCPPacket
+ *
+ * Move the packet pointer @packet to the next packet in the payload.
+ * Use gst_rtcp_buffer_get_first_packet() to initialize @packet.
+ *
+ * Returns: TRUE if @packet is pointing to a valid packet after calling this
+ * function.
+ */
+gboolean
+gst_rtcp_packet_move_to_next (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, FALSE);
+  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
+
+  /* if we have a padding packet, it must be the last, set pointer to end of
+   * buffer and return FALSE */
+  if (packet->padding)
+    goto end;
+
+  /* move to next packet. Add 4 because the header is not included in length */
+  packet->offset += (packet->length << 2) + 4;
+
+  /* try to read new header */
+  if (!read_packet_header (packet))
+    goto end;
+
+  return TRUE;
+
+  /* ERRORS */
+end:
+  {
+    packet->type = GST_RTCP_TYPE_INVALID;
+    packet->offset = GST_BUFFER_SIZE (packet->buffer);
+    return FALSE;
+  }
+}
+
+/**
+ * gst_rtcp_buffer_add_packet:
+ * @buffer: a valid RTCP buffer
+ * @type: the #GstRTCPType of the new packet
+ * @packet: pointer to new packet
+ *
+ * Add a new packet of @type to @buffer. @packet will point to the newly created 
+ * packet.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_buffer_add_packet (GstBuffer * buffer, GstRTCPType type,
+    GstRTCPPacket * packet)
+{
+  g_return_if_fail (GST_IS_BUFFER (buffer));
+  g_return_if_fail (type != GST_RTCP_TYPE_INVALID);
+  g_return_if_fail (packet != NULL);
+
+  g_warning ("not implemented");
+}
+
+/**
+ * gst_rtcp_packet_remove:
+ * @packet: a #GstRTCPPacket
+ *
+ * Removes the packet pointed to by @packet.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_packet_remove (GstRTCPPacket * packet)
+{
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type != GST_RTCP_TYPE_INVALID);
+
+  g_warning ("not implemented");
+}
+
+/**
+ * gst_rtcp_packet_get_padding:
+ * @packet: a valid #GstRTCPPacket
+ *
+ * Get the packet padding of the packet pointed to by @packet.
+ *
+ * Returns: If the packet has the padding bit set.
+ */
+gboolean
+gst_rtcp_packet_get_padding (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, FALSE);
+  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
+
+  return packet->padding;
+}
+
+/**
+ * gst_rtcp_packet_get_type:
+ * @packet: a valid #GstRTCPPacket
+ *
+ * Get the packet type of the packet pointed to by @packet.
+ *
+ * Returns: The packet type.
+ */
+GstRTCPType
+gst_rtcp_packet_get_type (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, GST_RTCP_TYPE_INVALID);
+  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID,
+      GST_RTCP_TYPE_INVALID);
+
+  return packet->type;
+}
+
+/**
+ * gst_rtcp_packet_get_count:
+ * @packet: a valid #GstRTCPPacket
+ *
+ * Get the count field in @packet.
+ *
+ * Returns: The count field in @packet or -1 if @packet does not point to a
+ * valid packet.
+ */
+guint8
+gst_rtcp_packet_get_count (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, -1);
+  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, -1);
+
+  return packet->count;
+}
+
+/**
+ * gst_rtcp_packet_get_length:
+ * @packet: a valid #GstRTCPPacket
+ *
+ * Get the length field of @packet. This is the length of the packet in 
+ * 32-bit words minus one.
+ *
+ * Returns: The length field of @packet.
+ */
+guint16
+gst_rtcp_packet_get_length (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, 0);
+
+  return packet->length;
+}
+
+/**
+ * gst_rtcp_packet_sr_get_sender_info:
+ * @packet: a valid SR #GstRTCPPacket
+ * @ssrc: result SSRC
+ * @ntptime: result NTP time
+ * @rtptime: result RTP time
+ * @packet_count: result packet count
+ * @octet_count: result octect count
+ *
+ * Parse the SR sender info and store the values.
+ */
+void
+gst_rtcp_packet_sr_get_sender_info (GstRTCPPacket * packet, guint32 * ssrc,
+    guint64 * ntptime, guint32 * rtptime, guint32 * packet_count,
+    guint32 * octet_count)
+{
+  guint8 *data;
+
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  data = GST_BUFFER_DATA (packet->buffer);
+
+  /* skip header */
+  data += packet->offset + 4;
+  if (ssrc)
+    *ssrc = GST_READ_UINT32_BE (data);
+  data += 4;
+  if (ntptime)
+    *ntptime = GST_READ_UINT64_BE (data);
+  data += 8;
+  if (rtptime)
+    *rtptime = GST_READ_UINT32_BE (data);
+  data += 4;
+  if (packet_count)
+    *packet_count = GST_READ_UINT32_BE (data);
+  data += 4;
+  if (octet_count)
+    *octet_count = GST_READ_UINT32_BE (data);
+}
+
+/**
+ * gst_rtcp_packet_sr_set_sender_info:
+ * @packet: a valid SR #GstRTCPPacket
+ * @ssrc: the SSRC 
+ * @ntptime: the NTP time
+ * @rtptime: the RTP time
+ * @packet_count: the packet count
+ * @octet_count: the octect count
+ *
+ * Set the given values in the SR packet @packet.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_packet_sr_set_sender_info (GstRTCPPacket * packet, guint32 ssrc,
+    guint64 ntptime, guint32 rtptime, guint32 packet_count, guint32 octet_count)
+{
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  g_warning ("not implemented");
+}
+
+/**
+ * gst_rtcp_packet_rr_get_ssrc:
+ * @packet: a valid RR #GstRTCPPacket
+ *
+ * Get the ssrc field of the RR @packet.
+ *
+ * Returns: the ssrc.
+ */
+guint32
+gst_rtcp_packet_rr_get_ssrc (GstRTCPPacket * packet)
+{
+  guint8 *data;
+  guint32 ssrc;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  data = GST_BUFFER_DATA (packet->buffer);
+
+  /* skip header */
+  data += packet->offset + 4;
+  ssrc = GST_READ_UINT32_BE (data);
+
+  return ssrc;
+}
+
+/**
+ * gst_rtcp_packet_rr_set_ssrc:
+ * @packet: a valid RR #GstRTCPPacket
+ * @ssrc: the SSRC to set
+ *
+ * Set the ssrc field of the RR @packet.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_packet_rr_set_ssrc (GstRTCPPacket * packet, guint32 ssrc)
+{
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_RR);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  g_warning ("not implemented");
+}
+
+/**
+ * gst_rtcp_packet_get_rb_count:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ *
+ * Get the number of report blocks in @packet.
+ *
+ * Returns: The number of report blocks in @packet.
+ */
+guint
+gst_rtcp_packet_get_rb_count (GstRTCPPacket * packet)
+{
+  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 (GST_IS_BUFFER (packet->buffer), 0);
+
+  return packet->count;
+}
+
+/**
+ * gst_rtcp_packet_get_rb:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ * @nth: the nth report block in @packet
+ * @ssrc: result for data source being reported
+ * @fractionlost: result for fraction lost since last SR/RR
+ * @packetslost: result for the cumululative number of packets lost
+ * @exthighestseq: result for the extended last sequence number received
+ * @jitter: result for the interarrival jitter
+ * @lsr: result for the last SR packet from this source
+ * @dlsr: result for the delay since last SR packet
+ *
+ * Parse the values of the @nth report block in @packet and store the result in
+ * the values.
+ */
+void
+gst_rtcp_packet_get_rb (GstRTCPPacket * packet, guint nth, guint32 * ssrc,
+    guint8 * fractionlost, gint32 * packetslost, guint32 * exthighestseq,
+    guint32 * jitter, guint32 * lsr, guint32 * dlsr)
+{
+  guint8 *data;
+  guint32 tmp;
+
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
+      packet->type == GST_RTCP_TYPE_SR);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  data = GST_BUFFER_DATA (packet->buffer);
+
+  /* skip header */
+  data += packet->offset + 4;
+  if (packet->type == GST_RTCP_TYPE_RR)
+    data += 4;
+  else
+    data += 36;
+
+  /* move to requested index */
+  data += (nth * 36);
+
+  if (ssrc)
+    *ssrc = GST_READ_UINT32_BE (data);
+  data += 4;
+  tmp = GST_READ_UINT32_BE (data);
+  data += 4;
+  if (fractionlost)
+    *fractionlost = (tmp >> 24);
+  if (packetslost) {
+    /* sign extend */
+    if (tmp & 0x00800000)
+      tmp |= 0xff000000;
+    else
+      tmp &= 0x00ffffff;
+    *packetslost = (gint32) tmp;
+  }
+  data += 4;
+  if (exthighestseq)
+    *exthighestseq = GST_READ_UINT32_BE (data);
+  data += 4;
+  if (jitter)
+    *jitter = GST_READ_UINT32_BE (data);
+  data += 4;
+  if (lsr)
+    *lsr = GST_READ_UINT32_BE (data);
+  data += 4;
+  if (dlsr)
+    *dlsr = GST_READ_UINT32_BE (data);
+}
+
+/**
+ * gst_rtcp_packet_add_rb:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ * @ssrc: data source being reported
+ * @fractionlost: fraction lost since last SR/RR
+ * @packetslost: the cumululative number of packets lost
+ * @exthighestseq: the extended last sequence number received
+ * @jitter: the interarrival jitter
+ * @lsr: the last SR packet from this source
+ * @dlsr: the delay since last SR packet
+ *
+ * Add a new report block to @packet with the given values.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_packet_add_rb (GstRTCPPacket * packet, guint32 ssrc,
+    guint8 fractionlost, gint32 packetslost, guint32 exthighestseq,
+    guint32 jitter, guint32 lsr, guint32 dlsr)
+{
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
+      packet->type == GST_RTCP_TYPE_SR);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  g_warning ("not implemented");
+}
+
+/**
+ * gst_rtcp_packet_set_rb:
+ * @packet: a valid SR or RR #GstRTCPPacket
+ * @nth: the nth report block to set
+ * @ssrc: data source being reported
+ * @fractionlost: fraction lost since last SR/RR
+ * @packetslost: the cumululative number of packets lost
+ * @exthighestseq: the extended last sequence number received
+ * @jitter: the interarrival jitter
+ * @lsr: the last SR packet from this source
+ * @dlsr: the delay since last SR packet
+ *
+ * Set the @nth new report block in @packet with the given values.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_packet_set_rb (GstRTCPPacket * packet, guint nth, guint32 ssrc,
+    guint8 fractionlost, gint32 packetslost, guint32 exthighestseq,
+    guint32 jitter, guint32 lsr, guint32 dlsr)
+{
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
+      packet->type == GST_RTCP_TYPE_SR);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  g_warning ("not implemented");
+}
+
+
+/**
+ * gst_rtcp_packet_sdes_get_chunk_count:
+ * @packet: a valid SDES #GstRTCPPacket
+ *
+ * Get the number of chunks in the SDES packet @packet.
+ *
+ * Returns: The number of chunks in @packet.
+ */
+guint
+gst_rtcp_packet_sdes_get_chunk_count (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  return packet->count;
+}
+
+/**
+ * gst_rtcp_packet_sdes_first_chunk:
+ * @packet: a valid SDES #GstRTCPPacket
+ *
+ * Move to the first SDES chunk in @packet.
+ *
+ * Returns: TRUE if there was a first chunk.
+ */
+gboolean
+gst_rtcp_packet_sdes_first_chunk (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  if (packet->count == 0)
+    return FALSE;
+
+  packet->chunk_offset = 4;
+  packet->item_offset = 4;
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_sdes_next_chunk:
+ * @packet: a valid SDES #GstRTCPPacket
+ *
+ * Move to the next SDES chunk in @packet.
+ *
+ * Returns: TRUE if there was a next chunk.
+ */
+gboolean
+gst_rtcp_packet_sdes_next_chunk (GstRTCPPacket * packet)
+{
+  guint8 *data;
+  guint offset;
+  guint len;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  /* move to SDES */
+  data = GST_BUFFER_DATA (packet->buffer);
+  data += packet->offset;
+  /* move to chunk */
+  offset = packet->chunk_offset;
+  /* skip SSRC */
+  offset += 4;
+
+  /* don't overrun */
+  len = (packet->length << 2);
+
+  while (offset < len) {
+    if (data[offset] == 0) {
+      /* end of list, round to next 32-bit word */
+      offset = (offset + 3) & ~3;
+      break;
+    }
+    offset += data[offset + 1] + 2;
+  }
+  if (offset >= len)
+    return FALSE;
+
+  packet->chunk_offset = offset;
+  packet->item_offset = 4;
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_sdes_get_ssrc:
+ * @packet: a valid SDES #GstRTCPPacket
+ *
+ * Get the SSRC of the current SDES chunk.
+ *
+ * Returns: the SSRC of the current chunk.
+ */
+guint32
+gst_rtcp_packet_sdes_get_ssrc (GstRTCPPacket * packet)
+{
+  guint32 ssrc;
+  guint8 *data;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  /* move to SDES */
+  data = GST_BUFFER_DATA (packet->buffer);
+  data += packet->offset;
+  /* move to chunk */
+  data += packet->chunk_offset;
+
+  ssrc = GST_READ_UINT32_BE (data);
+
+  return ssrc;
+}
+
+/**
+ * gst_rtcp_packet_sdes_first_item:
+ * @packet: a valid SDES #GstRTCPPacket
+ *
+ * Move to the first SDES item in the current chunk.
+ *
+ * Returns: TRUE if there was a first item.
+ */
+gboolean
+gst_rtcp_packet_sdes_first_item (GstRTCPPacket * packet)
+{
+  guint8 *data;
+  guint len, offset;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  /* move to SDES */
+  data = GST_BUFFER_DATA (packet->buffer);
+  data += packet->offset;
+  /* move to chunk */
+  offset = packet->chunk_offset;
+  /* skip SSRC */
+  offset += 4;
+
+  /* don't overrun */
+  len = (packet->length << 2);
+  if (offset >= len)
+    return FALSE;
+
+  if (data[offset] == 0)
+    return FALSE;
+
+  packet->item_offset = 4;
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_sdes_next_item:
+ * @packet: a valid SDES #GstRTCPPacket
+ *
+ * Move to the next SDES item in the current chunk.
+ *
+ * Returns: TRUE if there was a next item.
+ */
+gboolean
+gst_rtcp_packet_sdes_next_item (GstRTCPPacket * packet)
+{
+  guint8 *data;
+  guint len, offset, item_len;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  /* move to SDES */
+  data = GST_BUFFER_DATA (packet->buffer);
+  data += packet->offset;
+  /* move to chunk */
+  offset = packet->chunk_offset;
+  /* move to item */
+  offset += packet->item_offset;
+
+  item_len = data[offset + 1] + 2;
+  /* skip item */
+  offset += item_len;
+
+  /* don't overrun */
+  len = (packet->length << 2);
+  if (offset >= len)
+    return FALSE;
+
+  /* check for end of list */
+  if (data[offset] == 0)
+    return FALSE;
+
+  packet->item_offset += item_len;
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_sdes_get_item:
+ * @packet: a valid SDES #GstRTCPPacket
+ * @type: result of the item type
+ * @len: result length of the item data
+ * @data: result item data
+ *
+ * Get the data of the current SDES chunk item.
+ *
+ * Returns: TRUE if there was valid data.
+ */
+gboolean
+gst_rtcp_packet_sdes_get_item (GstRTCPPacket * packet,
+    GstRTCPSDESType * type, guint8 * len, gchar ** data)
+{
+  guint8 *bdata;
+  guint offset;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  /* move to SDES */
+  bdata = GST_BUFFER_DATA (packet->buffer);
+  bdata += packet->offset;
+  /* move to chunk */
+  offset = packet->chunk_offset;
+  /* move to item */
+  offset += packet->item_offset;
+
+  if (bdata[offset] == 0)
+    return FALSE;
+
+  if (type)
+    *type = bdata[offset];
+  if (len)
+    *len = bdata[offset + 1];
+  if (data)
+    *data = g_strndup ((const gchar *) &bdata[offset + 2], bdata[offset + 1]);
+
+  return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_bye_get_ssrc_count:
+ * @packet: a valid BYE #GstRTCPPacket
+ *
+ * Get the number of SSRC fields in @packet.
+ *
+ * Returns: The number of SSRC fields in @packet.
+ */
+guint
+gst_rtcp_packet_bye_get_ssrc_count (GstRTCPPacket * packet)
+{
+  g_return_val_if_fail (packet != NULL, -1);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, -1);
+
+  return packet->count;
+}
+
+/**
+ * gst_rtcp_packet_bye_get_nth_ssrc:
+ * @packet: a valid BYE #GstRTCPPacket
+ * @nth: the nth SSRC to get
+ *
+ * Get the @nth SSRC of the BYE @packet.
+ *
+ * Returns: The @nth SSRC of @packet.
+ */
+guint32
+gst_rtcp_packet_bye_get_nth_ssrc (GstRTCPPacket * packet, guint nth)
+{
+  guint8 *data;
+  guint offset;
+  guint32 ssrc;
+  guint8 sc;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  /* get amount of sources and check that we don't read too much */
+  sc = packet->count;
+  if (nth >= sc)
+    return 0;
+
+  /* get offset in 32-bits words into packet, skip the header */
+  offset = 1 + nth;
+  /* check that we don't go past the packet length */
+  if (offset > packet->length)
+    return 0;
+
+  /* scale to bytes */
+  offset <<= 2;
+  offset += packet->offset;
+
+  /* check if the packet is valid */
+  if (offset + 4 > GST_BUFFER_SIZE (packet->buffer))
+    return 0;
+
+  data = GST_BUFFER_DATA (packet->buffer);
+  data += offset;
+
+  ssrc = GST_READ_UINT32_BE (data);
+
+  return ssrc;
+}
+
+/**
+ * gst_rtcp_packet_bye_add_ssrc:
+ * @packet: a valid BYE #GstRTCPPacket
+ * @ssrc: an SSRC to add
+ *
+ * Add @ssrc to the BYE @packet.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_packet_bye_add_ssrc (GstRTCPPacket * packet, guint32 ssrc)
+{
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_BYE);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  g_warning ("not implemented");
+}
+
+/**
+ * gst_rtcp_packet_bye_add_ssrcs:
+ * @packet: a valid BYE #GstRTCPPacket
+ * @ssrc: an array of SSRCs to add
+ * @len: number of elements in @ssrc
+ *
+ * Adds @len SSRCs in @ssrc to BYE @packet.
+ *
+ * Note: Not implemented.
+ */
+void
+gst_rtcp_packet_bye_add_ssrcs (GstRTCPPacket * packet, guint32 * ssrc,
+    guint len)
+{
+  g_return_if_fail (packet != NULL);
+  g_return_if_fail (packet->type == GST_RTCP_TYPE_BYE);
+  g_return_if_fail (GST_IS_BUFFER (packet->buffer));
+
+  g_warning ("not implemented");
+}
+
+/* get the offset in packet of the reason length */
+static guint
+get_reason_offset (GstRTCPPacket * packet)
+{
+  guint sc;
+  guint offset;
+
+  /* get amount of sources */
+  sc = packet->count;
+
+  offset = 1 + sc;
+  /* check that we don't go past the packet length */
+  if (offset > packet->length)
+    return 0;
+
+  /* scale to bytes */
+  offset <<= 2;
+  offset += packet->offset;
+
+  /* check if the packet is valid */
+  if (offset + 1 > GST_BUFFER_SIZE (packet->buffer))
+    return 0;
+
+  return offset;
+}
+
+/**
+ * gst_rtcp_packet_bye_get_reason_len:
+ * @packet: a valid BYE #GstRTCPPacket
+ *
+ * Get the length of the reason string.
+ *
+ * Returns: The length of the reason string or 0 when there is no reason string
+ * present.
+ */
+guint8
+gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket * packet)
+{
+  guint8 *data;
+  guint roffset;
+
+  g_return_val_if_fail (packet != NULL, 0);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
+
+  roffset = get_reason_offset (packet);
+  if (roffset == 0)
+    return 0;
+
+  data = GST_BUFFER_DATA (packet->buffer);
+
+  return data[roffset];
+}
+
+/**
+ * gst_rtcp_packet_bye_get_reason:
+ * @packet: a valid BYE #GstRTCPPacket
+ *
+ * Get the reason in @packet.
+ *
+ * Returns: The reason for the BYE @packet or NULL if the packet did not contain
+ * a reason string. The string must be freed with g_free() after usage.
+ */
+gchar *
+gst_rtcp_packet_bye_get_reason (GstRTCPPacket * packet)
+{
+  guint8 *data;
+  guint roffset;
+  guint8 len;
+
+  g_return_val_if_fail (packet != NULL, NULL);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), NULL);
+
+  roffset = get_reason_offset (packet);
+  if (roffset == 0)
+    return NULL;
+
+  data = GST_BUFFER_DATA (packet->buffer);
+
+  /* get length of reason string */
+  len = data[roffset];
+  if (len == 0)
+    return NULL;
+
+  /* move to string */
+  roffset += 1;
+
+  /* check if enough data to copy */
+  if (roffset + len > GST_BUFFER_SIZE (packet->buffer))
+    return NULL;
+
+  return g_strndup ((gconstpointer) (data + roffset), len);
+}
+
+/**
+ * gst_rtcp_packet_bye_set_reason:
+ * @packet: a valid BYE #GstRTCPPacket
+ * @reason: a reason string
+ *
+ * Set the reason string to @reason in @packet.
+ *
+ * Returns: TRUE if the string could be set.
+ *
+ * Note: Not implemented.
+ */
+gboolean
+gst_rtcp_packet_bye_set_reason (GstRTCPPacket * packet, const gchar * reason)
+{
+  g_return_val_if_fail (packet != NULL, FALSE);
+  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
+  g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
+
+  g_warning ("not implemented");
+
+  return FALSE;
+}
diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h
new file mode 100644 (file)
index 0000000..4989a2e
--- /dev/null
@@ -0,0 +1,206 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim@fluendo.com>
+ *
+ * gstrtcpbuffer.h: various helper functions to manipulate buffers
+ *     with RTCP payload.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_RTCPBUFFER_H__
+#define __GST_RTCPBUFFER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GST_RTCP_VERSION:
+ *
+ * The supported RTCP version 2.
+ */
+#define GST_RTCP_VERSION 2
+
+/** 
+ * GstRTCPType:
+ * @GST_RTCP_TYPE_INVALID: Invalid type
+ * @GST_RTCP_TYPE_SR: Sender report
+ * @GST_RTCP_TYPE_RR: Receiver report
+ * @GST_RTCP_TYPE_SDES: Source description
+ * @GST_RTCP_TYPE_BYE: Goodbye
+ * @GST_RTCP_TYPE_APP: Application defined
+ *
+ * Different RTCP packet types.
+ */
+typedef enum
+{
+  GST_RTCP_TYPE_INVALID = 0,
+  GST_RTCP_TYPE_SR      = 200,
+  GST_RTCP_TYPE_RR      = 201,
+  GST_RTCP_TYPE_SDES    = 202,
+  GST_RTCP_TYPE_BYE     = 203,
+  GST_RTCP_TYPE_APP     = 204
+} GstRTCPType;
+
+/** 
+ * GstRTCPSDESType:
+ * @GST_RTCP_SDES_INVALID: Invalid SDES entry
+ * @GST_RTCP_SDES_END: End of SDES list
+ * @GST_RTCP_SDES_CNAME: Canonical name
+ * @GST_RTCP_SDES_NAME: User name
+ * @GST_RTCP_SDES_EMAIL: User's electronic mail address
+ * @GST_RTCP_SDES_PHONE: User's phone number
+ * @GST_RTCP_SDES_LOC: Geographic user location
+ * @GST_RTCP_SDES_TOOL: Name of application or tool
+ * @GST_RTCP_SDES_NOTE: Notice about the source
+ * @GST_RTCP_SDES_PRIV: Private extensions
+ *
+ * Different types of SDES content.
+ */
+typedef enum 
+{
+  GST_RTCP_SDES_INVALID  = -1,
+  GST_RTCP_SDES_END      = 0,
+  GST_RTCP_SDES_CNAME    = 1,
+  GST_RTCP_SDES_NAME     = 2,
+  GST_RTCP_SDES_EMAIL    = 3,
+  GST_RTCP_SDES_PHONE    = 4,
+  GST_RTCP_SDES_LOC      = 5,
+  GST_RTCP_SDES_TOOL     = 6,
+  GST_RTCP_SDES_NOTE     = 7,
+  GST_RTCP_SDES_PRIV     = 8
+} GstRTCPSDESType;
+
+/**
+ * GST_RTCP_MAX_SDES:
+ *
+ * The maximum text length for an SDES item.
+ */
+#define GST_RTCP_MAX_SDES 255
+
+/**
+ * GST_RTCP_VALID_MASK:
+ *
+ * Mask for version, padding bit and packet type pair
+ */
+#define GST_RTCP_VALID_MASK (0xc000 | 0x2000 | 0xfe)
+/**
+ * GST_RTCP_VALID_VALUE:
+ *
+ * Valid value for the first two bytes of an RTCP packet after applying
+ * #GST_RTCP_VALID_MASK to them.
+ */
+#define GST_RTCP_VALID_VALUE ((GST_RTCP_VERSION << 14) | GST_RTCP_TYPE_SR)
+
+typedef struct _GstRTCPPacket GstRTCPPacket;
+
+/**
+ * GstRTCPPacket:
+ * @buffer: pointer to RTCP buffer
+ * @offset: offset of packet in buffer data
+ *
+ * Data structure that points to a packet at @offset in @buffer. 
+ * The size of the structure is made public to allow stack allocations.
+ */
+struct _GstRTCPPacket
+{ 
+  GstBuffer   *buffer;
+  guint        offset;
+  
+  /*< private >*/
+  gboolean     padding;      /* padding field of current packet */
+  guint8       count;        /* count field of current packet */
+  GstRTCPType  type;         /* type of current packet */
+  guint16      length;       /* length of current packet in 32-bits words */
+
+  guint        chunk_offset; /* current chunk offset for navigating SDES */
+  guint        item_offset;  /* current item offset for navigating SDE */
+};
+
+/* creating buffers */
+GstBuffer*      gst_rtcp_buffer_new_take_data     (gpointer data, guint len);
+GstBuffer*      gst_rtcp_buffer_new_copy_data     (gpointer data, guint len);
+
+gboolean        gst_rtcp_buffer_validate_data     (guint8 *data, guint len);
+gboolean        gst_rtcp_buffer_validate          (GstBuffer *buffer);
+
+/* adding/retrieving packets */
+guint           gst_rtcp_buffer_get_packet_count  (GstBuffer *buffer);
+gboolean        gst_rtcp_buffer_get_first_packet  (GstBuffer *buffer, GstRTCPPacket *packet);
+gboolean        gst_rtcp_packet_move_to_next      (GstRTCPPacket *packet);
+
+void            gst_rtcp_buffer_add_packet        (GstBuffer *buffer, GstRTCPType type,
+                                                  GstRTCPPacket *packet);
+void            gst_rtcp_packet_remove            (GstRTCPPacket *packet);
+
+/* working with packets */
+gboolean        gst_rtcp_packet_get_padding       (GstRTCPPacket *packet);
+guint8          gst_rtcp_packet_get_count         (GstRTCPPacket *packet);
+GstRTCPType     gst_rtcp_packet_get_type          (GstRTCPPacket *packet);
+guint16         gst_rtcp_packet_get_length        (GstRTCPPacket *packet);
+
+
+/* sender reports */ 
+void            gst_rtcp_packet_sr_get_sender_info     (GstRTCPPacket *packet, guint32 *ssrc, 
+                                                        guint64 *ntptime, guint32 *rtptime, 
+                                                       guint32 *packet_count, guint32 *octet_count);
+void            gst_rtcp_packet_sr_set_sender_info     (GstRTCPPacket *packet, guint32 ssrc, 
+                                                        guint64 ntptime, guint32 rtptime, 
+                                                       guint32 packet_count, guint32 octet_count);
+/* receiver reports */ 
+guint32         gst_rtcp_packet_rr_get_ssrc            (GstRTCPPacket *packet);
+void            gst_rtcp_packet_rr_set_ssrc            (GstRTCPPacket *packet, guint32 ssrc);
+
+
+/* report blocks for SR and RR */
+guint           gst_rtcp_packet_get_rb_count          (GstRTCPPacket *packet);
+void            gst_rtcp_packet_get_rb                (GstRTCPPacket *packet, guint nth, guint32 *ssrc,
+                                                      guint8 *fractionlost, gint32 *packetslost,
+                                                      guint32 *exthighestseq, guint32 *jitter,
+                                                      guint32 *lsr, guint32 *dlsr);
+void            gst_rtcp_packet_add_rb                (GstRTCPPacket *packet, guint32 ssrc,
+                                                      guint8 fractionlost, gint32 packetslost,
+                                                      guint32 exthighestseq, guint32 jitter,
+                                                      guint32 lsr, guint32 dlsr);
+void            gst_rtcp_packet_set_rb                (GstRTCPPacket *packet, guint nth, guint32 ssrc,
+                                                      guint8 fractionlost, gint32 packetslost,
+                                                      guint32 exthighestseq, guint32 jitter,
+                                                      guint32 lsr, guint32 dlsr);
+
+/* source description packet */
+guint           gst_rtcp_packet_sdes_get_chunk_count   (GstRTCPPacket *packet);
+gboolean        gst_rtcp_packet_sdes_first_chunk       (GstRTCPPacket *packet);
+gboolean        gst_rtcp_packet_sdes_next_chunk        (GstRTCPPacket *packet);
+guint32         gst_rtcp_packet_sdes_get_ssrc          (GstRTCPPacket *packet); 
+gboolean        gst_rtcp_packet_sdes_first_item        (GstRTCPPacket *packet);
+gboolean        gst_rtcp_packet_sdes_next_item         (GstRTCPPacket *packet);
+gboolean        gst_rtcp_packet_sdes_get_item          (GstRTCPPacket *packet, 
+                                                        GstRTCPSDESType *type, guint8 *len,
+                                                       gchar **data);
+
+/* bye packet */
+guint           gst_rtcp_packet_bye_get_ssrc_count     (GstRTCPPacket *packet);
+guint32         gst_rtcp_packet_bye_get_nth_ssrc       (GstRTCPPacket *packet, guint nth);
+void            gst_rtcp_packet_bye_add_ssrc           (GstRTCPPacket *packet, guint32 ssrc);
+void            gst_rtcp_packet_bye_add_ssrcs          (GstRTCPPacket *packet, guint32 *ssrc, guint len);
+guint8          gst_rtcp_packet_bye_get_reason_len     (GstRTCPPacket *packet);
+gchar*          gst_rtcp_packet_bye_get_reason         (GstRTCPPacket *packet);
+gboolean        gst_rtcp_packet_bye_set_reason         (GstRTCPPacket *packet, const gchar *reason);
+
+G_END_DECLS
+
+#endif /* __GST_RTCPBUFFER_H__ */
+