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; }
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); }
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); }
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; }
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; }
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); }
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; } }