diff -r 4b0c6ed43234 -r 8e837d1bf446 gst_plugins_base/gst-libs/gst/rtp/gstbasertppayload.c --- a/gst_plugins_base/gst-libs/gst/rtp/gstbasertppayload.c Wed Mar 24 17:58:42 2010 -0500 +++ b/gst_plugins_base/gst-libs/gst/rtp/gstbasertppayload.c Wed Mar 24 18:04:17 2010 -0500 @@ -45,8 +45,6 @@ gboolean seqnum_offset_random; gboolean ssrc_random; guint16 next_seqnum; - - GstClockTime rt_base; }; /* BaseRTPPayload signals and args */ @@ -90,8 +88,8 @@ gpointer g_class); static void gst_basertppayload_finalize (GObject * object); -static gboolean gst_basertppayload_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_basertppayload_getcaps (GstPad * pad); +static gboolean gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps); +static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad); static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_basertppayload_chain (GstPad * pad, GstBuffer * buffer); @@ -163,28 +161,31 @@ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU, g_param_spec_uint ("mtu", "MTU", "Maximum size of one packet", - 28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE)); + 28, G_MAXUINT, DEFAULT_MTU, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT, g_param_spec_uint ("pt", "payload type", - "The payload type of the packets", - 0, 0x80, DEFAULT_PT, G_PARAM_READWRITE)); + "The payload type of the packets", 0, 0x80, DEFAULT_PT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC, g_param_spec_uint ("ssrc", "SSRC", - "The SSRC of the packets (default == random)", - 0, G_MAXUINT32, DEFAULT_SSRC, G_PARAM_READWRITE)); + "The SSRC of the packets (default == random)", 0, G_MAXUINT32, + DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset", "Timestamp Offset", "Offset to add to all outgoing timestamps (default = random)", 0, - G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET, G_PARAM_READWRITE)); + G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET, g_param_spec_int ("seqnum-offset", "Sequence number Offset", "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16, - DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE)); + DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME, g_param_spec_int64 ("max-ptime", "Max packet time", "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - -1, G_MAXINT64, DEFAULT_MAX_PTIME, G_PARAM_READWRITE)); + -1, G_MAXINT64, DEFAULT_MAX_PTIME, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstBaseRTPAudioPayload:min-ptime: * @@ -195,16 +196,17 @@ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME, g_param_spec_int64 ("min-ptime", "Min packet time", "Minimum duration of the packet data in ns (can't go above MTU)", - 0, G_MAXINT64, DEFAULT_MIN_PTIME, G_PARAM_READWRITE)); + 0, G_MAXINT64, DEFAULT_MIN_PTIME, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP, g_param_spec_uint ("timestamp", "Timestamp", "The RTP timestamp of the last processed packet", - 0, G_MAXUINT32, 0, G_PARAM_READABLE)); + 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM, g_param_spec_uint ("seqnum", "Sequence number", "The RTP sequence number of the last processed packet", - 0, G_MAXUINT16, 0, G_PARAM_READABLE)); + 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); gstelement_class->change_state = gst_basertppayload_change_state; @@ -234,9 +236,9 @@ basertppayload->sinkpad = gst_pad_new_from_template (templ, "sink"); gst_pad_set_setcaps_function (basertppayload->sinkpad, - gst_basertppayload_setcaps); + gst_basertppayload_sink_setcaps); gst_pad_set_getcaps_function (basertppayload->sinkpad, - gst_basertppayload_getcaps); + gst_basertppayload_sink_getcaps); gst_pad_set_event_function (basertppayload->sinkpad, gst_basertppayload_event); gst_pad_set_chain_function (basertppayload->sinkpad, @@ -288,7 +290,7 @@ } static gboolean -gst_basertppayload_setcaps (GstPad * pad, GstCaps * caps) +gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps) { GstBaseRTPPayload *basertppayload; GstBaseRTPPayloadClass *basertppayload_class; @@ -307,7 +309,7 @@ } static GstCaps * -gst_basertppayload_getcaps (GstPad * pad) +gst_basertppayload_sink_getcaps (GstPad * pad) { GstBaseRTPPayload *basertppayload; GstBaseRTPPayloadClass *basertppayload_class; @@ -477,8 +479,9 @@ ...) { GstCaps *srccaps, *peercaps; + gboolean res; - /* fill in the defaults, there properties cannot be negotiated. */ + /* fill in the defaults, their properties cannot be negotiated. */ srccaps = gst_caps_new_simple ("application/x-rtp", "media", G_TYPE_STRING, payload->media, "clock-rate", G_TYPE_INT, payload->clock_rate, @@ -591,10 +594,10 @@ GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps); } - gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps); + res = gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps); gst_caps_unref (srccaps); - return TRUE; + return res; } /** @@ -603,7 +606,7 @@ * @size: the size of the packet * @duration: the duration of the packet * - * Check if the packet with @size and @duration would exceed the configure + * Check if the packet with @size and @duration would exceed the configured * maximum size. * * Returns: %TRUE if the packet of @size and @duration would exceed the @@ -626,6 +629,155 @@ return FALSE; } +typedef struct +{ + GstBaseRTPPayload *payload; + guint32 ssrc; + guint16 seqnum; + guint8 pt; + GstCaps *caps; + GstClockTime timestamp; + guint32 rtptime; +} HeaderData; + +static GstBufferListItem +find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) +{ + data->timestamp = GST_BUFFER_TIMESTAMP (*buffer); + + /* stop when we find a timestamp */ + if (data->timestamp != -1) + return GST_BUFFER_LIST_END; + else + return GST_BUFFER_LIST_CONTINUE; +} + +static GstBufferListItem +set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) +{ + gst_rtp_buffer_set_ssrc (*buffer, data->ssrc); + gst_rtp_buffer_set_payload_type (*buffer, data->pt); + gst_rtp_buffer_set_seq (*buffer, data->seqnum); + gst_rtp_buffer_set_timestamp (*buffer, data->rtptime); + gst_buffer_set_caps (*buffer, data->caps); + data->seqnum++; + + return GST_BUFFER_LIST_SKIP_GROUP; +} + +/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer + * before the buffer is pushed. */ +static GstFlowReturn +gst_basertppayload_prepare_push (GstBaseRTPPayload * payload, + gpointer obj, gboolean is_list) +{ + GstBaseRTPPayloadPrivate *priv; + HeaderData data; + + if (payload->clock_rate == 0) + goto no_rate; + + priv = payload->priv; + + /* update first, so that the property is set to the last + * seqnum pushed */ + payload->seqnum = priv->next_seqnum; + + /* fill in the fields we want to set on all headers */ + data.payload = payload; + data.seqnum = payload->seqnum; + data.ssrc = payload->current_ssrc; + data.pt = payload->pt; + data.caps = GST_PAD_CAPS (payload->srcpad); + data.timestamp = -1; + + /* find the first buffer with a timestamp */ + if (is_list) { + gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), + (GstBufferListFunc) find_timestamp, &data); + } else { + data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj)); + } + + /* convert to RTP time */ + if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) { + gint64 rtime; + + rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, + data.timestamp); + + rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); + + /* add running_time in clock-rate units to the base timestamp */ + data.rtptime = payload->ts_base + rtime; + } else { + /* no timestamp to convert, take previous timestamp */ + data.rtptime = payload->timestamp; + } + + /* set ssrc, payload type, seq number, caps and rtptime */ + if (is_list) { + gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), + (GstBufferListFunc) set_headers, &data); + } else { + GstBuffer *buf = GST_BUFFER_CAST (obj); + set_headers (&buf, 0, 0, &data); + } + + priv->next_seqnum = data.seqnum; + payload->timestamp = data.rtptime; + + GST_LOG_OBJECT (payload, + "Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %" + GST_TIME_FORMAT, (is_list) ? -1 : + GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime, + GST_TIME_ARGS (data.timestamp)); + + return GST_FLOW_OK; + + /* ERRORS */ +no_rate: + { + GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), + ("subclass did not specify clock-rate")); + return GST_FLOW_ERROR; + } +} + +/** + * gst_basertppayload_push_list: + * @payload: a #GstBaseRTPPayload + * @list: a #GstBufferList + * + * Push @list to the peer element of the payloader. The SSRC, payload type, + * seqnum and timestamp of the RTP buffer will be updated first. + * + * This function takes ownership of @list. + * + * Returns: a #GstFlowReturn. + * + * Since: 0.10.24 + */ + +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +GstFlowReturn +gst_basertppayload_push_list (GstBaseRTPPayload * payload, GstBufferList * list) +{ + GstFlowReturn res; + + res = gst_basertppayload_prepare_push (payload, list, TRUE); + + if (G_LIKELY (res == GST_FLOW_OK)) + res = gst_pad_push_list (payload->srcpad, list); + else + gst_buffer_list_unref (list); + + return res; +} + /** * gst_basertppayload_push: * @payload: a #GstBaseRTPPayload @@ -646,78 +798,15 @@ gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer) { GstFlowReturn res; - GstClockTime timestamp; - guint32 rtptime; - GstBaseRTPPayloadPrivate *priv; - if (payload->clock_rate == 0) - goto no_rate; - - priv = payload->priv; - - gst_rtp_buffer_set_ssrc (buffer, payload->current_ssrc); - - gst_rtp_buffer_set_payload_type (buffer, payload->pt); - - /* update first, so that the property is set to the last - * seqnum pushed */ - payload->seqnum = priv->next_seqnum; - gst_rtp_buffer_set_seq (buffer, payload->seqnum); - - /* can wrap around, which is perfectly fine */ - priv->next_seqnum++; - - /* add our random offset to the timestamp */ - rtptime = payload->ts_base; - - timestamp = GST_BUFFER_TIMESTAMP (buffer); - if (GST_CLOCK_TIME_IS_VALID (timestamp)) { - gint64 rtime; - - rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, - timestamp); + res = gst_basertppayload_prepare_push (payload, buffer, FALSE); - /* take first timestamp as base, we want to calculate the RTP timestamp - * starting from the ts_base */ - if (priv->rt_base == -1) { - priv->rt_base = rtime; - GST_LOG_OBJECT (payload, "first timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (rtime)); - } - rtime -= priv->rt_base; - - rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); - - /* add running_time in clock-rate units to the base timestamp */ - rtptime += rtime; - } else { - /* no timestamp to convert, take previous timestamp */ - rtptime = payload->timestamp; - } - gst_rtp_buffer_set_timestamp (buffer, rtptime); - - payload->timestamp = rtptime; - - /* set caps */ - gst_buffer_set_caps (buffer, GST_PAD_CAPS (payload->srcpad)); - - GST_LOG_OBJECT (payload, - "Pushing packet size %d, seq=%d, rtptime=%u, timestamp %" GST_TIME_FORMAT, - GST_BUFFER_SIZE (buffer), payload->seqnum, rtptime, - GST_TIME_ARGS (timestamp)); - - res = gst_pad_push (payload->srcpad, buffer); + if (G_LIKELY (res == GST_FLOW_OK)) + res = gst_pad_push (payload->srcpad, buffer); + else + gst_buffer_unref (buffer); return res; - - /* ERRORS */ -no_rate: - { - GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), - ("subclass did not specify clock-rate")); - gst_buffer_unref (buffer); - return GST_FLOW_ERROR; - } } static void @@ -843,6 +932,7 @@ else basertppayload->seqnum_base = basertppayload->seqnum_offset; priv->next_seqnum = basertppayload->seqnum_base; + basertppayload->seqnum = basertppayload->seqnum_base; if (priv->ssrc_random) basertppayload->current_ssrc = g_rand_int (basertppayload->ssrc_rand); @@ -853,8 +943,7 @@ basertppayload->ts_base = g_rand_int (basertppayload->ts_rand); else basertppayload->ts_base = basertppayload->ts_offset; - - priv->rt_base = -1; + basertppayload->timestamp = basertppayload->ts_base; break; default: break;