diff --git a/girs/GstRtp-1.0.gir b/girs/GstRtp-1.0.gir
index 2771b131ba..1675b00630 100644
--- a/girs/GstRtp-1.0.gir
+++ b/girs/GstRtp-1.0.gir
@@ -3146,6 +3146,19 @@ the need to handle these extensions manually using the
GstRTPBasePayload::request-extension: signal.
+
+ A list of already enabled RTP header extensions. This may be useful for finding
+out which extensions are already enabled (with add-extension signal) and picking a non-conflicting
+ID for a new extension that needs to be added on top of the existing ones.
+
+Note that the value returned by reading this property is not dynamically updated when the set of
+enabled extensions changes by any of existing action signals. Rather, it represents the current state
+at the time the property is read.
+
+Dynamic updates of this property can be received by subscribing to its corresponding "notify" signal, i.e.
+"notify::extensions".
+
+
diff --git a/subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasepayload.c b/subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasepayload.c
index 4b01beb6dd..34d24db2f6 100644
--- a/subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasepayload.c
+++ b/subprojects/gst-plugins-base/gst-libs/gst/rtp/gstrtpbasepayload.c
@@ -137,9 +137,12 @@ enum
PROP_ONVIF_NO_RATE_CONTROL,
PROP_SCALE_RTPTIME,
PROP_AUTO_HEADER_EXTENSION,
+ PROP_EXTENSIONS,
PROP_LAST
};
+static GParamSpec *gst_rtp_base_payload_extensions_pspec;
+
static void gst_rtp_base_payload_class_init (GstRTPBasePayloadClass * klass);
static void gst_rtp_base_payload_init (GstRTPBasePayload * rtpbasepayload,
gpointer g_class);
@@ -176,6 +179,8 @@ static gboolean gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload);
static void gst_rtp_base_payload_add_extension (GstRTPBasePayload * payload,
GstRTPHeaderExtension * ext);
static void gst_rtp_base_payload_clear_extensions (GstRTPBasePayload * payload);
+static void gst_rtp_base_payload_get_extensions (GstRTPBasePayload * payload,
+ GValue * out_value);
static GstElementClass *parent_class = NULL;
static gint private_offset = 0;
@@ -442,6 +447,33 @@ gst_rtp_base_payload_class_init (GstRTPBasePayloadClass * klass)
DEFAULT_AUTO_HEADER_EXTENSION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_rtp_base_payload_extensions_pspec = gst_param_spec_array ("extensions",
+ "RTP header extensions",
+ "A list of already enabled RTP header extensions",
+ g_param_spec_object ("extension", "RTP header extension",
+ "An already enabled RTP extension", GST_TYPE_RTP_HEADER_EXTENSION,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS),
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GstRTPBasePayload:extensions:
+ *
+ * A list of already enabled RTP header extensions. This may be useful for finding
+ * out which extensions are already enabled (with add-extension signal) and picking a non-conflicting
+ * ID for a new extension that needs to be added on top of the existing ones.
+ *
+ * Note that the value returned by reading this property is not dynamically updated when the set of
+ * enabled extensions changes by any of existing action signals. Rather, it represents the current state
+ * at the time the property is read.
+ *
+ * Dynamic updates of this property can be received by subscribing to its corresponding "notify" signal, i.e.
+ * "notify::extensions".
+ *
+ * Since: 1.24
+ */
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_EXTENSIONS, gst_rtp_base_payload_extensions_pspec);
+
/**
* GstRTPBasePayload::add-extension:
* @object: the #GstRTPBasePayload
@@ -1589,6 +1621,9 @@ gst_rtp_base_payload_add_extension (GstRTPBasePayload * payload,
g_ptr_array_add (payload->priv->header_exts, gst_object_ref (ext));
gst_pad_mark_reconfigure (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
GST_OBJECT_UNLOCK (payload);
+
+ g_object_notify_by_pspec (G_OBJECT (payload),
+ gst_rtp_base_payload_extensions_pspec);
}
static void
@@ -1597,6 +1632,32 @@ gst_rtp_base_payload_clear_extensions (GstRTPBasePayload * payload)
GST_OBJECT_LOCK (payload);
g_ptr_array_set_size (payload->priv->header_exts, 0);
GST_OBJECT_UNLOCK (payload);
+
+ g_object_notify_by_pspec (G_OBJECT (payload),
+ gst_rtp_base_payload_extensions_pspec);
+}
+
+static void
+gst_rtp_base_payload_get_extensions (GstRTPBasePayload * payload,
+ GValue * out_value)
+{
+ GPtrArray *extensions;
+ guint i;
+
+ GST_OBJECT_LOCK (payload);
+ extensions = payload->priv->header_exts;
+
+ for (i = 0; i < extensions->len; ++i) {
+ GValue value = G_VALUE_INIT;
+ g_value_init (&value, GST_TYPE_RTP_HEADER_EXTENSION);
+
+ g_value_set_object (&value, g_ptr_array_index (extensions, i));
+
+ gst_value_array_append_value (out_value, &value);
+ g_value_unset (&value);
+ }
+
+ GST_OBJECT_UNLOCK (payload);
}
typedef struct
@@ -2248,6 +2309,9 @@ gst_rtp_base_payload_get_property (GObject * object, guint prop_id,
case PROP_AUTO_HEADER_EXTENSION:
g_value_set_boolean (value, priv->auto_hdr_ext);
break;
+ case PROP_EXTENSIONS:
+ gst_rtp_base_payload_get_extensions (rtpbasepayload, value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
diff --git a/subprojects/gst-plugins-base/tests/check/libs/rtpbasepayload.c b/subprojects/gst-plugins-base/tests/check/libs/rtpbasepayload.c
index a7cfa46ffd..7da0a8ca67 100644
--- a/subprojects/gst-plugins-base/tests/check/libs/rtpbasepayload.c
+++ b/subprojects/gst-plugins-base/tests/check/libs/rtpbasepayload.c
@@ -2310,6 +2310,61 @@ GST_START_TEST (rtp_base_payload_extensions_shrink_ext_data)
}
GST_END_TEST;
+
+GST_START_TEST (rtp_base_payload_extensions_get_enabled)
+{
+ GstElement *pay = GST_ELEMENT (rtp_dummy_pay_new ());
+ GstRTPHeaderExtension *ext = rtp_dummy_hdr_ext_new ();
+ GValue extensions = G_VALUE_INIT;
+ const GValue *returned_ext;
+
+ g_signal_emit_by_name (pay, "add-extension", ext, NULL);
+ g_object_get_property (G_OBJECT (pay), "extensions", &extensions);
+
+ fail_unless_equals_int (gst_value_array_get_size (&extensions), 1);
+
+ returned_ext = gst_value_array_get_value (&extensions, 0);
+
+ fail_unless (G_VALUE_HOLDS (returned_ext, GST_TYPE_RTP_HEADER_EXTENSION));
+ fail_unless (g_value_get_object (returned_ext) == ext);
+
+ g_value_unset (&extensions);
+ gst_object_unref (ext);
+ gst_object_unref (pay);
+}
+
+GST_END_TEST;
+
+static void
+on_extensions_changed (GObject * sender, GParamSpec * pspec,
+ guint * invocation_count)
+{
+ (void) sender;
+ (void) pspec;
+ (*invocation_count)++;
+}
+
+GST_START_TEST (rtp_base_payload_extensions_notify_on_change)
+{
+ GstElement *pay = GST_ELEMENT (rtp_dummy_pay_new ());
+ GstRTPHeaderExtension *ext = rtp_dummy_hdr_ext_new ();
+ guint invocation_count = 0;
+
+ g_signal_connect (pay, "notify::extensions",
+ G_CALLBACK (on_extensions_changed), &invocation_count);
+
+ g_signal_emit_by_name (pay, "add-extension", ext, NULL);
+ fail_unless_equals_int (invocation_count, 1);
+
+ g_signal_emit_by_name (pay, "clear-extensions", NULL);
+ fail_unless_equals_int (invocation_count, 2);
+
+ gst_object_unref (ext);
+ gst_object_unref (pay);
+}
+
+GST_END_TEST;
+
static Suite *
rtp_basepayloading_suite (void)
{
@@ -2358,6 +2413,8 @@ rtp_basepayloading_suite (void)
tcase_add_test (tc_chain, rtp_base_payload_caps_request_ignored);
tcase_add_test (tc_chain, rtp_base_payload_extensions_in_output_caps);
tcase_add_test (tc_chain, rtp_base_payload_extensions_shrink_ext_data);
+ tcase_add_test (tc_chain, rtp_base_payload_extensions_get_enabled);
+ tcase_add_test (tc_chain, rtp_base_payload_extensions_notify_on_change);
return s;
}