static GstFlowReturn gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime, GstRDTPacket * packet) { GstFlowReturn ret; GstBuffer *outbuf; GstMapInfo outmap; guint8 *data, *outdata; guint size; guint16 stream_id; guint32 timestamp; gint gap; guint16 seqnum; guint8 flags; guint16 outflags; /* get pointers to the packet data */ data = gst_rdt_packet_data_map (packet, &size); outbuf = gst_buffer_new_and_alloc (12 + size); GST_BUFFER_TIMESTAMP (outbuf) = outtime; GST_DEBUG_OBJECT (rdtdepay, "have size %u", size); /* copy over some things */ stream_id = gst_rdt_packet_data_get_stream_id (packet); timestamp = gst_rdt_packet_data_get_timestamp (packet); flags = gst_rdt_packet_data_get_flags (packet); seqnum = gst_rdt_packet_data_get_seq (packet); GST_DEBUG_OBJECT (rdtdepay, "stream_id %u, timestamp %u, seqnum %d, flags %d", stream_id, timestamp, seqnum, flags); if (rdtdepay->next_seqnum != -1) { gap = gst_rdt_buffer_compare_seqnum (seqnum, rdtdepay->next_seqnum); /* if we have no gap, all is fine */ if (G_UNLIKELY (gap != 0)) { GST_LOG_OBJECT (rdtdepay, "got packet %u, expected %u, gap %d", seqnum, rdtdepay->next_seqnum, gap); if (gap < 0) { /* seqnum > next_seqnum, we are missing some packets, this is always a * DISCONT. */ GST_LOG_OBJECT (rdtdepay, "%d missing packets", gap); rdtdepay->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 (rdtdepay, "%d > 100, packet too old, sender likely restarted", gap); rdtdepay->discont = TRUE; } } } rdtdepay->next_seqnum = (seqnum + 1); if (rdtdepay->next_seqnum == 0xff00) rdtdepay->next_seqnum = 0; if ((flags & 1) == 0) outflags = 2; else outflags = 0; gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE); outdata = outmap.data; GST_WRITE_UINT16_BE (outdata + 0, 0); /* version */ GST_WRITE_UINT16_BE (outdata + 2, size + 12); /* length */ GST_WRITE_UINT16_BE (outdata + 4, stream_id); /* stream */ GST_WRITE_UINT32_BE (outdata + 6, timestamp); /* timestamp */ GST_WRITE_UINT16_BE (outdata + 10, outflags); /* flags */ memcpy (outdata + 12, data, size); gst_buffer_unmap (outbuf, &outmap); gst_buffer_resize (outbuf, 0, 12 + size); gst_rdt_packet_data_unmap (packet); GST_DEBUG_OBJECT (rdtdepay, "Pushing packet, outtime %" GST_TIME_FORMAT, GST_TIME_ARGS (outtime)); ret = gst_rdt_depay_push (rdtdepay, outbuf); return ret; /* ERRORS */ dropping: { GST_WARNING_OBJECT (rdtdepay, "%d <= 100, dropping old packet", gap); return GST_FLOW_OK; } }
/** * rdt_jitter_buffer_insert: * @jbuf: an #RDTJitterBuffer * @buf: a buffer * @time: a running_time when this buffer was received in nanoseconds * @clock_rate: the clock-rate of the payload 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 rdt_jitter_buffer_insert (RDTJitterBuffer * jbuf, GstBuffer * buf, GstClockTime time, guint32 clock_rate, gboolean * tail) { GList *list; guint32 rtptime; guint16 seqnum; GstRDTPacket packet; gboolean more; g_return_val_if_fail (jbuf != NULL, FALSE); g_return_val_if_fail (buf != NULL, FALSE); more = gst_rdt_buffer_get_first_packet (buf, &packet); /* programmer error */ g_return_val_if_fail (more == TRUE, FALSE); seqnum = gst_rdt_packet_data_get_seq (&packet); /* 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_rdt_packet_data_get_timestamp (&packet); /* loop the list to skip strictly smaller seqnum buffers */ for (list = jbuf->packets->head; list; list = g_list_next (list)) { guint16 qseq; gint gap; more = gst_rdt_buffer_get_first_packet (GST_BUFFER_CAST (list->data), &packet); /* programmer error */ g_return_val_if_fail (more == TRUE, FALSE); qseq = gst_rdt_packet_data_get_seq (&packet); /* compare the new seqnum to the one in the buffer */ gap = gst_rdt_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; } if (clock_rate) { time = calculate_skew (jbuf, rtptime, time, clock_rate); GST_BUFFER_TIMESTAMP (buf) = time; } if (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 (tail) *tail = (list == NULL); return TRUE; /* ERRORS */ duplicate: { GST_WARNING ("duplicate packet %d found", (gint) seqnum); return FALSE; } }