gst/realmedia/rdtdepay.*: Parse other values from the incomming caps.

Original commit message from CVS:
* gst/realmedia/rdtdepay.c: (gst_rdt_depay_init),
(gst_rdt_depay_setcaps), (gst_rdt_depay_sink_event),
(create_segment_event), (gst_rdt_depay_push),
(gst_rdt_depay_handle_data), (gst_rdt_depay_change_state):
* gst/realmedia/rdtdepay.h:
Parse other values from the incomming caps.
Add event handler to handle flushing and segments.
Create segment events.
* gst/realmedia/rdtjitterbuffer.c: (rdt_jitter_buffer_insert):
Do skew correction based on RDT timestamps.
* gst/realmedia/rdtmanager.c: (activate_session),
(gst_rdt_manager_parse_caps), (gst_rdt_manager_setcaps),
(create_recv_rtp):
Parse caps to get the clockrate needed for the jitterbuffer.
* gst/realmedia/rmdemux.c: (gst_rmdemux_parse_video_packet):
Apply timestamp fixup after correcting for initial timestamp and
internal base timestamp corrections.
This commit is contained in:
Wim Taymans 2008-08-27 15:55:05 +00:00
parent 35b3e2b596
commit ff1503f5cf
6 changed files with 236 additions and 19 deletions

View file

@ -1,3 +1,26 @@
2008-08-27 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/realmedia/rdtdepay.c: (gst_rdt_depay_init),
(gst_rdt_depay_setcaps), (gst_rdt_depay_sink_event),
(create_segment_event), (gst_rdt_depay_push),
(gst_rdt_depay_handle_data), (gst_rdt_depay_change_state):
* gst/realmedia/rdtdepay.h:
Parse other values from the incomming caps.
Add event handler to handle flushing and segments.
Create segment events.
* gst/realmedia/rdtjitterbuffer.c: (rdt_jitter_buffer_insert):
Do skew correction based on RDT timestamps.
* gst/realmedia/rdtmanager.c: (activate_session),
(gst_rdt_manager_parse_caps), (gst_rdt_manager_setcaps),
(create_recv_rtp):
Parse caps to get the clockrate needed for the jitterbuffer.
* gst/realmedia/rmdemux.c: (gst_rmdemux_parse_video_packet):
Apply timestamp fixup after correcting for initial timestamp and
internal base timestamp corrections.
2008-08-27 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/realmedia/rdtdepay.c: (gst_rdt_depay_handle_data),

View file

@ -84,6 +84,7 @@ static GstStateChangeReturn gst_rdt_depay_change_state (GstElement *
element, GstStateChange transition);
static gboolean gst_rdt_depay_setcaps (GstPad * pad, GstCaps * caps);
static gboolean gst_rdt_depay_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_rdt_depay_chain (GstPad * pad, GstBuffer * buf);
static void
@ -127,6 +128,7 @@ gst_rdt_depay_init (GstRDTDepay * rdtdepay, GstRDTDepayClass * klass)
rdtdepay->sinkpad =
gst_pad_new_from_static_template (&gst_rdt_depay_sink_template, "sink");
gst_pad_set_chain_function (rdtdepay->sinkpad, gst_rdt_depay_chain);
gst_pad_set_event_function (rdtdepay->sinkpad, gst_rdt_depay_sink_event);
gst_pad_set_setcaps_function (rdtdepay->sinkpad, gst_rdt_depay_setcaps);
gst_element_add_pad (GST_ELEMENT_CAST (rdtdepay), rdtdepay->sinkpad);
@ -155,7 +157,7 @@ gst_rdt_depay_setcaps (GstPad * pad, GstCaps * caps)
GstRDTDepay *rdtdepay;
GstCaps *srccaps;
gint clock_rate = 1000; /* default */
const GValue *config;
const GValue *value;
GstBuffer *header;
rdtdepay = GST_RDT_DEPAY (GST_PAD_PARENT (pad));
@ -166,14 +168,44 @@ gst_rdt_depay_setcaps (GstPad * pad, GstCaps * caps)
gst_structure_get_int (structure, "clock-rate", &clock_rate);
/* config contains the RealMedia header as a buffer. */
config = gst_structure_get_value (structure, "config");
if (!config)
value = gst_structure_get_value (structure, "config");
if (!value)
goto no_header;
header = gst_value_get_buffer (config);
header = gst_value_get_buffer (value);
if (!header)
goto no_header;
/* get other values for newsegment */
value = gst_structure_get_value (structure, "npt-start");
if (value && G_VALUE_HOLDS_UINT64 (value))
rdtdepay->npt_start = g_value_get_uint64 (value);
else
rdtdepay->npt_start = 0;
GST_DEBUG_OBJECT (rdtdepay, "NPT start %" G_GUINT64_FORMAT,
rdtdepay->npt_start);
value = gst_structure_get_value (structure, "npt-stop");
if (value && G_VALUE_HOLDS_UINT64 (value))
rdtdepay->npt_stop = g_value_get_uint64 (value);
else
rdtdepay->npt_stop = -1;
GST_DEBUG_OBJECT (rdtdepay, "NPT stop %" G_GUINT64_FORMAT,
rdtdepay->npt_stop);
value = gst_structure_get_value (structure, "play-speed");
if (value && G_VALUE_HOLDS_DOUBLE (value))
rdtdepay->play_speed = g_value_get_double (value);
else
rdtdepay->play_speed = 1.0;
value = gst_structure_get_value (structure, "play-scale");
if (value && G_VALUE_HOLDS_DOUBLE (value))
rdtdepay->play_scale = g_value_get_double (value);
else
rdtdepay->play_scale = 1.0;
/* caps seem good, configure element */
rdtdepay->clock_rate = clock_rate;
@ -196,11 +228,81 @@ no_header:
}
}
static gboolean
gst_rdt_depay_sink_event (GstPad * pad, GstEvent * event)
{
GstRDTDepay *depay;
gboolean res = TRUE;
depay = GST_RDT_DEPAY (GST_OBJECT_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
res = gst_pad_push_event (depay->srcpad, event);
gst_segment_init (&depay->segment, GST_FORMAT_UNDEFINED);
depay->need_newsegment = TRUE;
depay->next_seqnum = -1;
break;
case GST_EVENT_NEWSEGMENT:
{
gboolean update;
gdouble rate;
GstFormat fmt;
gint64 start, stop, position;
gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop,
&position);
gst_segment_set_newsegment (&depay->segment, update, rate, fmt,
start, stop, position);
/* don't pass the event downstream, we generate our own segment
* including the NTP time and other things we receive in caps */
gst_event_unref (event);
break;
}
default:
/* pass other events forward */
res = gst_pad_push_event (depay->srcpad, event);
break;
}
return res;
}
static GstEvent *
create_segment_event (GstRDTDepay * depay, gboolean update,
GstClockTime position)
{
GstEvent *event;
GstClockTime stop;
if (depay->npt_stop != -1)
stop = depay->npt_stop - depay->npt_start;
else
stop = -1;
event = gst_event_new_new_segment_full (update, depay->play_speed,
depay->play_scale, GST_FORMAT_TIME, position, stop,
position + depay->npt_start);
return event;
}
static GstFlowReturn
gst_rdt_depay_push (GstRDTDepay * rdtdepay, GstBuffer * buffer)
{
GstFlowReturn ret;
if (rdtdepay->need_newsegment) {
GstEvent *event;
event = create_segment_event (rdtdepay, FALSE, 0);
gst_pad_push_event (rdtdepay->srcpad, event);
rdtdepay->need_newsegment = FALSE;
}
gst_buffer_set_caps (buffer, GST_PAD_CAPS (rdtdepay->srcpad));
if (rdtdepay->discont) {
@ -224,7 +326,6 @@ gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime,
guint32 timestamp;
gint gap;
guint16 seqnum;
gboolean discont;
/* get pointers to the packet data */
gst_rdt_packet_data_peek_data (packet, &data, &size);
@ -399,7 +500,9 @@ gst_rdt_depay_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_segment_init (&rdtdepay->segment, GST_FORMAT_UNDEFINED);
rdtdepay->next_seqnum = -1;
rdtdepay->need_newsegment = TRUE;
break;
default:
break;

View file

@ -47,9 +47,16 @@ struct _GstRDTDepay
GstPad *srcpad;
guint clock_rate;
GstClockTime npt_start;
GstClockTime npt_stop;
gdouble play_speed;
gdouble play_scale;
guint32 next_seqnum;
gboolean discont;
gboolean need_newsegment;
GstSegment segment;
GstBuffer *header;
};

View file

@ -360,6 +360,10 @@ rdt_jitter_buffer_insert (RDTJitterBuffer * jbuf, GstBuffer * buf,
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)) {
@ -385,11 +389,7 @@ rdt_jitter_buffer_insert (RDTJitterBuffer * jbuf, GstBuffer * buf,
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);
rtptime = 0;
if (clock_rate) {
time = calculate_skew (jbuf, rtptime, time, clock_rate);
GST_BUFFER_TIMESTAMP (buf) = time;

View file

@ -136,6 +136,10 @@ static GstPad *gst_rdt_manager_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name);
static void gst_rdt_manager_release_pad (GstElement * element, GstPad * pad);
static gboolean gst_rdt_manager_parse_caps (GstRDTManager * rdtmanager,
GstRDTManagerSession * session, GstCaps * caps);
static gboolean gst_rdt_manager_setcaps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_rdt_manager_chain_rdt (GstPad * pad,
GstBuffer * buffer);
static GstFlowReturn gst_rdt_manager_chain_rtcp (GstPad * pad,
@ -181,6 +185,7 @@ struct _GstRDTManagerSession
guint8 pt;
gint clock_rate;
GstCaps *caps;
gint64 clock_base;
GstSegment segment;
@ -279,7 +284,14 @@ activate_session (GstRDTManager * rdtmanager, GstRDTManagerSession * session,
g_signal_emitv (args, gst_rdt_manager_signals[SIGNAL_REQUEST_PT_MAP], 0,
&ret);
caps = (GstCaps *) g_value_get_boxed (&ret);
g_value_unset (&args[0]);
g_value_unset (&args[1]);
g_value_unset (&args[2]);
caps = (GstCaps *) g_value_dup_boxed (&ret);
g_value_unset (&ret);
if (caps)
gst_rdt_manager_parse_caps (rdtmanager, session, caps);
name = g_strdup_printf ("recv_rtp_src_%d_%u_%d", session->id, ssrc, pt);
klass = GST_ELEMENT_GET_CLASS (rdtmanager);
@ -288,6 +300,7 @@ activate_session (GstRDTManager * rdtmanager, GstRDTManagerSession * session,
g_free (name);
gst_pad_set_caps (session->recv_rtp_src, caps);
gst_caps_unref (caps);
gst_pad_set_element_private (session->recv_rtp_src, session);
gst_pad_set_query_function (session->recv_rtp_src, gst_rdt_manager_query_src);
@ -651,6 +664,73 @@ duplicate:
}
}
static gboolean
gst_rdt_manager_parse_caps (GstRDTManager * rdtmanager,
GstRDTManagerSession * session, GstCaps * caps)
{
GstStructure *caps_struct;
guint val;
/* first parse the caps */
caps_struct = gst_caps_get_structure (caps, 0);
GST_DEBUG_OBJECT (rdtmanager, "got caps");
/* we need a clock-rate to convert the rtp timestamps to GStreamer time and to
* measure the amount of data in the buffer */
if (!gst_structure_get_int (caps_struct, "clock-rate", &session->clock_rate))
session->clock_rate = 1000;
if (session->clock_rate <= 0)
goto wrong_rate;
GST_DEBUG_OBJECT (rdtmanager, "got clock-rate %d", session->clock_rate);
/* gah, clock-base is uint. If we don't have a base, we will use the first
* buffer timestamp as the base time. This will screw up sync but it's better
* than nothing. */
if (gst_structure_get_uint (caps_struct, "clock-base", &val))
session->clock_base = val;
else
session->clock_base = -1;
GST_DEBUG_OBJECT (rdtmanager, "got clock-base %" G_GINT64_FORMAT,
session->clock_base);
/* first expected seqnum */
if (gst_structure_get_uint (caps_struct, "seqnum-base", &val))
session->next_seqnum = val;
else
session->next_seqnum = -1;
GST_DEBUG_OBJECT (rdtmanager, "got seqnum-base %d", session->next_seqnum);
return TRUE;
/* ERRORS */
wrong_rate:
{
GST_DEBUG_OBJECT (rdtmanager, "Invalid clock-rate %d", session->clock_rate);
return FALSE;
}
}
static gboolean
gst_rdt_manager_setcaps (GstPad * pad, GstCaps * caps)
{
GstRDTManager *rdtmanager;
GstRDTManagerSession *session;
gboolean res;
rdtmanager = GST_RDT_MANAGER (GST_PAD_PARENT (pad));
/* find session */
session = gst_pad_get_element_private (pad);
res = gst_rdt_manager_parse_caps (rdtmanager, session, caps);
return res;
}
static GstFlowReturn
gst_rdt_manager_chain_rdt (GstPad * pad, GstBuffer * buffer)
{
@ -1072,6 +1152,8 @@ create_recv_rtp (GstRDTManager * rdtmanager, GstPadTemplate * templ,
session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
gst_pad_set_element_private (session->recv_rtp_sink, session);
gst_pad_set_setcaps_function (session->recv_rtp_sink,
gst_rdt_manager_setcaps);
gst_pad_set_chain_function (session->recv_rtp_sink,
gst_rdt_manager_chain_rdt);
gst_pad_set_active (session->recv_rtp_sink, TRUE);

View file

@ -2311,17 +2311,19 @@ gst_rmdemux_parse_video_packet (GstRMDemux * rmdemux, GstRMDemuxStream * stream,
stream->frag_length = 0;
gst_buffer_set_caps (out, GST_PAD_CAPS (stream->pad));
if (timestamp != -1) {
if (rmdemux->first_ts != -1 && timestamp > rmdemux->first_ts)
timestamp -= rmdemux->first_ts;
else
timestamp = 0;
if (rmdemux->base_ts != -1)
timestamp += rmdemux->base_ts;
}
timestamp =
gst_rmdemux_fix_timestamp (rmdemux, stream, outdata, timestamp);
if (rmdemux->first_ts != -1 && timestamp > rmdemux->first_ts)
timestamp -= rmdemux->first_ts;
else
timestamp = 0;
if (rmdemux->base_ts != -1)
timestamp += rmdemux->base_ts;
GST_BUFFER_TIMESTAMP (out) = timestamp;
GST_LOG_OBJECT (rmdemux, "pushing timestamp %" GST_TIME_FORMAT,