static GstBuffer *
create_rtp_buffer (guint32 ssrc, guint8 payload_type, guint16 seqnum)
{
  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
  guint payload_size = 29;
  guint64 timestamp = gst_util_uint64_scale_int (seqnum, 90000, 30);
  GstBuffer *buf = gst_rtp_buffer_new_allocate (payload_size, 0, 0);

  gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtpbuf);
  gst_rtp_buffer_set_ssrc (&rtpbuf, ssrc);
  gst_rtp_buffer_set_payload_type (&rtpbuf, payload_type);
  gst_rtp_buffer_set_seq (&rtpbuf, seqnum);
  gst_rtp_buffer_set_timestamp (&rtpbuf, (guint32) timestamp);
  memset (gst_rtp_buffer_get_payload (&rtpbuf), 0x29, payload_size);
  gst_rtp_buffer_unmap (&rtpbuf);
  return buf;
}
示例#2
0
static void
gst_rtp_dtmf_prepare_rtp_headers (GstRTPDTMFSrc * dtmfsrc, GstBuffer * buf)
{
  gst_rtp_buffer_set_ssrc (buf, dtmfsrc->current_ssrc);
  gst_rtp_buffer_set_payload_type (buf, dtmfsrc->pt);
  /* Only the very first packet gets a marker */
  if (dtmfsrc->first_packet) {
    gst_rtp_buffer_set_marker (buf, TRUE);
  } else if (dtmfsrc->last_packet) {
    dtmfsrc->payload->e = 1;
  }

  dtmfsrc->seqnum++;
  gst_rtp_buffer_set_seq (buf, dtmfsrc->seqnum);

  /* timestamp of RTP header */
  gst_rtp_buffer_set_timestamp (buf, dtmfsrc->rtp_timestamp);
}
示例#3
0
static void
send_rtp_packet (GstPad * src, guint timestamp, gboolean marker, gboolean end,
    guint number, guint volume, guint duration)
{
  GstBuffer *buf;
  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
  gchar *payload;
  static guint seqnum = 1;

  buf = gst_rtp_buffer_new_allocate (4, 0, 0);
  fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtpbuf));
  gst_rtp_buffer_set_seq (&rtpbuf, seqnum++);
  gst_rtp_buffer_set_timestamp (&rtpbuf, timestamp);
  gst_rtp_buffer_set_marker (&rtpbuf, marker);
  payload = gst_rtp_buffer_get_payload (&rtpbuf);
  payload[0] = number;
  payload[1] = volume | (end ? END_BIT : 0);
  GST_WRITE_UINT16_BE (payload + 2, duration);
  gst_rtp_buffer_unmap (&rtpbuf);
  fail_unless (gst_pad_push (src, buf) == GST_FLOW_OK);
}
示例#4
0
static void
lock_check_cb (GstPad * pad, int i)
{
  GstBuffer *inbuf;

  if (i % 2) {
    fail_unless (buffers == NULL);
  } else {
    GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;

    fail_unless (buffers && g_list_length (buffers) == 1);
    gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
    fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
    fail_unless_equals_int64 (200 - 57 + 1000 + i,
        gst_rtp_buffer_get_timestamp (&rtpbuffer));
    fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
    gst_rtp_buffer_unmap (&rtpbuffer);

    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
    GST_BUFFER_PTS (inbuf) = i * 1000 + 500;
    GST_BUFFER_DURATION (inbuf) = 1000;
    gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);
    gst_rtp_buffer_set_version (&rtpbuffer, 2);
    gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
    gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
    gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
    gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
    gst_rtp_buffer_unmap (&rtpbuffer);
    fail_unless (gst_pad_push (pad, inbuf) == GST_FLOW_OK);


    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
    g_list_free (buffers);
    buffers = NULL;
  }
}
static GstFlowReturn
gst_rtp_ulpfec_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstRtpUlpFecDec *self = GST_RTP_ULPFEC_DEC (parent);

  if (G_LIKELY (GST_FLOW_OK == self->chain_return_val)) {
    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
    buf = gst_buffer_make_writable (buf);

    if (G_UNLIKELY (self->unset_discont_flag)) {
      self->unset_discont_flag = FALSE;
      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
    }

    gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtp);
    gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++);
    gst_rtp_buffer_unmap (&rtp);

    return gst_pad_push (self->srcpad, buf);
  }

  gst_buffer_unref (buf);
  return self->chain_return_val;
}
示例#6
0
static GstFlowReturn
gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
{
  GstRTPBasePayload *rtppay;
  GstAsfPacketInfo *packetinfo;
  guint8 flags;
  guint8 *data;
  guint32 packet_util_size;
  guint32 packet_offset;
  guint32 size_left;
  GstFlowReturn ret = GST_FLOW_OK;

  rtppay = GST_RTP_BASE_PAYLOAD (rtpasfpay);
  packetinfo = &rtpasfpay->packetinfo;

  if (!gst_asf_parse_packet (buffer, packetinfo, TRUE,
          rtpasfpay->asfinfo.packet_size)) {
    GST_ERROR_OBJECT (rtpasfpay, "Error while parsing asf packet");
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }

  if (packetinfo->packet_size == 0)
    packetinfo->packet_size = rtpasfpay->asfinfo.packet_size;

  GST_LOG_OBJECT (rtpasfpay, "Packet size: %" G_GUINT32_FORMAT
      ", padding: %" G_GUINT32_FORMAT, packetinfo->packet_size,
      packetinfo->padding);

  /* update padding field to 0 */
  if (packetinfo->padding > 0) {
    GstAsfPacketInfo info;
    /* find padding field offset */
    guint offset = packetinfo->err_cor_len + 2 +
        gst_asf_get_var_size_field_len (packetinfo->packet_field_type) +
        gst_asf_get_var_size_field_len (packetinfo->seq_field_type);
    buffer = gst_buffer_make_writable (buffer);
    switch (packetinfo->padd_field_type) {
      case ASF_FIELD_TYPE_DWORD:
        gst_buffer_memset (buffer, offset, 0, 4);
        break;
      case ASF_FIELD_TYPE_WORD:
        gst_buffer_memset (buffer, offset, 0, 2);
        break;
      case ASF_FIELD_TYPE_BYTE:
        gst_buffer_memset (buffer, offset, 0, 1);
        break;
      case ASF_FIELD_TYPE_NONE:
      default:
        break;
    }
    gst_asf_parse_packet (buffer, &info, FALSE, 0);
  }

  if (packetinfo->padding != 0)
    packet_util_size = rtpasfpay->asfinfo.packet_size - packetinfo->padding;
  else
    packet_util_size = packetinfo->packet_size;
  packet_offset = 0;
  while (packet_util_size > 0) {
    /* Even if we don't fill completely an output buffer we
     * push it when we add an fragment. Because it seems that
     * it is not possible to determine where a asf packet
     * fragment ends inside a rtp packet payload.
     * This flag tells us to push the packet.
     */
    gboolean force_push = FALSE;
    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;

    /* we have no output buffer pending, create one */
    if (rtpasfpay->current == NULL) {
      GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer");
      rtpasfpay->current =
          gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU (rtpasfpay),
          0, 0);
      rtpasfpay->cur_off = 0;
      rtpasfpay->has_ts = FALSE;
      rtpasfpay->marker = FALSE;
    }
    gst_rtp_buffer_map (rtpasfpay->current, GST_MAP_READWRITE, &rtp);
    data = gst_rtp_buffer_get_payload (&rtp);
    data += rtpasfpay->cur_off;
    size_left = gst_rtp_buffer_get_payload_len (&rtp) - rtpasfpay->cur_off;

    GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %"
        G_GUINT32_FORMAT "/%" G_GSIZE_FORMAT, packet_offset,
        gst_buffer_get_size (buffer));

    GST_DEBUG_OBJECT (rtpasfpay, "Output rtpbuffer status");
    GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT,
        rtpasfpay->cur_off);
    GST_DEBUG_OBJECT (rtpasfpay, "Size left: %" G_GUINT32_FORMAT, size_left);
    GST_DEBUG_OBJECT (rtpasfpay, "Has ts: %s",
        rtpasfpay->has_ts ? "yes" : "no");
    if (rtpasfpay->has_ts) {
      GST_DEBUG_OBJECT (rtpasfpay, "Ts: %" G_GUINT32_FORMAT, rtpasfpay->ts);
    }

    flags = 0;
    if (packetinfo->has_keyframe) {
      flags = flags | 0x80;
    }
    flags = flags | 0x20;       /* Relative timestamp is present */

    if (!rtpasfpay->has_ts) {
      /* this is the first asf packet, its send time is the 
       * rtp packet timestamp */
      rtpasfpay->has_ts = TRUE;
      rtpasfpay->ts = packetinfo->send_time;
    }

    if (size_left >= packet_util_size + 8) {
      /* enough space for the rest of the packet */
      if (packet_offset == 0) {
        flags = flags | 0x40;
        GST_WRITE_UINT24_BE (data + 1, packet_util_size);
      } else {
        GST_WRITE_UINT24_BE (data + 1, packet_offset);
        force_push = TRUE;
      }
      data[0] = flags;
      GST_WRITE_UINT32_BE (data + 4,
          (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
      gst_buffer_extract (buffer, packet_offset, data + 8, packet_util_size);

      /* updating status variables */
      rtpasfpay->cur_off += 8 + packet_util_size;
      size_left -= packet_util_size + 8;
      packet_offset += packet_util_size;
      packet_util_size = 0;
      rtpasfpay->marker = TRUE;
    } else {
      /* fragment packet */
      data[0] = flags;
      GST_WRITE_UINT24_BE (data + 1, packet_offset);
      GST_WRITE_UINT32_BE (data + 4,
          (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
      gst_buffer_extract (buffer, packet_offset, data + 8, size_left - 8);

      /* updating status variables */
      rtpasfpay->cur_off += size_left;
      packet_offset += size_left - 8;
      packet_util_size -= size_left - 8;
      size_left = 0;
      force_push = TRUE;
    }

    /* there is not enough room for any more buffers */
    if (force_push || size_left <= 8) {

      gst_rtp_buffer_set_ssrc (&rtp, rtppay->current_ssrc);
      gst_rtp_buffer_set_marker (&rtp, rtpasfpay->marker);
      gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (rtppay));
      gst_rtp_buffer_set_seq (&rtp, rtppay->seqnum + 1);
      gst_rtp_buffer_set_timestamp (&rtp, packetinfo->send_time);
      gst_rtp_buffer_unmap (&rtp);

      /* trim remaining bytes not used */
      if (size_left != 0) {
        gst_buffer_set_size (rtpasfpay->current,
            gst_buffer_get_size (rtpasfpay->current) - size_left);
      }

      GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer);

      rtppay->seqnum++;
      rtppay->timestamp = packetinfo->send_time;

      GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer");
      ret = gst_rtp_base_payload_push (rtppay, rtpasfpay->current);
      rtpasfpay->current = NULL;
      if (ret != GST_FLOW_OK) {
        gst_buffer_unref (buffer);
        return ret;
      }
    }
  }
  gst_buffer_unref (buffer);
  return ret;
}
示例#7
0
文件: rtpmux.c 项目: zsx/ossbuild
static void
test_basic (const gchar * elem_name, int count, check_cb cb)
{
  GstElement *rtpmux = NULL;
  GstPad *reqpad1 = NULL;
  GstPad *reqpad2 = NULL;
  GstPad *src1 = NULL;
  GstPad *src2 = NULL;
  GstPad *sink = NULL;
  GstBuffer *inbuf = NULL;
  GstCaps *src1caps = NULL;
  GstCaps *src2caps = NULL;
  GstCaps *sinkcaps = NULL;
  GstCaps *caps;
  int i;

  rtpmux = gst_check_setup_element (elem_name);

  reqpad1 = gst_element_get_request_pad (rtpmux, "sink_1");
  fail_unless (reqpad1 != NULL);
  reqpad2 = gst_element_get_request_pad (rtpmux, "sink_2");
  fail_unless (reqpad2 != NULL);
  sink = gst_check_setup_sink_pad_by_name (rtpmux, &sinktemplate, "src");

  src1 = gst_pad_new_from_static_template (&srctemplate, "src");
  src2 = gst_pad_new_from_static_template (&srctemplate, "src");
  fail_unless (gst_pad_link (src1, reqpad1) == GST_PAD_LINK_OK);
  fail_unless (gst_pad_link (src2, reqpad2) == GST_PAD_LINK_OK);
  gst_pad_set_getcaps_function (src1, getcaps_func);
  gst_pad_set_getcaps_function (src2, getcaps_func);
  gst_pad_set_getcaps_function (sink, getcaps_func);
  gst_pad_set_setcaps_function (sink, setcaps_func);
  g_object_set_data (G_OBJECT (src1), "caps", &src1caps);
  g_object_set_data (G_OBJECT (src2), "caps", &src2caps);
  g_object_set_data (G_OBJECT (sink), "caps", &sinkcaps);

  src1caps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 1, "ssrc", G_TYPE_UINT, 11, NULL);
  src2caps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 2, "ssrc", G_TYPE_UINT, 12, NULL);
  sinkcaps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 3, "ssrc", G_TYPE_UINT, 13, NULL);

  caps = gst_pad_peer_get_caps (src1);
  fail_unless (gst_caps_is_empty (caps));
  gst_caps_unref (caps);

  gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
  caps = gst_pad_peer_get_caps (src1);
  fail_unless (gst_caps_is_equal (caps, sinkcaps));
  gst_caps_unref (caps);

  g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
      "ssrc", 55, NULL);

  fail_unless (gst_element_set_state (rtpmux,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
  gst_pad_set_active (sink, TRUE);
  gst_pad_set_active (src1, TRUE);
  gst_pad_set_active (src2, TRUE);

  gst_caps_set_simple (sinkcaps,
      "payload", G_TYPE_INT, 98, "seqnum-base", G_TYPE_UINT, 100,
      "clock-base", G_TYPE_UINT, 1000, "ssrc", G_TYPE_UINT, 66, NULL);
  caps = gst_caps_new_simple ("application/x-rtp",
      "payload", G_TYPE_INT, 98, "clock-rate", G_TYPE_INT, 3,
      "seqnum-base", G_TYPE_UINT, 56, "clock-base", G_TYPE_UINT, 57,
      "ssrc", G_TYPE_UINT, 66, NULL);
  fail_unless (gst_pad_set_caps (src1, caps));

  for (i = 0; i < count; i++) {
    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
    gst_buffer_set_caps (inbuf, caps);
    gst_rtp_buffer_set_version (inbuf, 2);
    gst_rtp_buffer_set_payload_type (inbuf, 98);
    gst_rtp_buffer_set_ssrc (inbuf, 44);
    gst_rtp_buffer_set_timestamp (inbuf, 200 + i);
    gst_rtp_buffer_set_seq (inbuf, 2000 + i);
    fail_unless (gst_pad_push (src1, inbuf) == GST_FLOW_OK);

    cb (src2, i);

    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
    g_list_free (buffers);
    buffers = NULL;
  }


  gst_pad_set_active (sink, FALSE);
  gst_pad_set_active (src1, FALSE);
  gst_pad_set_active (src2, FALSE);
  fail_unless (gst_element_set_state (rtpmux,
          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
  gst_check_teardown_pad_by_name (rtpmux, "src");
  gst_object_unref (reqpad1);
  gst_object_unref (reqpad2);
  gst_check_teardown_pad_by_name (rtpmux, "sink_1");
  gst_check_teardown_pad_by_name (rtpmux, "sink_2");
  gst_element_release_request_pad (rtpmux, reqpad1);
  gst_element_release_request_pad (rtpmux, reqpad2);

  gst_caps_unref (caps);
  gst_caps_replace (&src1caps, NULL);
  gst_caps_replace (&src2caps, NULL);
  gst_caps_replace (&sinkcaps, NULL);

  gst_check_teardown_element (rtpmux);
}
示例#8
0
static void
test_basic (const gchar * elem_name, const gchar * sink2, int count,
    check_cb cb)
{
  GstElement *rtpmux = NULL;
  GstPad *reqpad1 = NULL;
  GstPad *reqpad2 = NULL;
  GstPad *src1 = NULL;
  GstPad *src2 = NULL;
  GstPad *sink = NULL;
  GstBuffer *inbuf = NULL;
  GstCaps *src1caps = NULL;
  GstCaps *src2caps = NULL;
  GstCaps *sinkcaps = NULL;
  GstCaps *caps;
  GstSegment segment;
  int i;

  rtpmux = gst_check_setup_element (elem_name);

  reqpad1 = gst_element_get_request_pad (rtpmux, "sink_1");
  fail_unless (reqpad1 != NULL);
  reqpad2 = gst_element_get_request_pad (rtpmux, sink2);
  fail_unless (reqpad2 != NULL);
  sink = gst_check_setup_sink_pad_by_name (rtpmux, &sinktemplate, "src");

  src1 = gst_pad_new_from_static_template (&srctemplate, "src");
  src2 = gst_pad_new_from_static_template (&srctemplate, "src");
  fail_unless (gst_pad_link (src1, reqpad1) == GST_PAD_LINK_OK);
  fail_unless (gst_pad_link (src2, reqpad2) == GST_PAD_LINK_OK);
  gst_pad_set_query_function (src1, query_func);
  gst_pad_set_query_function (src2, query_func);
  gst_pad_set_query_function (sink, query_func);
  gst_pad_set_event_function (sink, event_func);
  g_object_set_data (G_OBJECT (src1), "caps", &src1caps);
  g_object_set_data (G_OBJECT (src2), "caps", &src2caps);
  g_object_set_data (G_OBJECT (sink), "caps", &sinkcaps);

  src1caps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 1, "ssrc", G_TYPE_UINT, 11, NULL);
  src2caps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 2, "ssrc", G_TYPE_UINT, 12, NULL);
  sinkcaps = gst_caps_new_simple ("application/x-rtp",
      "clock-rate", G_TYPE_INT, 3, "ssrc", G_TYPE_UINT, 13, NULL);

  caps = gst_pad_peer_query_caps (src1, NULL);
  fail_unless (gst_caps_is_empty (caps));
  gst_caps_unref (caps);

  gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
  caps = gst_pad_peer_query_caps (src1, NULL);
  gst_caps_unref (caps);

  g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
      "ssrc", 55, NULL);

  fail_unless (gst_element_set_state (rtpmux,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
  gst_pad_set_active (sink, TRUE);
  gst_pad_set_active (src1, TRUE);
  gst_pad_set_active (src2, TRUE);

  fail_unless (gst_pad_push_event (src1,
          gst_event_new_stream_start ("stream1")));
  fail_unless (gst_pad_push_event (src2,
          gst_event_new_stream_start ("stream2")));

  gst_caps_set_simple (sinkcaps,
      "payload", G_TYPE_INT, 98, "seqnum-offset", G_TYPE_UINT, 100,
      "timestamp-offset", G_TYPE_UINT, 1000, "ssrc", G_TYPE_UINT, 66, NULL);
  caps = gst_caps_new_simple ("application/x-rtp",
      "payload", G_TYPE_INT, 98, "clock-rate", G_TYPE_INT, 3,
      "seqnum-offset", G_TYPE_UINT, 56, "timestamp-offset", G_TYPE_UINT, 57,
      "ssrc", G_TYPE_UINT, 66, NULL);
  fail_unless (gst_pad_set_caps (src1, caps));
  gst_caps_unref (caps);

  caps = gst_pad_peer_query_caps (sink, NULL);
  fail_if (gst_caps_is_empty (caps));

  gst_segment_init (&segment, GST_FORMAT_TIME);
  segment.start = 100000;
  fail_unless (gst_pad_push_event (src1, gst_event_new_segment (&segment)));
  segment.start = 0;
  fail_unless (gst_pad_push_event (src2, gst_event_new_segment (&segment)));


  for (i = 0; i < count; i++) {
    GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;

    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
    GST_BUFFER_PTS (inbuf) = i * 1000 + 100000;
    GST_BUFFER_DURATION (inbuf) = 1000;

    gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);

    gst_rtp_buffer_set_version (&rtpbuffer, 2);
    gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
    gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
    gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
    gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
    gst_rtp_buffer_unmap (&rtpbuffer);
    fail_unless (gst_pad_push (src1, inbuf) == GST_FLOW_OK);

    if (buffers)
      fail_unless (GST_BUFFER_PTS (buffers->data) == i * 1000, "%lld",
          GST_BUFFER_PTS (buffers->data));

    cb (src2, i);

    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
    g_list_free (buffers);
    buffers = NULL;
  }


  gst_pad_set_active (sink, FALSE);
  gst_pad_set_active (src1, FALSE);
  gst_pad_set_active (src2, FALSE);
  fail_unless (gst_element_set_state (rtpmux,
          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
  gst_check_teardown_pad_by_name (rtpmux, "src");
  gst_object_unref (reqpad1);
  gst_object_unref (reqpad2);
  gst_check_teardown_pad_by_name (rtpmux, "sink_1");
  gst_check_teardown_pad_by_name (rtpmux, sink2);
  gst_element_release_request_pad (rtpmux, reqpad1);
  gst_element_release_request_pad (rtpmux, reqpad2);

  gst_caps_unref (caps);
  gst_caps_replace (&src1caps, NULL);
  gst_caps_replace (&src2caps, NULL);
  gst_caps_replace (&sinkcaps, NULL);

  gst_check_teardown_element (rtpmux);
}
/* Copy fixed header and extension. Replace current ssrc by ssrc1,
 * remove OSN and replace current seq num by OSN.
 * Copy memory to avoid to manually copy each rtp buffer field.
 */
static GstBuffer *
_gst_rtp_buffer_new_from_rtx (GstRTPBuffer * rtp, guint32 ssrc1,
    guint16 orign_seqnum, guint8 origin_payload_type)
{
  GstMemory *mem = NULL;
  GstRTPBuffer new_rtp = GST_RTP_BUFFER_INIT;
  GstBuffer *new_buffer = gst_buffer_new ();
  GstMapInfo map;
  guint payload_len = 0;

  /* copy fixed header */
  mem = gst_memory_copy (rtp->map[0].memory,
      (guint8 *) rtp->data[0] - rtp->map[0].data, rtp->size[0]);
  gst_buffer_append_memory (new_buffer, mem);

  /* copy extension if any */
  if (rtp->size[1]) {
    mem = gst_memory_copy (rtp->map[1].memory,
        (guint8 *) rtp->data[1] - rtp->map[1].data, rtp->size[1]);
    gst_buffer_append_memory (new_buffer, mem);
  }

  /* copy payload and remove OSN */
  payload_len = rtp->size[2] - 2;
  mem = gst_allocator_alloc (NULL, payload_len, NULL);

  gst_memory_map (mem, &map, GST_MAP_WRITE);
  if (rtp->size[2])
    memcpy (map.data, (guint8 *) rtp->data[2] + 2, payload_len);
  gst_memory_unmap (mem, &map);
  gst_buffer_append_memory (new_buffer, mem);

  /* the sender always constructs rtx packets without padding,
   * But the receiver can still receive rtx packets with padding.
   * So just copy it.
   */
  if (rtp->size[3]) {
    guint pad_len = rtp->size[3];

    mem = gst_allocator_alloc (NULL, pad_len, NULL);

    gst_memory_map (mem, &map, GST_MAP_WRITE);
    map.data[pad_len - 1] = pad_len;
    gst_memory_unmap (mem, &map);

    gst_buffer_append_memory (new_buffer, mem);
  }

  /* set ssrc and seq num */
  gst_rtp_buffer_map (new_buffer, GST_MAP_WRITE, &new_rtp);
  gst_rtp_buffer_set_ssrc (&new_rtp, ssrc1);
  gst_rtp_buffer_set_seq (&new_rtp, orign_seqnum);
  gst_rtp_buffer_set_payload_type (&new_rtp, origin_payload_type);
  gst_rtp_buffer_unmap (&new_rtp);

  gst_buffer_copy_into (new_buffer, rtp->buffer,
      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
  GST_BUFFER_FLAG_SET (new_buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION);

  return new_buffer;
}
static gboolean
gst_rtp_ulpfec_dec_handle_packet_loss (GstRtpUlpFecDec * self, guint16 seqnum,
    GstClockTime timestamp, GstClockTime duration)
{
  gint caps_pt = self->have_caps_pt ? self->caps_pt : -1;
  gboolean ret = TRUE;
  GstBufferList *buflist =
      rtp_storage_get_packets_for_recovery (self->storage, self->fec_pt,
      self->caps_ssrc, seqnum);

  if (buflist) {
    GstBuffer *recovered_buffer = NULL;
    guint16 recovered_seq = 0;
    guint8 recovered_pt = 0;

    gst_rtp_ulpfec_dec_start (self, buflist, self->fec_pt, seqnum);

    while (NULL != (recovered_buffer =
            gst_rtp_ulpfec_dec_recover (self, self->caps_ssrc, caps_pt,
                &recovered_pt, &recovered_seq))) {
      if (seqnum == recovered_seq) {
        GstBuffer *sent_buffer;
        GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;

        recovered_buffer = gst_buffer_make_writable (recovered_buffer);
        GST_BUFFER_PTS (recovered_buffer) = timestamp;
        /* GST_BUFFER_DURATION (recovered_buffer) = duration;
         * JB does not set the duration, so we will not too */

        if (!self->lost_packet_from_storage)
          rtp_storage_put_recovered_packet (self->storage,
              recovered_buffer, recovered_pt, self->caps_ssrc, recovered_seq);

        GST_DEBUG_OBJECT (self,
            "Pushing recovered packet ssrc=0x%08x seq=%u %" GST_PTR_FORMAT,
            self->caps_ssrc, seqnum, recovered_buffer);

        sent_buffer = gst_buffer_copy_deep (recovered_buffer);

        gst_rtp_buffer_map (sent_buffer, GST_MAP_WRITE, &rtp);
        gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++);
        gst_rtp_buffer_unmap (&rtp);

        ret = FALSE;
        self->unset_discont_flag = TRUE;
        self->chain_return_val = gst_pad_push (self->srcpad, sent_buffer);
        break;
      }

      rtp_storage_put_recovered_packet (self->storage,
          recovered_buffer, recovered_pt, self->caps_ssrc, recovered_seq);
    }

    gst_rtp_ulpfec_dec_stop (self);
    gst_buffer_list_unref (buflist);
  }

  GST_DEBUG_OBJECT (self, "Packet lost ssrc=0x%08x seq=%u", self->caps_ssrc,
      seqnum);

  return ret;
}
/**
 * gst_basertppayload_push:
 * @payload: a #GstBaseRTPPayload
 * @buffer: a #GstBuffer
 *
 * Push @buffer to the peer element of the payloader. The SSRC, payload type,
 * seqnum and timestamp of the RTP buffer will be updated first.
 * 
 * This function takes ownership of @buffer.
 *
 * Returns: a #GstFlowReturn.
 */
GstFlowReturn
gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
{
  GstFlowReturn res;
  GstClockTime timestamp;
  guint32 rtptime;
  GstBaseRTPPayloadPrivate *priv;

  if (payload->clock_rate == 0)
    goto no_rate;

  priv = payload->priv;

  gst_rtp_buffer_set_ssrc (buffer, payload->current_ssrc);

  gst_rtp_buffer_set_payload_type (buffer, payload->pt);

  /* update first, so that the property is set to the last
   * seqnum pushed */
  payload->seqnum = priv->next_seqnum;
  gst_rtp_buffer_set_seq (buffer, payload->seqnum);

  /* can wrap around, which is perfectly fine */
  priv->next_seqnum++;

  /* add our random offset to the timestamp */
  rtptime = payload->ts_base;

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
    gint64 rtime;

    rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME,
        timestamp);

    rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND);

    /* add running_time in clock-rate units to the base timestamp */
    rtptime += rtime;
  } else {
    /* no timestamp to convert, take previous timestamp */
    rtptime = payload->timestamp;
  }
  gst_rtp_buffer_set_timestamp (buffer, rtptime);

  payload->timestamp = rtptime;

  /* set caps */
  gst_buffer_set_caps (buffer, GST_PAD_CAPS (payload->srcpad));

  GST_LOG_OBJECT (payload,
      "Pushing packet size %d, seq=%d, rtptime=%u, timestamp %" GST_TIME_FORMAT,
      GST_BUFFER_SIZE (buffer), payload->seqnum, rtptime,
      GST_TIME_ARGS (timestamp));

  res = gst_pad_push (payload->srcpad, buffer);

  return res;

  /* ERRORS */
no_rate:
  {
    GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL),
        ("subclass did not specify clock-rate"));
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }
}