gboolean source_info;
GstBuffer *input_meta_buffer;
+ guint8 twcc_ext_id;
guint64 base_offset;
gint64 base_rtime;
#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
{
PROP_STATS,
PROP_SOURCE_INFO,
PROP_ONVIF_NO_RATE_CONTROL,
+ PROP_TWCC_EXT_ID,
PROP_LAST
};
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;
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);
GstClockTime pts;
guint64 offset;
guint32 rtptime;
+ guint8 twcc_ext_id;
} HeaderData;
static gboolean
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)
{
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 */
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) {
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;
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;
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)
{
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);