From 85e201fe301f2c946cdb209671fcf27750208a66 Mon Sep 17 00:00:00 2001 From: =?utf8?q?H=C3=A5vard=20Graff?= Date: Fri, 14 Feb 2020 09:40:59 +0000 Subject: [PATCH] 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. --- gst-libs/gst/rtp/gstrtpbasepayload.c | 54 ++++++++++++++++++++++++++++++++++++ tests/check/libs/rtpbasepayload.c | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/gst-libs/gst/rtp/gstrtpbasepayload.c b/gst-libs/gst/rtp/gstrtpbasepayload.c index 4127546..8167abc 100644 --- a/gst-libs/gst/rtp/gstrtpbasepayload.c +++ b/gst-libs/gst/rtp/gstrtpbasepayload.c @@ -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; diff --git a/tests/check/libs/rtpbasepayload.c b/tests/check/libs/rtpbasepayload.c index 8dcf6a7..5319830 100644 --- a/tests/check/libs/rtpbasepayload.c +++ b/tests/check/libs/rtpbasepayload.c @@ -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); -- 2.7.4