Commit 85e201fe authored by Håvard Graff's avatar Håvard Graff Committed by GStreamer Merge Bot

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.
parent 0e1f7f6e
......@@ -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);
......
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