static GstFlowReturn
gst_rdt_depay_chain (GstPad * pad, GstBuffer * buf)
{
  GstRDTDepay *rdtdepay;
  GstFlowReturn ret;
  GstClockTime timestamp;
  gboolean more;
  GstRDTPacket packet;

  rdtdepay = GST_RDT_DEPAY (GST_PAD_PARENT (pad));

  if (GST_BUFFER_IS_DISCONT (buf)) {
    GST_LOG_OBJECT (rdtdepay, "received discont");
    rdtdepay->discont = TRUE;
  }

  if (rdtdepay->header) {
    GstBuffer *out;

    out = rdtdepay->header;
    rdtdepay->header = NULL;

    /* push header data first */
    ret = gst_rdt_depay_push (rdtdepay, out);
  }

  /* save timestamp */
  timestamp = GST_BUFFER_TIMESTAMP (buf);

  ret = GST_FLOW_OK;

  GST_LOG_OBJECT (rdtdepay, "received buffer timestamp %" GST_TIME_FORMAT,
      GST_TIME_ARGS (timestamp));

  /* data is in RDT format. */
  more = gst_rdt_buffer_get_first_packet (buf, &packet);
  while (more) {
    GstRDTType type;

    type = gst_rdt_packet_get_type (&packet);
    GST_DEBUG_OBJECT (rdtdepay, "Have packet of type %04x", type);

    if (GST_RDT_IS_DATA_TYPE (type)) {
      GST_DEBUG_OBJECT (rdtdepay, "We have a data packet");
      ret = gst_rdt_depay_handle_data (rdtdepay, timestamp, &packet);
    } else {
      switch (type) {
        default:
          GST_DEBUG_OBJECT (rdtdepay, "Ignoring packet");
          break;
      }
    }
    if (ret != GST_FLOW_OK)
      break;

    more = gst_rdt_packet_move_to_next (&packet);
  }

  return ret;
}
static GstStateChangeReturn
gst_rdt_depay_change_state (GstElement * element, GstStateChange transition)
{
  GstRDTDepay *rdtdepay;
  GstStateChangeReturn ret;

  rdtdepay = GST_RDT_DEPAY (element);

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      gst_segment_init (&rdtdepay->segment, GST_FORMAT_UNDEFINED);
      rdtdepay->next_seqnum = -1;
      rdtdepay->need_newsegment = TRUE;
      break;
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      if (rdtdepay->header)
        gst_buffer_unref (rdtdepay->header);
      rdtdepay->header = NULL;
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      break;
    default:
      break;
  }
  return ret;
}
static void
gst_rdt_depay_finalize (GObject * object)
{
  GstRDTDepay *rdtdepay;

  rdtdepay = GST_RDT_DEPAY (object);

  if (rdtdepay->header)
    gst_buffer_unref (rdtdepay->header);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_rdt_depay_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstRDTDepay *rdtdepay;

  rdtdepay = GST_RDT_DEPAY (object);

  switch (prop_id) {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static gboolean
gst_rdt_depay_sink_event (GstPad * pad, GstEvent * event)
{
  GstRDTDepay *depay;
  gboolean res = TRUE;

  depay = GST_RDT_DEPAY (GST_OBJECT_PARENT (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:
      res = gst_pad_push_event (depay->srcpad, event);

      gst_segment_init (&depay->segment, GST_FORMAT_UNDEFINED);
      depay->need_newsegment = TRUE;
      depay->next_seqnum = -1;
      break;
    case GST_EVENT_NEWSEGMENT:
    {
      gboolean update;
      gdouble rate;
      GstFormat fmt;
      gint64 start, stop, position;

      gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop,
          &position);

      gst_segment_set_newsegment (&depay->segment, update, rate, fmt,
          start, stop, position);

      /* don't pass the event downstream, we generate our own segment
       * including the NTP time and other things we receive in caps */
      gst_event_unref (event);
      break;
    }
    default:
      /* pass other events forward */
      res = gst_pad_push_event (depay->srcpad, event);
      break;
  }
  return res;
}
static gboolean
gst_rdt_depay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstRDTDepay *depay;
  gboolean res = TRUE;

  depay = GST_RDT_DEPAY (parent);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      res = gst_rdt_depay_setcaps (pad, caps);
      gst_event_unref (event);
      break;
    }
    case GST_EVENT_FLUSH_STOP:
      res = gst_pad_push_event (depay->srcpad, event);

      gst_segment_init (&depay->segment, GST_FORMAT_UNDEFINED);
      depay->need_newsegment = TRUE;
      depay->next_seqnum = -1;
      break;
    case GST_EVENT_SEGMENT:
    {
      gst_event_copy_segment (event, &depay->segment);
      /* don't pass the event downstream, we generate our own segment
       * including the NTP time and other things we receive in caps */
      gst_event_unref (event);
      break;
    }
    default:
      /* pass other events forward */
      res = gst_pad_push_event (depay->srcpad, event);
      break;
  }
  return res;
}
static gboolean
gst_rdt_depay_setcaps (GstPad * pad, GstCaps * caps)
{
  GstStructure *structure;
  GstRDTDepay *rdtdepay;
  GstCaps *srccaps;
  gint clock_rate = 1000;       /* default */
  const GValue *value;
  GstBuffer *header;

  rdtdepay = GST_RDT_DEPAY (GST_PAD_PARENT (pad));

  structure = gst_caps_get_structure (caps, 0);

  if (gst_structure_has_field (structure, "clock-rate"))
    gst_structure_get_int (structure, "clock-rate", &clock_rate);

  /* config contains the RealMedia header as a buffer. */
  value = gst_structure_get_value (structure, "config");
  if (!value)
    goto no_header;

  header = gst_value_get_buffer (value);
  if (!header)
    goto no_header;

  /* get other values for newsegment */
  value = gst_structure_get_value (structure, "npt-start");
  if (value && G_VALUE_HOLDS_UINT64 (value))
    rdtdepay->npt_start = g_value_get_uint64 (value);
  else
    rdtdepay->npt_start = 0;
  GST_DEBUG_OBJECT (rdtdepay, "NPT start %" G_GUINT64_FORMAT,
      rdtdepay->npt_start);

  value = gst_structure_get_value (structure, "npt-stop");
  if (value && G_VALUE_HOLDS_UINT64 (value))
    rdtdepay->npt_stop = g_value_get_uint64 (value);
  else
    rdtdepay->npt_stop = -1;

  GST_DEBUG_OBJECT (rdtdepay, "NPT stop %" G_GUINT64_FORMAT,
      rdtdepay->npt_stop);

  value = gst_structure_get_value (structure, "play-speed");
  if (value && G_VALUE_HOLDS_DOUBLE (value))
    rdtdepay->play_speed = g_value_get_double (value);
  else
    rdtdepay->play_speed = 1.0;

  value = gst_structure_get_value (structure, "play-scale");
  if (value && G_VALUE_HOLDS_DOUBLE (value))
    rdtdepay->play_scale = g_value_get_double (value);
  else
    rdtdepay->play_scale = 1.0;

  /* caps seem good, configure element */
  rdtdepay->clock_rate = clock_rate;

  /* set caps on pad and on header */
  srccaps = gst_caps_new_empty_simple ("application/vnd.rn-realmedia");
  gst_pad_set_caps (rdtdepay->srcpad, srccaps);
  gst_caps_unref (srccaps);

  if (rdtdepay->header)
    gst_buffer_unref (rdtdepay->header);
  rdtdepay->header = gst_buffer_ref (header);

  return TRUE;

  /* ERRORS */
no_header:
  {
    GST_ERROR_OBJECT (rdtdepay, "no header found in caps, no 'config' field");
    return FALSE;
  }
}