/** * rtp_jitter_buffer_insert: * @jbuf: an #RTPJitterBuffer * @buf: a buffer * @time: a running_time when this buffer was received in nanoseconds * @clock_rate: the clock-rate of the payload of @buf * @max_delay: the maximum lateness of @buf * @tail: TRUE when the tail element changed. * * Inserts @buf into the packet queue of @jbuf. The sequence number of the * packet will be used to sort the packets. This function takes ownerhip of * @buf when the function returns %TRUE. * @buf should have writable metadata when calling this function. * * Returns: %FALSE if a packet with the same number already existed. */ gboolean rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf, GstClockTime time, guint32 clock_rate, GstClockTime max_delay, gboolean * tail) { GList *list; guint32 rtptime; guint16 seqnum; g_return_val_if_fail (jbuf != NULL, FALSE); g_return_val_if_fail (buf != NULL, FALSE); seqnum = gst_rtp_buffer_get_seq (buf); /* loop the list to skip strictly smaller seqnum buffers */ for (list = jbuf->packets->head; list; list = g_list_next (list)) { guint16 qseq; gint gap; qseq = gst_rtp_buffer_get_seq (GST_BUFFER_CAST (list->data)); /* compare the new seqnum to the one in the buffer */ gap = gst_rtp_buffer_compare_seqnum (seqnum, qseq); /* we hit a packet with the same seqnum, notify a duplicate */ if (G_UNLIKELY (gap == 0)) goto duplicate; /* seqnum > qseq, we can stop looking */ if (G_LIKELY (gap < 0)) break; } /* do skew calculation by measuring the difference between rtptime and the * receive time, this function will retimestamp @buf with the skew corrected * running time. */ rtptime = gst_rtp_buffer_get_timestamp (buf); time = calculate_skew (jbuf, rtptime, time, clock_rate, max_delay); GST_BUFFER_TIMESTAMP (buf) = time; /* It's more likely that the packet was inserted in the front of the buffer */ if (G_LIKELY (list)) g_queue_insert_before (jbuf->packets, list, buf); else g_queue_push_tail (jbuf->packets, buf); /* tail was changed when we did not find a previous packet, we set the return * flag when requested. */ if (G_LIKELY (tail)) *tail = (list == NULL); return TRUE; /* ERRORS */ duplicate: { GST_WARNING ("duplicate packet %d found", (gint) seqnum); return FALSE; } }
static gint _compare_fec_map_info (gconstpointer a, gconstpointer b, gpointer userdata) { guint16 aseq = gst_rtp_buffer_get_seq (&RTP_FEC_MAP_INFO_NTH (userdata, a)->rtp); guint16 bseq = gst_rtp_buffer_get_seq (&RTP_FEC_MAP_INFO_NTH (userdata, b)->rtp); return gst_rtp_buffer_compare_seqnum (bseq, aseq); }
static GstBuffer * gst_rtp_pcma_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; gboolean marker; guint len; marker = gst_rtp_buffer_get_marker (buf); GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d", GST_BUFFER_SIZE (buf), marker, gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf)); len = gst_rtp_buffer_get_payload_len (buf); outbuf = gst_rtp_buffer_get_payload_buffer (buf); if (outbuf) { GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); if (marker) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } } return outbuf; }
void lock_check_cb (GstPad * pad, int i) { GstStructure *s; GstEvent *event; if (i % 2) s = gst_structure_new ("stream-lock", "lock", G_TYPE_BOOLEAN, FALSE, NULL); else s = gst_structure_new ("stream-lock", "lock", G_TYPE_BOOLEAN, TRUE, NULL); event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s); gst_pad_push_event (pad, event); if (i % 2) { fail_unless (buffers == NULL); } else { fail_unless (buffers && g_list_length (buffers) == 1); fail_unless (gst_rtp_buffer_get_ssrc (buffers->data) == 55); fail_unless (gst_rtp_buffer_get_timestamp (buffers->data) == 200 - 57 + 1000 + i); fail_unless (gst_rtp_buffer_get_seq (buffers->data) == 100 + 1 + (i / 2)); g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL); g_list_free (buffers); buffers = NULL; } }
static GstBuffer * gst_rtp_pcmu_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; guint len; gboolean marker; GstRTPBuffer rtp = { NULL }; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); marker = gst_rtp_buffer_get_marker (&rtp); GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (buf), marker, gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp)); len = gst_rtp_buffer_get_payload_len (&rtp); outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); gst_rtp_buffer_unmap (&rtp); if (outbuf) { GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); if (marker) { /* mark start of talkspurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } } return outbuf; }
static GstBuffer * gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf; gboolean marker; GstRTPBuffer rtp = { NULL }; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); marker = gst_rtp_buffer_get_marker (&rtp); GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (buf), marker, gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp)); outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); gst_rtp_buffer_unmap (&rtp); if (marker && outbuf) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } return outbuf; }
static GstBuffer * gst_rtp_gsm_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstBuffer *outbuf = NULL; gboolean marker; marker = gst_rtp_buffer_get_marker (rtp); GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (rtp->buffer), marker, gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp)); outbuf = gst_rtp_buffer_get_payload_buffer (rtp); if (marker && outbuf) { /* mark start of talkspurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } if (outbuf) { gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); } return outbuf; }
void basic_check_cb (GstPad * pad, int i) { fail_unless (buffers && g_list_length (buffers) == 1); fail_unless (gst_rtp_buffer_get_ssrc (buffers->data) == 55); fail_unless (gst_rtp_buffer_get_timestamp (buffers->data) == 200 - 57 + 1000 + i); fail_unless (gst_rtp_buffer_get_seq (buffers->data) == 100 + 1 + i); }
static GstPadProbeReturn rtpsession_sinkpad_probe2 (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) { GstPadProbeReturn ret = GST_PAD_PROBE_OK; if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) { GstBuffer *buffer = GST_BUFFER (info->data); GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; guint payload_type = 0; static gint i = 0; /* retrieve current ssrc for retransmission stream only */ gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp); payload_type = gst_rtp_buffer_get_payload_type (&rtp); if (payload_type == 99) { if (i < 3) rtx_ssrc_before = gst_rtp_buffer_get_ssrc (&rtp); else rtx_ssrc_after = gst_rtp_buffer_get_ssrc (&rtp); } else { /* ask to retransmit every packet */ GstEvent *event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, gst_structure_new ("GstRTPRetransmissionRequest", "seqnum", G_TYPE_UINT, gst_rtp_buffer_get_seq (&rtp), "ssrc", G_TYPE_UINT, gst_rtp_buffer_get_ssrc (&rtp), NULL)); gst_pad_push_event (pad, event); if (i < 3) ssrc_before = gst_rtp_buffer_get_ssrc (&rtp); else ssrc_after = gst_rtp_buffer_get_ssrc (&rtp); } gst_rtp_buffer_unmap (&rtp); /* feint a collision on recv_rtcp_sink pad of gstrtpsession * (note that after being marked as collied the rtpsession ignores * all non bye packets) */ if (i == 2) { GstBuffer *rtcp_buffer = create_rtcp_app (rtx_ssrc_before, 0); /* push collied packet on recv_rtcp_sink */ gst_pad_push (srcpad, rtcp_buffer); } ++i; } return ret; }
static void basic_check_cb (GstPad * pad, int i) { 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); }
static void compare_rtp_packets (GstBuffer * a, GstBuffer * b) { GstRTPBuffer rtp_a = GST_RTP_BUFFER_INIT; GstRTPBuffer rtp_b = GST_RTP_BUFFER_INIT; gst_rtp_buffer_map (a, GST_MAP_READ, &rtp_a); gst_rtp_buffer_map (b, GST_MAP_READ, &rtp_b); fail_unless_equals_int (gst_rtp_buffer_get_header_len (&rtp_a), gst_rtp_buffer_get_header_len (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp_a), gst_rtp_buffer_get_version (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp_a), gst_rtp_buffer_get_ssrc (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp_a), gst_rtp_buffer_get_seq (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp_a), gst_rtp_buffer_get_csrc_count (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_marker (&rtp_a), gst_rtp_buffer_get_marker (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp_a), gst_rtp_buffer_get_payload_type (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp_a), gst_rtp_buffer_get_timestamp (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_extension (&rtp_a), gst_rtp_buffer_get_extension (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_payload_len (&rtp_a), gst_rtp_buffer_get_payload_len (&rtp_b)); fail_unless_equals_int (memcmp (gst_rtp_buffer_get_payload (&rtp_a), gst_rtp_buffer_get_payload (&rtp_b), gst_rtp_buffer_get_payload_len (&rtp_a)), 0); gst_rtp_buffer_unmap (&rtp_a); gst_rtp_buffer_unmap (&rtp_b); }
static void gst_rtp_ulpfec_dec_start (GstRtpUlpFecDec * self, GstBufferList * buflist, guint8 fec_pt, guint16 lost_seq) { guint fec_packets = 0; gsize i; g_assert (NULL == self->info_media); g_assert (0 == self->info_fec->len); g_assert (0 == self->info_arr->len); g_array_set_size (self->info_arr, gst_buffer_list_length (buflist)); for (i = 0; i < gst_buffer_list_length (buflist) && !self->lost_packet_from_storage; ++i) { GstBuffer *buffer = gst_buffer_list_get (buflist, i); RtpUlpFecMapInfo *info = RTP_FEC_MAP_INFO_NTH (self, i); if (!rtp_ulpfec_map_info_map (gst_buffer_ref (buffer), info)) g_assert_not_reached (); if (fec_pt == gst_rtp_buffer_get_payload_type (&info->rtp)) { GST_DEBUG_RTP_PACKET (self, "rtp header (fec)", &info->rtp); ++fec_packets; if (rtp_ulpfec_buffer_is_valid (&info->rtp)) { GST_DEBUG_FEC_PACKET (self, &info->rtp); g_ptr_array_add (self->info_fec, GUINT_TO_POINTER (i)); } } else { GST_LOG_RTP_PACKET (self, "rtp header (incoming)", &info->rtp); if (lost_seq == gst_rtp_buffer_get_seq (&info->rtp)) { GST_DEBUG_OBJECT (self, "Received lost packet from from the storage"); g_list_free (self->info_media); self->info_media = NULL; self->lost_packet_from_storage = TRUE; } self->info_media = g_list_insert_sorted_with_data (self->info_media, GUINT_TO_POINTER (i), _compare_fec_map_info, self); } } if (!self->lost_packet_from_storage) { self->fec_packets_received += fec_packets; self->fec_packets_rejected += fec_packets - self->info_fec->len; } }
static guint64 gst_rtp_ulpfec_dec_get_media_buffers_mask (GstRtpUlpFecDec * self, guint16 fec_seq_base) { guint64 mask = 0; GList *it; for (it = self->info_media; it; it = it->next) { RtpUlpFecMapInfo *info = RTP_FEC_MAP_INFO_NTH (self, it->data); mask |= rtp_ulpfec_packet_mask_from_seqnum (gst_rtp_buffer_get_seq (&info->rtp), fec_seq_base, TRUE); } return mask; }
static GstFlowReturn gst_scream_queue_sink_chain(GstPad *pad, GstObject *parent, GstBuffer *buffer) { GstScreamQueue *self = GST_SCREAM_QUEUE(parent); GstRTPBuffer rtp_buffer = GST_RTP_BUFFER_INIT; GstFlowReturn flow_ret = GST_FLOW_OK; GstScreamDataQueueRtpItem *rtp_item; if (GST_PAD_IS_FLUSHING(pad)) { flow_ret = GST_FLOW_FLUSHING; goto end; } if (!gst_rtp_buffer_map(buffer, GST_MAP_READ, &rtp_buffer)) { flow_ret = GST_FLOW_ERROR; goto end; } rtp_item = g_slice_new(GstScreamDataQueueRtpItem); ((GstDataQueueItem *)rtp_item)->object = GST_MINI_OBJECT(buffer); ((GstDataQueueItem *)rtp_item)->size = gst_buffer_get_size(buffer); ((GstDataQueueItem *)rtp_item)->visible = TRUE; ((GstDataQueueItem *)rtp_item)->duration = GST_BUFFER_DURATION(buffer); ((GstDataQueueItem *)rtp_item)->destroy = (GDestroyNotify) gst_scream_data_queue_rtp_item_free; ((GstScreamDataQueueItem *)rtp_item)->type = GST_SCREAM_DATA_QUEUE_ITEM_TYPE_RTP; ((GstScreamDataQueueItem *)rtp_item)->rtp_ssrc = gst_rtp_buffer_get_ssrc(&rtp_buffer); rtp_item->rtp_pt = gst_rtp_buffer_get_payload_type(&rtp_buffer); rtp_item->gst_ts = GST_BUFFER_PTS(buffer); rtp_item->rtp_seq = gst_rtp_buffer_get_seq(&rtp_buffer); rtp_item->rtp_ts = gst_rtp_buffer_get_timestamp(&rtp_buffer); rtp_item->rtp_marker = gst_rtp_buffer_get_marker(&rtp_buffer); rtp_item->rtp_payload_size = gst_rtp_buffer_get_payload_len(&rtp_buffer); rtp_item->enqueued_time = get_gst_time_us(self); gst_rtp_buffer_unmap(&rtp_buffer); if (self->pass_through) { rtp_item->adapted = FALSE; GST_LOG_OBJECT(self, "passing through: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through); gst_data_queue_push(self->approved_packets, (GstDataQueueItem *)rtp_item); goto end; } GST_LOG_OBJECT(self, "queuing: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through); g_async_queue_push(self->incoming_packets, (gpointer)rtp_item); end: return flow_ret; }
static GstBuffer * gst_rtp_celt_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; guint8 *payload; guint offset, pos, payload_len, total_size, size; guint8 s; GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d", GST_BUFFER_SIZE (buf), gst_rtp_buffer_get_marker (buf), gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf)); payload = gst_rtp_buffer_get_payload (buf); payload_len = gst_rtp_buffer_get_payload_len (buf); /* first count how many bytes are consumed by the size headers and make offset * point to the first data byte */ total_size = 0; offset = 0; while (total_size < payload_len) { size = 0; do { s = payload[offset++]; total_size += s + 1; } while (s == 0xff); } /* offset is now pointing to the payload */ total_size = 0; pos = 0; while (total_size < payload_len) { size = 0; do { s = payload[pos++]; size += s; total_size += size + 1; } while (s == 0xff); outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, offset, size); offset += size; gst_base_rtp_depayload_push (depayload, outbuf); } return NULL; }
static GstBuffer * gst_rtp_ulpfec_dec_recover_from_storage (GstRtpUlpFecDec * self, guint8 * dst_pt, guint16 * dst_seq) { RtpUlpFecMapInfo *info; if (self->lost_packet_returned) return NULL; g_assert (g_list_length (self->info_media) == 1); info = RTP_FEC_MAP_INFO_NTH (self, self->info_media->data); *dst_seq = gst_rtp_buffer_get_seq (&info->rtp); *dst_pt = gst_rtp_buffer_get_payload_type (&info->rtp); self->lost_packet_returned = TRUE; GST_DEBUG_RTP_PACKET (self, "rtp header (recovered)", &info->rtp); return gst_buffer_ref (info->rtp.buffer); }
static GstBuffer * gst_rtp_ilbc_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf; gboolean marker; marker = gst_rtp_buffer_get_marker (buf); GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d", GST_BUFFER_SIZE (buf), marker, gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf)); outbuf = gst_rtp_buffer_get_payload_buffer (buf); if (marker && outbuf) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } return outbuf; }
static GstBuffer * gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstBuffer *outbuf; gboolean marker; marker = gst_rtp_buffer_get_marker (rtp); GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (rtp->buffer), marker, gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp)); outbuf = gst_rtp_buffer_get_payload_buffer (rtp); if (marker && outbuf) { /* mark start of talkspurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } return outbuf; }
static GstBuffer * gst_rtp_speex_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; GstRTPBuffer rtp = { NULL }; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (buf), gst_rtp_buffer_get_marker (&rtp), gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp)); /* nothing special to be done */ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); gst_rtp_buffer_unmap (&rtp); if (outbuf) GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND; return outbuf; }
static void packet_recovered_cb (GObject * internal_storage, GstBuffer * buffer, GList * infos) { gboolean found = FALSE; GstRTPBuffer rtp = { NULL }; fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); for (GList * it = infos; it; it = it->next) { RecoveredPacketInfo *info = it->data; if (gst_rtp_buffer_get_seq (&rtp) == info->seq) { fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), info->pt); fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), info->ssrc); found = TRUE; break; } } gst_rtp_buffer_unmap (&rtp); fail_unless (found); }
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 GstBuffer * gst_rtp_sv3v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpSV3VDepay *rtpsv3vdepay; GstBuffer *outbuf; guint16 seq; rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; /* flush on sequence number gaps */ seq = gst_rtp_buffer_get_seq (buf); if (seq != rtpsv3vdepay->nextseq) { gst_adapter_clear (rtpsv3vdepay->adapter); } rtpsv3vdepay->nextseq = seq + 1; { gint payload_len; guint8 *payload; gboolean M; gboolean C, S, E; payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len < 3) goto bad_packet; payload = gst_rtp_buffer_get_payload (buf); M = gst_rtp_buffer_get_marker (buf); /* This is all a guess: * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * C: config, packet contains config info * S: start, packet contains start of frame * E: end, packet contains end of frame */ /* this seems to indicate a packet with a config string sent before each * keyframe */ C = (payload[0] & 0x40) == 0x40; /* redundant with the RTP marker bit */ S = (payload[0] & 0x20) == 0x20; E = (payload[0] & 0x10) == 0x10; if (C) { GstCaps *caps; GstBuffer *codec_data; GValue value = { 0 }; /* if we already have caps, we don't need to do anything. FIXME, check if * something changed. */ if (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload))) return NULL; /* No idea... These are the two examples I found.. */ if (payload[2] == 0x1d) { rtpsv3vdepay->width = 160; rtpsv3vdepay->height = 128; } else if (payload[2] == 0xdd) { rtpsv3vdepay->width = 320; rtpsv3vdepay->height = 240; } /* we need a dummy empty codec data */ g_value_init (&value, GST_TYPE_BUFFER); gst_value_deserialize (&value, ""); codec_data = gst_value_get_buffer (&value); caps = gst_caps_new_simple ("video/x-svq", "svqversion", G_TYPE_INT, 3, "width", G_TYPE_INT, rtpsv3vdepay->width, "height", G_TYPE_INT, rtpsv3vdepay->height, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps); gst_caps_unref (caps); g_value_unset (&value); return NULL; } /* store data in adapter, stip off 2 bytes header */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); gst_adapter_push (rtpsv3vdepay->adapter, outbuf); if (M) { /* frame is completed: push contents of adapter */ guint avail; avail = gst_adapter_available (rtpsv3vdepay->adapter); outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail); /* timestamp for complete buffer is that of last buffer as well */ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (depayload->srcpad)); return outbuf; } } return NULL; /* ERRORS */ bad_packet: { GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE, ("Packet did not validate"), (NULL)); return NULL; } }
static GstFlowReturn gst_base_rtp_depayload_chain (GstPad * pad, GstBuffer * in) { GstBaseRTPDepayload *filter; GstBaseRTPDepayloadPrivate *priv; GstBaseRTPDepayloadClass *bclass; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *out_buf; GstClockTime timestamp; guint16 seqnum; guint32 rtptime; gboolean reset_seq, discont; gint gap; filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad)); priv = filter->priv; /* we must have a setcaps first */ if (G_UNLIKELY (!priv->negotiated)) goto not_negotiated; /* we must validate, it's possible that this element is plugged right after a * network receiver and we don't want to operate on invalid data */ if (G_UNLIKELY (!gst_rtp_buffer_validate (in))) goto invalid_buffer; priv->discont = GST_BUFFER_IS_DISCONT (in); timestamp = GST_BUFFER_TIMESTAMP (in); /* convert to running_time and save the timestamp, this is the timestamp * we put on outgoing buffers. */ timestamp = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, timestamp); priv->timestamp = timestamp; priv->duration = GST_BUFFER_DURATION (in); seqnum = gst_rtp_buffer_get_seq (in); rtptime = gst_rtp_buffer_get_timestamp (in); reset_seq = TRUE; discont = FALSE; GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, timestamp %" GST_TIME_FORMAT, priv->discont, seqnum, rtptime, GST_TIME_ARGS (timestamp)); /* Check seqnum. This is a very simple check that makes sure that the seqnums * are striclty increasing, dropping anything that is out of the ordinary. We * can only do this when the next_seqnum is known. */ if (G_LIKELY (priv->next_seqnum != -1)) { gap = gst_rtp_buffer_compare_seqnum (seqnum, priv->next_seqnum); /* if we have no gap, all is fine */ if (G_UNLIKELY (gap != 0)) { GST_LOG_OBJECT (filter, "got packet %u, expected %u, gap %d", seqnum, priv->next_seqnum, gap); if (gap < 0) { /* seqnum > next_seqnum, we are missing some packets, this is always a * DISCONT. */ GST_LOG_OBJECT (filter, "%d missing packets", gap); discont = TRUE; } else { /* seqnum < next_seqnum, we have seen this packet before or the sender * could be restarted. If the packet is not too old, we throw it away as * a duplicate, otherwise we mark discont and continue. 100 misordered * packets is a good threshold. See also RFC 4737. */ if (gap < 100) goto dropping; GST_LOG_OBJECT (filter, "%d > 100, packet too old, sender likely restarted", gap); discont = TRUE; } } } priv->next_seqnum = (seqnum + 1) & 0xffff; if (G_UNLIKELY (discont && !priv->discont)) { GST_LOG_OBJECT (filter, "mark DISCONT on input buffer"); /* we detected a seqnum discont but the buffer was not flagged with a discont, * set the discont flag so that the subclass can throw away old data. */ priv->discont = TRUE; GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT); } bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); if (G_UNLIKELY (bclass->process == NULL)) goto no_process; /* let's send it out to processing */ out_buf = bclass->process (filter, in); if (out_buf) { /* we pass rtptime as backward compatibility, in reality, the incomming * buffer timestamp is always applied to the outgoing packet. */ ret = gst_base_rtp_depayload_push_ts (filter, rtptime, out_buf); } gst_buffer_unref (in); return ret; /* ERRORS */ not_negotiated: { /* this is not fatal but should be filtered earlier */ GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), ("Not RTP format was negotiated")); gst_buffer_unref (in); return GST_FLOW_NOT_NEGOTIATED; } invalid_buffer: { /* this is not fatal but should be filtered earlier */ GST_ELEMENT_WARNING (filter, STREAM, DECODE, (NULL), ("Received invalid RTP payload, dropping")); gst_buffer_unref (in); return GST_FLOW_OK; } dropping: { GST_WARNING_OBJECT (filter, "%d <= 100, dropping old packet", gap); gst_buffer_unref (in); return GST_FLOW_OK; } no_process: { /* this is not fatal but should be filtered earlier */ GST_ELEMENT_ERROR (filter, STREAM, NOT_IMPLEMENTED, (NULL), ("The subclass does not have a process method")); gst_buffer_unref (in); return GST_FLOW_ERROR; } }
gboolean kms_rtp_synchronizer_process_rtp_buffer_mapped (KmsRtpSynchronizer * self, GstRTPBuffer * rtp_buffer, GError ** error) { GstBuffer *buffer = rtp_buffer->buffer; guint64 pts_orig, ext_ts, last_sr_ext_ts, last_sr_ntp_ns_time; guint64 diff_ntp_ns_time; guint8 pt; guint32 ssrc, ts; gint32 clock_rate; gboolean ret = TRUE; ssrc = gst_rtp_buffer_get_ssrc (rtp_buffer); KMS_RTP_SYNCHRONIZER_LOCK (self); if (self->priv->ssrc == 0) { self->priv->ssrc = ssrc; } else if (ssrc != self->priv->ssrc) { gchar *msg = g_strdup_printf ("Invalid SSRC (%u), not matching with %u", ssrc, self->priv->ssrc); GST_ERROR_OBJECT (self, "%s", msg); g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA, msg); g_free (msg); KMS_RTP_SYNCHRONIZER_UNLOCK (self); return FALSE; } pt = gst_rtp_buffer_get_payload_type (rtp_buffer); if (pt != self->priv->pt || self->priv->clock_rate <= 0) { gchar *msg = g_strdup_printf ("Invalid clock-rate %d for PT %u, not changing PTS", self->priv->clock_rate, pt); GST_ERROR_OBJECT (self, "%s", msg); g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA, msg); g_free (msg); KMS_RTP_SYNCHRONIZER_UNLOCK (self); return FALSE; } pts_orig = GST_BUFFER_PTS (buffer); ts = gst_rtp_buffer_get_timestamp (rtp_buffer); gst_rtp_buffer_ext_timestamp (&self->priv->ext_ts, ts); if (self->priv->feeded_sorted) { if (self->priv->fs_last_ext_ts != -1 && self->priv->ext_ts < self->priv->fs_last_ext_ts) { guint16 seq = gst_rtp_buffer_get_seq (rtp_buffer); gchar *msg = g_strdup_printf ("Received an unsorted RTP buffer when expecting sorted (ssrc: %" G_GUINT32_FORMAT ", seq: %" G_GUINT16_FORMAT ", ts: %" G_GUINT32_FORMAT ", ext_ts: %" G_GUINT64_FORMAT "). Moving to unsorted mode", ssrc, seq, ts, self->priv->ext_ts); GST_ERROR_OBJECT (self, "%s", msg); g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA, msg); g_free (msg); self->priv->feeded_sorted = FALSE; ret = FALSE; } else if (self->priv->ext_ts == self->priv->fs_last_ext_ts) { GST_BUFFER_PTS (buffer) = self->priv->fs_last_pts; goto end; } } if (!self->priv->base_initiated) { GST_DEBUG_OBJECT (self, "Do not sync data for SSRC %u and PT %u, interpolating PTS", ssrc, pt); if (!self->priv->base_interpolate_initiated) { self->priv->base_interpolate_ext_ts = self->priv->ext_ts; self->priv->base_interpolate_time = GST_BUFFER_PTS (buffer); self->priv->base_interpolate_initiated = TRUE; } else { buffer = gst_buffer_make_writable (buffer); GST_BUFFER_PTS (buffer) = self->priv->base_interpolate_time; kms_rtp_synchronizer_rtp_diff (self, rtp_buffer, self->priv->clock_rate, self->priv->base_interpolate_ext_ts); } } else { gboolean wrapped_down, wrapped_up; wrapped_down = wrapped_up = FALSE; buffer = gst_buffer_make_writable (buffer); GST_BUFFER_PTS (buffer) = self->priv->base_sync_time; if (self->priv->last_sr_ntp_ns_time > self->priv->base_ntp_ns_time) { diff_ntp_ns_time = self->priv->last_sr_ntp_ns_time - self->priv->base_ntp_ns_time; wrapped_up = diff_ntp_ns_time > (G_MAXUINT64 - GST_BUFFER_PTS (buffer)); GST_BUFFER_PTS (buffer) += diff_ntp_ns_time; } else if (self->priv->last_sr_ntp_ns_time < self->priv->base_ntp_ns_time) { diff_ntp_ns_time = self->priv->base_ntp_ns_time - self->priv->last_sr_ntp_ns_time; wrapped_down = GST_BUFFER_PTS (buffer) < diff_ntp_ns_time; GST_BUFFER_PTS (buffer) -= diff_ntp_ns_time; } /* if equals do nothing */ kms_rtp_synchronizer_rtp_diff_full (self, rtp_buffer, self->priv->clock_rate, self->priv->last_sr_ext_ts, wrapped_down, wrapped_up); } if (self->priv->feeded_sorted) { if (GST_BUFFER_PTS (buffer) < self->priv->fs_last_pts) { guint16 seq = gst_rtp_buffer_get_seq (rtp_buffer); GST_WARNING_OBJECT (self, "Non monotonic PTS assignment in sorted mode (ssrc: %" G_GUINT32_FORMAT ", seq: %" G_GUINT16_FORMAT ", ts: %" G_GUINT32_FORMAT ", ext_ts: %" G_GUINT64_FORMAT "). Forcing monotonic", ssrc, seq, ts, self->priv->ext_ts); GST_BUFFER_PTS (buffer) = self->priv->fs_last_pts; } self->priv->fs_last_ext_ts = self->priv->ext_ts; self->priv->fs_last_pts = GST_BUFFER_PTS (buffer); } end: clock_rate = self->priv->clock_rate; ext_ts = self->priv->ext_ts; last_sr_ext_ts = self->priv->last_sr_ext_ts; last_sr_ntp_ns_time = self->priv->last_sr_ntp_ns_time; KMS_RTP_SYNCHRONIZER_UNLOCK (self); kms_rtp_sync_context_write_stats (self->priv->context, ssrc, clock_rate, pts_orig, GST_BUFFER_PTS (buffer), GST_BUFFER_DTS (buffer), ext_ts, last_sr_ntp_ns_time, last_sr_ext_ts); return ret; }
static GstBuffer * gst_rtp_qdm2_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpQDM2Depay *rtpqdm2depay; GstBuffer *outbuf; guint16 seq; rtpqdm2depay = GST_RTP_QDM2_DEPAY (depayload); { gint payload_len; guint8 *payload; guint avail; guint pos = 0; payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len < 3) goto bad_packet; payload = gst_rtp_buffer_get_payload (buf); seq = gst_rtp_buffer_get_seq (buf); if (G_UNLIKELY (seq != rtpqdm2depay->nextseq)) { GST_DEBUG ("GAP in sequence number, Resetting data !"); /* Flush previous data */ flush_data (rtpqdm2depay); /* And store new timestamp */ rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp; rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf); /* And that previous data will be pushed at the bottom */ } rtpqdm2depay->nextseq = seq + 1; GST_DEBUG ("Payload size %d 0x%x sequence:%d", payload_len, payload_len, seq); GST_MEMDUMP ("Incoming payload", payload, payload_len); while (pos < payload_len) { switch (payload[pos]) { case 0x80:{ GST_DEBUG ("Unrecognized 0x80 marker, skipping 12 bytes"); pos += 12; } break; case 0xff: /* HEADERS */ GST_DEBUG ("Headers"); /* Store the incoming timestamp */ rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp; rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf); /* flush the internal data if needed */ flush_data (rtpqdm2depay); if (G_UNLIKELY (!rtpqdm2depay->configured)) { guint8 *ourdata; GstBuffer *codecdata; GstCaps *caps; /* First bytes are unknown */ GST_MEMDUMP ("Header", payload + pos, 32); ourdata = payload + pos + 10; pos += 10; rtpqdm2depay->channs = GST_READ_UINT32_BE (payload + pos + 4); rtpqdm2depay->samplerate = GST_READ_UINT32_BE (payload + pos + 8); rtpqdm2depay->bitrate = GST_READ_UINT32_BE (payload + pos + 12); rtpqdm2depay->blocksize = GST_READ_UINT32_BE (payload + pos + 16); rtpqdm2depay->framesize = GST_READ_UINT32_BE (payload + pos + 20); rtpqdm2depay->packetsize = GST_READ_UINT32_BE (payload + pos + 24); /* 16 bit empty block (0x02 0x00) */ pos += 30; GST_DEBUG ("channs:%d, samplerate:%d, bitrate:%d, blocksize:%d, framesize:%d, packetsize:%d", rtpqdm2depay->channs, rtpqdm2depay->samplerate, rtpqdm2depay->bitrate, rtpqdm2depay->blocksize, rtpqdm2depay->framesize, rtpqdm2depay->packetsize); /* Caps */ codecdata = gst_buffer_new_and_alloc (48); memcpy (GST_BUFFER_DATA (codecdata), headheader, 20); memcpy (GST_BUFFER_DATA (codecdata) + 20, ourdata, 28); caps = gst_caps_new_simple ("audio/x-qdm2", "samplesize", G_TYPE_INT, 16, "rate", G_TYPE_INT, rtpqdm2depay->samplerate, "channels", G_TYPE_INT, rtpqdm2depay->channs, "codec_data", GST_TYPE_BUFFER, codecdata, NULL); gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps); gst_caps_unref (caps); rtpqdm2depay->configured = TRUE; } else { GST_DEBUG ("Already configured, skipping headers"); pos += 40; } break; default:{ /* Shuffled packet contents */ guint packetid = payload[pos++]; guint packettype = payload[pos++]; guint packlen = payload[pos++]; guint hsize = 2; GST_DEBUG ("Packet id:%d, type:0x%x, len:%d", packetid, packettype, packlen); /* Packets bigger than 0xff bytes have a type with the high bit set */ if (G_UNLIKELY (packettype & 0x80)) { packettype &= 0x7f; packlen <<= 8; packlen |= payload[pos++]; hsize = 3; GST_DEBUG ("Packet id:%d, type:0x%x, len:%d", packetid, packettype, packlen); } if (packettype > 0x7f) { GST_ERROR ("HOUSTON WE HAVE A PROBLEM !!!!"); } add_packet (rtpqdm2depay, packetid, packlen + hsize, payload + pos - hsize); pos += packlen; } } } GST_DEBUG ("final pos %d", pos); avail = gst_adapter_available (rtpqdm2depay->adapter); if (G_UNLIKELY (avail)) { GST_DEBUG ("Pushing out %d bytes of collected data", avail); outbuf = gst_adapter_take_buffer (rtpqdm2depay->adapter, avail); GST_BUFFER_TIMESTAMP (outbuf) = rtpqdm2depay->ptimestamp; GST_DEBUG ("Outgoing buffer timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (rtpqdm2depay->ptimestamp)); return outbuf; } } return NULL; /* ERRORS */ bad_packet: { GST_ELEMENT_WARNING (rtpqdm2depay, STREAM, DECODE, (NULL), ("Packet was too short")); return NULL; } }
static void fec_dec_recover_packets(fec_dec *dec) { of_session_t *session; of_rs_parameters_t params; void **encoding_symbol_tab; guint i; GList *link; assert(dec->has_snbase); assert(dec->max_packet_size > 0); encoding_symbol_tab = malloc(sizeof(void*) * (dec->num_media_packets + dec->num_fec_packets)); memset(encoding_symbol_tab, 0, sizeof(void*) * (dec->num_media_packets + dec->num_fec_packets)); for (link = g_queue_peek_head_link(dec->media_packets); link != NULL; link = link->next) { GstBuffer *media_packet; guint32 seqnum; media_packet = link->data; seqnum = fec_dec_correct_seqnum(dec, gst_rtp_buffer_get_seq(media_packet)); encoding_symbol_tab[seqnum - dec->cur_snbase] = GST_BUFFER_DATA(media_packet); } for (link = g_queue_peek_head_link(dec->fec_packets); link != NULL; link = link->next) { GstBuffer *packet; guint8 *fec_data; guint8 esi; packet = link->data; fec_data = GST_BUFFER_DATA(packet) + gst_rtp_buffer_get_header_len(packet); esi = fec_data[12]; encoding_symbol_tab[esi + dec->num_media_packets] = fec_data + RTP_FEC_HEADER_SIZE + 1; } params.nb_source_symbols = dec->num_media_packets; params.nb_repair_symbols = dec->num_fec_packets; params.encoding_symbol_length = dec->max_packet_size; of_create_codec_instance(&session, OF_CODEC_REED_SOLOMON_GF_2_8_STABLE, OF_DECODER, 0); of_set_fec_parameters(session, (of_parameters_t*)(¶ms)); of_set_callback_functions(session, fec_dec_source_packet_cb, NULL, dec); #if 1 for (i = 0; i < dec->num_media_packets + dec->num_fec_packets; ++i) { if (encoding_symbol_tab[i] != 0) of_decode_with_new_symbol(session, encoding_symbol_tab[i], i); } #else of_set_available_symbols(session, encoding_symbol_tab); #endif if (!of_is_decoding_complete(session)) { of_finish_decoding(session); } free(encoding_symbol_tab); of_release_codec_instance(session); }
void fec_dec_push_media_packet(fec_dec *dec, GstBuffer *packet) { guint32 original_seqnum; original_seqnum = gst_rtp_buffer_get_seq(packet); if (g_hash_table_lookup_extended(dec->media_packet_set, GINT_TO_POINTER(original_seqnum), NULL, NULL)) { GST_DEBUG("Media packet with seqnum %u is already in queue - discarding duplicate", original_seqnum); return; } if (dec->has_snbase) { guint32 corrected_seqnum; corrected_seqnum = fec_dec_correct_seqnum(dec, original_seqnum); GST_DEBUG("Pushing media packet with seqnum %u, current snbase is %u", original_seqnum, dec->cur_snbase); if ((corrected_seqnum - (guint32)(dec->cur_snbase)) >= dec->num_media_packets) { GST_DEBUG("Distance between FEC packets and incoming media packets is too large - purging %u FEC packets and setting has_snbase to FALSE", dec->num_received_fec_packets); dec->has_snbase = FALSE; dec->blacklisted_snbase = dec->cur_snbase; g_queue_foreach(dec->fec_packets, fec_dec_clear_packet, NULL); g_queue_clear(dec->fec_packets); g_hash_table_remove_all(dec->fec_packet_set); dec->num_received_fec_packets = 0; GST_DEBUG("Pushing media packet with seqnum %u, no current snbase set", original_seqnum); g_queue_push_tail(dec->media_packets, gst_buffer_ref(packet)); g_hash_table_add(dec->media_packet_set, GINT_TO_POINTER(original_seqnum)); ++dec->num_received_media_packets; } else if ((corrected_seqnum >= (guint32)(dec->cur_snbase)) && (corrected_seqnum <= ((guint32)(dec->cur_snbase) + ((guint32)(dec->num_media_packets)) - 1))) { g_queue_push_tail(dec->media_packets, gst_buffer_ref(packet)); g_hash_table_add(dec->media_packet_set, GINT_TO_POINTER(original_seqnum)); ++dec->num_received_media_packets; dec->received_media_packet_mask |= (1ul << (corrected_seqnum - dec->cur_snbase)); dec->max_packet_size = MAX(dec->max_packet_size, GST_BUFFER_SIZE(packet)); fec_dec_check_state(dec); } else { GST_DEBUG("Received media packet with seqnum %u outside bounds [%u, %u] - pushing aborted", original_seqnum, dec->cur_snbase, dec->cur_snbase + dec->num_media_packets - 1); } } else { GST_DEBUG("Pushing media packet with seqnum %u, no current snbase set", original_seqnum); g_queue_push_tail(dec->media_packets, gst_buffer_ref(packet)); g_hash_table_add(dec->media_packet_set, GINT_TO_POINTER(original_seqnum)); ++dec->num_received_media_packets; } if (dec->num_received_media_packets > dec->num_media_packets) { guint i; GST_DEBUG("Too many media packets in queue - deleting the %u oldest packets", dec->num_received_media_packets - dec->num_media_packets); for (i = dec->num_media_packets; i < dec->num_received_media_packets; ++i) { GstBuffer *media_packet; guint16 seqnum; media_packet = g_queue_pop_head(dec->media_packets); seqnum = gst_rtp_buffer_get_seq(packet); g_hash_table_remove(dec->media_packet_set, GINT_TO_POINTER(seqnum)); gst_buffer_unref(media_packet); } dec->num_received_media_packets = dec->num_media_packets; } }
void fec_dec_push_fec_packet(fec_dec *dec, GstBuffer *packet) { guint8 *fec_data; guint32 snbase; guint16 seqnum; GList *link; fec_data = GST_BUFFER_DATA(packet) + gst_rtp_buffer_get_header_len(packet); snbase = (((guint16)(fec_data[0])) << 8) | (((guint16)(fec_data[1])) << 0); seqnum = gst_rtp_buffer_get_seq(packet); GST_DEBUG("Received FEC packet, snbase %u, index %u, seqnum %u", snbase, (guint)(fec_data[12]), seqnum); if (snbase == dec->blacklisted_snbase) { GST_DEBUG("Ignoring FEC packet since data from this snbase has been restored already (= the packet is not needed)"); return; } if (g_hash_table_lookup_extended(dec->fec_packet_set, GINT_TO_POINTER(seqnum), NULL, NULL)) { GST_DEBUG("FEC packet with seqnum %u is already in queue - discarding duplicate", seqnum); return; } if (dec->cur_snbase != snbase) { GST_DEBUG("snbase changed from %u to %u - purging FEC queue (%u FEC packets and %u media packets present)", dec->cur_snbase, snbase, dec->num_received_fec_packets, dec->num_received_media_packets); g_queue_foreach(dec->fec_packets, fec_dec_clear_packet, NULL); g_queue_clear(dec->fec_packets); g_hash_table_remove_all(dec->fec_packet_set); dec->num_received_fec_packets = 0; } dec->cur_snbase = snbase; dec->has_snbase = TRUE; dec->received_media_packet_mask = 0; dec->num_received_media_packets = 0; dec->max_packet_size = 0; g_queue_push_tail(dec->fec_packets, gst_buffer_ref(packet)); g_hash_table_add(dec->fec_packet_set, GINT_TO_POINTER(seqnum)); ++dec->num_received_fec_packets; for (link = g_queue_peek_head_link(dec->media_packets); link != NULL;) { GstBuffer *media_packet; guint32 corrected_seqnum; media_packet = link->data; seqnum = gst_rtp_buffer_get_seq(media_packet); corrected_seqnum = fec_dec_correct_seqnum(dec, seqnum); if ((corrected_seqnum < snbase) || (corrected_seqnum > (snbase + dec->num_media_packets - 1))) { GList *old_link; GST_DEBUG("Found media packet with seqnum %u outside bounds [%u, %u] - purging", seqnum, snbase, snbase + dec->num_media_packets - 1); g_hash_table_remove(dec->media_packet_set, GINT_TO_POINTER(seqnum)); gst_buffer_unref(media_packet); old_link = link; link = link->next; g_queue_delete_link(dec->media_packets, old_link); } else { dec->max_packet_size = MAX(dec->max_packet_size, GST_BUFFER_SIZE(media_packet)); dec->received_media_packet_mask |= (1ul << (corrected_seqnum - dec->cur_snbase)); ++dec->num_received_media_packets; link = link->next; } } fec_dec_check_state(dec); }
/* * This function should be called while holding the filter lock */ static gboolean gst_srtp_dec_decode_buffer (GstSrtpDec * filter, GstPad * pad, GstBuffer * buf, gboolean is_rtcp, guint32 ssrc) { GstMapInfo map; err_status_t err; gint size; GST_LOG_OBJECT (pad, "Received %s buffer of size %" G_GSIZE_FORMAT " with SSRC = %u", is_rtcp ? "RTCP" : "RTP", gst_buffer_get_size (buf), ssrc); /* Change buffer to remove protection */ buf = gst_buffer_make_writable (buf); gst_buffer_map (buf, &map, GST_MAP_READWRITE); size = map.size; unprotect: gst_srtp_init_event_reporter (); if (is_rtcp) err = srtp_unprotect_rtcp (filter->session, map.data, &size); else { /* If ROC has changed, we know we need to set the initial RTP * sequence number too. */ if (filter->roc_changed) { srtp_stream_t stream; stream = srtp_get_stream (filter->session, htonl (ssrc)); if (stream) { guint16 seqnum = 0; GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT; gst_rtp_buffer_map (buf, GST_MAP_READ | GST_RTP_BUFFER_MAP_FLAG_SKIP_PADDING, &rtpbuf); seqnum = gst_rtp_buffer_get_seq (&rtpbuf); gst_rtp_buffer_unmap (&rtpbuf); /* We finally add the RTP sequence number to the current * rollover counter. */ stream->rtp_rdbx.index &= ~0xFFFF; stream->rtp_rdbx.index |= seqnum; } filter->roc_changed = FALSE; } err = srtp_unprotect (filter->session, map.data, &size); } GST_OBJECT_UNLOCK (filter); if (err != err_status_ok) { GST_WARNING_OBJECT (pad, "Unable to unprotect buffer (unprotect failed code %d)", err); /* Signal user depending on type of error */ switch (err) { case err_status_key_expired: GST_OBJECT_LOCK (filter); /* Update stream */ if (find_stream_by_ssrc (filter, ssrc)) { GST_OBJECT_UNLOCK (filter); if (request_key_with_signal (filter, ssrc, SIGNAL_HARD_LIMIT)) { GST_OBJECT_LOCK (filter); goto unprotect; } else { GST_WARNING_OBJECT (filter, "Hard limit reached, no new key, " "dropping"); } } else { GST_WARNING_OBJECT (filter, "Could not find matching stream, " "dropping"); } break; case err_status_auth_fail: GST_WARNING_OBJECT (filter, "Error authentication packet, dropping"); break; case err_status_cipher_fail: GST_WARNING_OBJECT (filter, "Error while decrypting packet, dropping"); break; default: GST_WARNING_OBJECT (filter, "Other error, dropping"); break; } gst_buffer_unmap (buf, &map); GST_OBJECT_LOCK (filter); return FALSE; } gst_buffer_unmap (buf, &map); gst_buffer_set_size (buf, size); GST_OBJECT_LOCK (filter); return TRUE; }
static GstBuffer * gst_rtp_celt_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstBuffer *outbuf = NULL; guint8 *payload; guint offset, pos, payload_len, total_size, size; guint8 s; gint clock_rate = 0, frame_size = 0; GstClockTime framesize_ns = 0, timestamp; guint n = 0; GstRtpCELTDepay *rtpceltdepay; rtpceltdepay = GST_RTP_CELT_DEPAY (depayload); clock_rate = depayload->clock_rate; frame_size = rtpceltdepay->frame_size; framesize_ns = gst_util_uint64_scale_int (frame_size, GST_SECOND, clock_rate); timestamp = GST_BUFFER_PTS (rtp->buffer); GST_LOG_OBJECT (depayload, "got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (rtp->buffer), gst_rtp_buffer_get_marker (rtp), gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp)); GST_LOG_OBJECT (depayload, "got clock-rate=%d, frame_size=%d, " "_ns=%" GST_TIME_FORMAT ", timestamp=%" GST_TIME_FORMAT, clock_rate, frame_size, GST_TIME_ARGS (framesize_ns), GST_TIME_ARGS (timestamp)); payload = gst_rtp_buffer_get_payload (rtp); payload_len = gst_rtp_buffer_get_payload_len (rtp); /* first count how many bytes are consumed by the size headers and make offset * point to the first data byte */ total_size = 0; offset = 0; while (total_size < payload_len) { do { s = payload[offset++]; total_size += s + 1; } while (s == 0xff); } /* offset is now pointing to the payload */ total_size = 0; pos = 0; while (total_size < payload_len) { n++; size = 0; do { s = payload[pos++]; size += s; total_size += s + 1; } while (s == 0xff); outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, size); offset += size; if (frame_size != -1 && clock_rate != -1) { GST_BUFFER_PTS (outbuf) = timestamp + framesize_ns * n; GST_BUFFER_DURATION (outbuf) = framesize_ns; } GST_LOG_OBJECT (depayload, "push timestamp=%" GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)), GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf))); gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); gst_rtp_base_depayload_push (depayload, outbuf); } return NULL; }