mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
basertppayload: add support for bufferlists
Based on patch from Ognyan Tonchev. See #585559
This commit is contained in:
parent
f5c8055edf
commit
85af9b82e8
4 changed files with 154 additions and 59 deletions
|
@ -990,6 +990,7 @@ GST_BASE_RTP_PAYLOAD_SRCPAD
|
||||||
|
|
||||||
gst_basertppayload_is_filled
|
gst_basertppayload_is_filled
|
||||||
gst_basertppayload_push
|
gst_basertppayload_push
|
||||||
|
gst_basertppayload_push_list
|
||||||
gst_basertppayload_set_options
|
gst_basertppayload_set_options
|
||||||
gst_basertppayload_set_outcaps
|
gst_basertppayload_set_outcaps
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
|
|
|
@ -613,6 +613,150 @@ gst_basertppayload_is_filled (GstBaseRTPPayload * payload,
|
||||||
return FALSE;
|
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
|
||||||
|
*/
|
||||||
|
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:
|
* gst_basertppayload_push:
|
||||||
* @payload: a #GstBaseRTPPayload
|
* @payload: a #GstBaseRTPPayload
|
||||||
|
@ -629,69 +773,15 @@ GstFlowReturn
|
||||||
gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
|
gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstFlowReturn res;
|
GstFlowReturn res;
|
||||||
GstClockTime timestamp;
|
|
||||||
guint32 rtptime;
|
|
||||||
GstBaseRTPPayloadPrivate *priv;
|
|
||||||
|
|
||||||
if (payload->clock_rate == 0)
|
res = gst_basertppayload_prepare_push (payload, buffer, FALSE);
|
||||||
goto no_rate;
|
|
||||||
|
|
||||||
priv = payload->priv;
|
if (G_LIKELY (res == GST_FLOW_OK))
|
||||||
|
res = gst_pad_push (payload->srcpad, buffer);
|
||||||
gst_rtp_buffer_set_ssrc (buffer, payload->current_ssrc);
|
else
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return res;
|
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
|
static void
|
||||||
|
|
|
@ -144,6 +144,9 @@ gboolean gst_basertppayload_is_filled (GstBaseRTPPayload *payl
|
||||||
GstFlowReturn gst_basertppayload_push (GstBaseRTPPayload *payload,
|
GstFlowReturn gst_basertppayload_push (GstBaseRTPPayload *payload,
|
||||||
GstBuffer *buffer);
|
GstBuffer *buffer);
|
||||||
|
|
||||||
|
GstFlowReturn gst_basertppayload_push_list (GstBaseRTPPayload *payload,
|
||||||
|
GstBufferList *list);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_BASE_RTP_PAYLOAD_H__ */
|
#endif /* __GST_BASE_RTP_PAYLOAD_H__ */
|
||||||
|
|
|
@ -13,6 +13,7 @@ EXPORTS
|
||||||
gst_basertppayload_get_type
|
gst_basertppayload_get_type
|
||||||
gst_basertppayload_is_filled
|
gst_basertppayload_is_filled
|
||||||
gst_basertppayload_push
|
gst_basertppayload_push
|
||||||
|
gst_basertppayload_push_list
|
||||||
gst_basertppayload_set_options
|
gst_basertppayload_set_options
|
||||||
gst_basertppayload_set_outcaps
|
gst_basertppayload_set_outcaps
|
||||||
gst_rtcp_buffer_add_packet
|
gst_rtcp_buffer_add_packet
|
||||||
|
|
Loading…
Reference in a new issue