From 35b3e2b59649c3adb6272f37ad8ca686b916161d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 27 Aug 2008 11:28:50 +0000 Subject: [PATCH] gst/realmedia/rdtdepay.*: Check seqnum gaps and drop duplicate packets or mark outgoing buffers with a DISCONT flag w... Original commit message from CVS: * gst/realmedia/rdtdepay.c: (gst_rdt_depay_handle_data), (gst_rdt_depay_change_state): * gst/realmedia/rdtdepay.h: Check seqnum gaps and drop duplicate packets or mark outgoing buffers with a DISCONT flag when needed. * gst/realmedia/rdtmanager.c: (gst_rdt_manager_query_src): Report the configure latency instead of a hardcoded value. --- ChangeLog | 11 ++++++++ gst/realmedia/rdtdepay.c | 51 +++++++++++++++++++++++++++++++++++--- gst/realmedia/rdtdepay.h | 1 + gst/realmedia/rdtmanager.c | 10 ++++++-- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index bd798bfa56..1e93d01f96 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-08-27 Wim Taymans + + * gst/realmedia/rdtdepay.c: (gst_rdt_depay_handle_data), + (gst_rdt_depay_change_state): + * gst/realmedia/rdtdepay.h: + Check seqnum gaps and drop duplicate packets or mark outgoing buffers + with a DISCONT flag when needed. + + * gst/realmedia/rdtmanager.c: (gst_rdt_manager_query_src): + Report the configure latency instead of a hardcoded value. + 2008-08-27 Wim Taymans * gst/realmedia/rdtmanager.c: (create_session), (activate_session), diff --git a/gst/realmedia/rdtdepay.c b/gst/realmedia/rdtdepay.c index 3deacd793c..3668da2f76 100644 --- a/gst/realmedia/rdtdepay.c +++ b/gst/realmedia/rdtdepay.c @@ -222,6 +222,9 @@ gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime, guint size; guint16 stream_id; guint32 timestamp; + gint gap; + guint16 seqnum; + gboolean discont; /* get pointers to the packet data */ gst_rdt_packet_data_peek_data (packet, &data, &size); @@ -236,6 +239,41 @@ gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime, stream_id = gst_rdt_packet_data_get_stream_id (packet); timestamp = gst_rdt_packet_data_get_timestamp (packet); + seqnum = gst_rdt_packet_data_get_seq (packet); + + GST_DEBUG_OBJECT (rdtdepay, "stream_id %u, timestamp %u, seqnum %d", + stream_id, timestamp, seqnum); + + 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; + 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 */ @@ -243,13 +281,19 @@ gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime, GST_WRITE_UINT16_BE (outdata + 10, 0); /* flags */ memcpy (outdata + 12, data, size); - GST_DEBUG_OBJECT (rdtdepay, "Passing on packet " - "stream_id=%u timestamp=%u, outtime %" GST_TIME_FORMAT, stream_id, - timestamp, GST_TIME_ARGS (outtime)); + 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; + } } static GstFlowReturn @@ -355,6 +399,7 @@ gst_rdt_depay_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: + rdtdepay->next_seqnum = -1; break; default: break; diff --git a/gst/realmedia/rdtdepay.h b/gst/realmedia/rdtdepay.h index 2f6f3e905b..9099a4100f 100644 --- a/gst/realmedia/rdtdepay.h +++ b/gst/realmedia/rdtdepay.h @@ -47,6 +47,7 @@ struct _GstRDTDepay GstPad *srcpad; guint clock_rate; + guint32 next_seqnum; gboolean discont; GstBuffer *header; diff --git a/gst/realmedia/rdtmanager.c b/gst/realmedia/rdtmanager.c index 144a0f46bf..1d4540ef6a 100644 --- a/gst/realmedia/rdtmanager.c +++ b/gst/realmedia/rdtmanager.c @@ -528,9 +528,15 @@ gst_rdt_manager_query_src (GstPad * pad, GstQuery * query) switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { + GstClockTime latency; + + latency = rdtmanager->latency * GST_MSECOND; + /* we pretend to be live with a 3 second latency */ - gst_query_set_latency (query, TRUE, 5 * GST_SECOND, -1); - GST_DEBUG_OBJECT (rdtmanager, "reporting 5 seconds of latency"); + gst_query_set_latency (query, TRUE, latency, -1); + + GST_DEBUG_OBJECT (rdtmanager, "reporting %" GST_TIME_FORMAT " of latency", + GST_TIME_ARGS (latency)); res = TRUE; break; }