mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-17 22:06:41 +00:00
rtpbasepayload: add property for embedding twcc sequencenumbers
By setting the extension-ID for TWCC (Transport Wide Congestion Control), the payloader will embed sequencenumbers as a RTP header-extension according to https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-2 The negotiation of this being enabled with downstream elements is done with caps reflecting the way this is communicated using SDP.
This commit is contained in:
parent
0e1f7f6e8d
commit
85e201fe30
2 changed files with 102 additions and 0 deletions
|
@ -47,6 +47,7 @@ struct _GstRTPBasePayloadPrivate
|
|||
|
||||
gboolean source_info;
|
||||
GstBuffer *input_meta_buffer;
|
||||
guint8 twcc_ext_id;
|
||||
|
||||
guint64 base_offset;
|
||||
gint64 base_rtime;
|
||||
|
@ -92,6 +93,7 @@ enum
|
|||
#define DEFAULT_RUNNING_TIME GST_CLOCK_TIME_NONE
|
||||
#define DEFAULT_SOURCE_INFO FALSE
|
||||
#define DEFAULT_ONVIF_NO_RATE_CONTROL FALSE
|
||||
#define DEFAULT_TWCC_EXT_ID 0
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -110,6 +112,7 @@ enum
|
|||
PROP_STATS,
|
||||
PROP_SOURCE_INFO,
|
||||
PROP_ONVIF_NO_RATE_CONTROL,
|
||||
PROP_TWCC_EXT_ID,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -337,6 +340,28 @@ gst_rtp_base_payload_class_init (GstRTPBasePayloadClass * klass)
|
|||
DEFAULT_ONVIF_NO_RATE_CONTROL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstRTPBasePayload:twcc-ext-id:
|
||||
*
|
||||
* The RTP header-extension ID used for tagging buffers with Transport-Wide
|
||||
* Congestion Control sequence-numbers.
|
||||
*
|
||||
* To use this across multiple bundled streams (transport wide), the
|
||||
* GstRTPFunnel can mux TWCC sequence-numbers together.
|
||||
*
|
||||
* This is experimental, as it is still a draft and not yet a standard.
|
||||
*
|
||||
* Since: 1.18
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_TWCC_EXT_ID,
|
||||
g_param_spec_uint ("twcc-ext-id",
|
||||
"Transport-wide Congestion Control Extension ID (experimental)",
|
||||
"The RTP header-extension ID to use for tagging buffers with "
|
||||
"Transport-wide Congestion Control sequencenumbers (0 = disable)",
|
||||
0, 15, DEFAULT_TWCC_EXT_ID,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
|
||||
gstelement_class->change_state = gst_rtp_base_payload_change_state;
|
||||
|
||||
klass->get_caps = gst_rtp_base_payload_getcaps_default;
|
||||
|
@ -1115,6 +1140,16 @@ gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload)
|
|||
|
||||
update_max_ptime (payload);
|
||||
|
||||
|
||||
if (payload->priv->twcc_ext_id > 0) {
|
||||
/* TODO: put this as a separate utility-function for RTP extensions */
|
||||
gchar *name = g_strdup_printf ("extmap-%u", payload->priv->twcc_ext_id);
|
||||
gst_caps_set_simple (srccaps, name, G_TYPE_STRING,
|
||||
"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
|
||||
NULL);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
res = gst_pad_set_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), srccaps);
|
||||
gst_caps_unref (srccaps);
|
||||
gst_caps_unref (templ);
|
||||
|
@ -1162,6 +1197,7 @@ typedef struct
|
|||
GstClockTime pts;
|
||||
guint64 offset;
|
||||
guint32 rtptime;
|
||||
guint8 twcc_ext_id;
|
||||
} HeaderData;
|
||||
|
||||
static gboolean
|
||||
|
@ -1180,6 +1216,16 @@ find_timestamp (GstBuffer ** buffer, guint idx, gpointer user_data)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_set_twcc_seq (GstRTPBuffer * rtp, guint16 seq, guint8 ext_id)
|
||||
{
|
||||
guint16 data;
|
||||
if (ext_id == 0 || ext_id > 14)
|
||||
return;
|
||||
GST_WRITE_UINT16_BE (&data, seq);
|
||||
gst_rtp_buffer_add_extension_onebyte_header (rtp, ext_id, &data, 2);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_headers (GstBuffer ** buffer, guint idx, gpointer user_data)
|
||||
{
|
||||
|
@ -1193,6 +1239,7 @@ set_headers (GstBuffer ** buffer, guint idx, gpointer user_data)
|
|||
gst_rtp_buffer_set_payload_type (&rtp, data->pt);
|
||||
gst_rtp_buffer_set_seq (&rtp, data->seqnum);
|
||||
gst_rtp_buffer_set_timestamp (&rtp, data->rtptime);
|
||||
_set_twcc_seq (&rtp, data->seqnum, data->twcc_ext_id);
|
||||
gst_rtp_buffer_unmap (&rtp);
|
||||
|
||||
/* increment the seqnum for each buffer */
|
||||
|
@ -1249,6 +1296,7 @@ gst_rtp_base_payload_prepare_push (GstRTPBasePayload * payload,
|
|||
data.seqnum = payload->seqnum;
|
||||
data.ssrc = payload->current_ssrc;
|
||||
data.pt = payload->pt;
|
||||
data.twcc_ext_id = priv->twcc_ext_id;
|
||||
|
||||
/* find the first buffer with a timestamp */
|
||||
if (is_list) {
|
||||
|
@ -1566,6 +1614,9 @@ gst_rtp_base_payload_set_property (GObject * object, guint prop_id,
|
|||
case PROP_ONVIF_NO_RATE_CONTROL:
|
||||
priv->onvif_no_rate_control = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_TWCC_EXT_ID:
|
||||
priv->twcc_ext_id = g_value_get_uint (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1636,6 +1687,9 @@ gst_rtp_base_payload_get_property (GObject * object, guint prop_id,
|
|||
case PROP_ONVIF_NO_RATE_CONTROL:
|
||||
g_value_set_boolean (value, priv->onvif_no_rate_control);
|
||||
break;
|
||||
case PROP_TWCC_EXT_ID:
|
||||
g_value_set_uint (value, priv->twcc_ext_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -1969,6 +1969,53 @@ GST_START_TEST (rtp_base_payload_segment_time)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
#define TWCC_EXTMAP_STR "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"
|
||||
|
||||
GST_START_TEST (rtp_base_payload_property_twcc_ext_id_test)
|
||||
{
|
||||
GstHarness *h;
|
||||
GstRtpDummyPay *pay;
|
||||
GstBuffer *buf;
|
||||
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
||||
guint8 ext_id = 10;
|
||||
gpointer data;
|
||||
guint size;
|
||||
guint16 seqnum, twcc_seqnum;
|
||||
GstCaps *caps, *expected_caps;
|
||||
|
||||
pay = rtp_dummy_pay_new ();
|
||||
g_object_set (pay, "twcc-ext-id", ext_id, NULL);
|
||||
|
||||
h = gst_harness_new_with_element (GST_ELEMENT_CAST (pay), "sink", "src");
|
||||
gst_harness_set_src_caps_str (h, "application/x-rtp");
|
||||
|
||||
/* verify the presence of the twcc-seqnum */
|
||||
buf = gst_harness_push_and_pull (h, gst_buffer_new ());
|
||||
gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
|
||||
fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, ext_id,
|
||||
0, &data, &size));
|
||||
fail_unless_equals_int (2, size);
|
||||
twcc_seqnum = GST_READ_UINT16_BE (data);
|
||||
seqnum = gst_rtp_buffer_get_seq (&rtp);
|
||||
fail_unless_equals_int (twcc_seqnum, seqnum);
|
||||
gst_rtp_buffer_unmap (&rtp);
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
/* verify the presence of the twcc in caps */
|
||||
caps = gst_pad_get_current_caps (GST_PAD_PEER (h->sinkpad));
|
||||
expected_caps = gst_caps_from_string ("application/x-rtp, "
|
||||
"extmap-10=" TWCC_EXTMAP_STR "");
|
||||
fail_unless (gst_caps_is_subset (caps, expected_caps));
|
||||
gst_caps_unref (caps);
|
||||
gst_caps_unref (expected_caps);
|
||||
|
||||
g_object_unref (pay);
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
|
||||
static Suite *
|
||||
rtp_basepayloading_suite (void)
|
||||
{
|
||||
|
@ -2003,6 +2050,7 @@ rtp_basepayloading_suite (void)
|
|||
tcase_add_test (tc_chain, rtp_base_payload_property_ptime_multiple_test);
|
||||
tcase_add_test (tc_chain, rtp_base_payload_property_stats_test);
|
||||
tcase_add_test (tc_chain, rtp_base_payload_property_source_info_test);
|
||||
tcase_add_test (tc_chain, rtp_base_payload_property_twcc_ext_id_test);
|
||||
|
||||
tcase_add_test (tc_chain, rtp_base_payload_framerate_attribute);
|
||||
tcase_add_test (tc_chain, rtp_base_payload_max_framerate_attribute);
|
||||
|
|
Loading…
Reference in a new issue