Commit 85af9b82 authored by Wim Taymans's avatar Wim Taymans
Browse files

basertppayload: add support for bufferlists

Based on patch from Ognyan Tonchev.

See #585559
parent f5c8055e
......@@ -990,6 +990,7 @@ GST_BASE_RTP_PAYLOAD_SRCPAD
gst_basertppayload_is_filled
gst_basertppayload_push
gst_basertppayload_push_list
gst_basertppayload_set_options
gst_basertppayload_set_outcaps
<SUBSECTION Standard>
......
......@@ -613,87 +613,177 @@ gst_basertppayload_is_filled (GstBaseRTPPayload * payload,
return FALSE;
}
/**
* gst_basertppayload_push:
* @payload: a #GstBaseRTPPayload
* @buffer: a #GstBuffer
*
* Push @buffer 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 @buffer.
*
* Returns: a #GstFlowReturn.
*/
GstFlowReturn
gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
typedef struct
{
GstFlowReturn res;
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;
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;
/* 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));
}
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
/* 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,
timestamp);
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 */
rtptime += rtime;
data.rtptime = payload->ts_base + rtime;
} else {
/* no timestamp to convert, take previous timestamp */
rtptime = payload->timestamp;
data.rtptime = payload->timestamp;
}
gst_rtp_buffer_set_timestamp (buffer, rtptime);
payload->timestamp = rtptime;
/* 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);
}
/* set caps */
gst_buffer_set_caps (buffer, GST_PAD_CAPS (payload->srcpad));
priv->next_seqnum = data.seqnum;
payload->timestamp = data.rtptime;
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));
"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));
res = gst_pad_push (payload->srcpad, buffer);
return res;
return GST_FLOW_OK;
/* 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;
}
}
/**
* 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
*/
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
* @buffer: a #GstBuffer
*
* Push @buffer 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 @buffer.
*
* Returns: a #GstFlowReturn.
*/
GstFlowReturn
gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
{
GstFlowReturn res;
res = gst_basertppayload_prepare_push (payload, buffer, FALSE);
if (G_LIKELY (res == GST_FLOW_OK))
res = gst_pad_push (payload->srcpad, buffer);
else
gst_buffer_unref (buffer);
return res;
}
static void
gst_basertppayload_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
......
......@@ -144,6 +144,9 @@ gboolean gst_basertppayload_is_filled (GstBaseRTPPayload *payl
GstFlowReturn gst_basertppayload_push (GstBaseRTPPayload *payload,
GstBuffer *buffer);
GstFlowReturn gst_basertppayload_push_list (GstBaseRTPPayload *payload,
GstBufferList *list);
G_END_DECLS
#endif /* __GST_BASE_RTP_PAYLOAD_H__ */
......@@ -13,6 +13,7 @@ EXPORTS
gst_basertppayload_get_type
gst_basertppayload_is_filled
gst_basertppayload_push
gst_basertppayload_push_list
gst_basertppayload_set_options
gst_basertppayload_set_outcaps
gst_rtcp_buffer_add_packet
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment