static GstFlowReturn gst_rdt_depay_chain (GstPad * pad, GstBuffer * buf) { GstRDTDepay *rdtdepay; GstFlowReturn ret; GstClockTime timestamp; gboolean more; GstRDTPacket packet; rdtdepay = GST_RDT_DEPAY (GST_PAD_PARENT (pad)); if (GST_BUFFER_IS_DISCONT (buf)) { GST_LOG_OBJECT (rdtdepay, "received discont"); rdtdepay->discont = TRUE; } if (rdtdepay->header) { GstBuffer *out; out = rdtdepay->header; rdtdepay->header = NULL; /* push header data first */ ret = gst_rdt_depay_push (rdtdepay, out); } /* save timestamp */ timestamp = GST_BUFFER_TIMESTAMP (buf); ret = GST_FLOW_OK; GST_LOG_OBJECT (rdtdepay, "received buffer timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); /* data is in RDT format. */ more = gst_rdt_buffer_get_first_packet (buf, &packet); while (more) { GstRDTType type; type = gst_rdt_packet_get_type (&packet); GST_DEBUG_OBJECT (rdtdepay, "Have packet of type %04x", type); if (GST_RDT_IS_DATA_TYPE (type)) { GST_DEBUG_OBJECT (rdtdepay, "We have a data packet"); ret = gst_rdt_depay_handle_data (rdtdepay, timestamp, &packet); } else { switch (type) { default: GST_DEBUG_OBJECT (rdtdepay, "Ignoring packet"); break; } } if (ret != GST_FLOW_OK) break; more = gst_rdt_packet_move_to_next (&packet); } return ret; }
static 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; } }