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; }