gst_element_seek_simple
gst_element_seek
+<SUBSECTION element-property-notifications>
+gst_element_add_property_notify_watch
+gst_element_add_property_deep_notify_watch
+gst_element_remove_property_notify_watch
+
<SUBSECTION Standard>
GST_ELEMENT
GST_IS_ELEMENT
gst_message_new_device_removed
gst_message_parse_device_added
gst_message_parse_device_removed
+
+gst_message_new_property_notify
+gst_message_parse_property_notify
<SUBSECTION Standard>
GstMessageClass
GST_MESSAGE
return ret;
}
+
+static void
+gst_element_property_post_notify_msg (GstElement * element, GObject * obj,
+ GParamSpec * pspec, gboolean include_value)
+{
+ GValue val = G_VALUE_INIT;
+ GValue *v;
+
+ GST_LOG_OBJECT (element, "property '%s' of object %" GST_PTR_FORMAT " has "
+ "changed, posting message with%s value", pspec->name, obj,
+ include_value ? "" : "out");
+
+ if (include_value && (pspec->flags & G_PARAM_READABLE) != 0) {
+ g_value_init (&val, pspec->value_type);
+ g_object_get_property (obj, pspec->name, &val);
+ v = &val;
+ } else {
+ v = NULL;
+ }
+ gst_element_post_message (element,
+ gst_message_new_property_notify (GST_OBJECT_CAST (obj), pspec->name, v));
+}
+
+static void
+gst_element_property_deep_notify_cb (GstElement * element, GObject * prop_obj,
+ GParamSpec * pspec, gpointer user_data)
+{
+ gboolean include_value = GPOINTER_TO_INT (user_data);
+
+ gst_element_property_post_notify_msg (element, prop_obj, pspec,
+ include_value);
+}
+
+static void
+gst_element_property_notify_cb (GObject * obj, GParamSpec * pspec,
+ gpointer user_data)
+{
+ gboolean include_value = GPOINTER_TO_INT (user_data);
+
+ gst_element_property_post_notify_msg (GST_ELEMENT_CAST (obj), obj, pspec,
+ include_value);
+}
+
+/**
+ * gst_element_add_property_notify_watch:
+ * @element: a #GstElement to watch for property changes
+ * @property_name: (allow-none): name of property to watch for changes, or
+ * NULL to watch all properties
+ * @include_value: whether to include the new property value in the message
+ *
+ * Returns: a watch id, which can be used in connection with
+ * gst_element_remove_property_notify_watch() to remove the watch again.
+ *
+ * Since: 1.10
+ */
+gulong
+gst_element_add_property_notify_watch (GstElement * element,
+ const gchar * property_name, gboolean include_value)
+{
+ const gchar *sep;
+ gchar *signal_name;
+ gulong id;
+
+ g_return_val_if_fail (GST_IS_ELEMENT (element), 0);
+
+ sep = (property_name != NULL) ? "::" : NULL;
+ signal_name = g_strconcat ("notify", sep, property_name, NULL);
+ id = g_signal_connect (element, signal_name,
+ G_CALLBACK (gst_element_property_notify_cb),
+ GINT_TO_POINTER (include_value));
+ g_free (signal_name);
+
+ return id;
+}
+
+/**
+ * gst_element_add_property_deep_notify_watch:
+ * @element: a #GstElement to watch (recursively) for property changes
+ * @property_name: (allow-none): name of property to watch for changes, or
+ * NULL to watch all properties
+ * @include_value: whether to include the new property value in the message
+ *
+ * Returns: a watch id, which can be used in connection with
+ * gst_element_remove_property_notify_watch() to remove the watch again.
+ *
+ * Since: 1.10
+ */
+gulong
+gst_element_add_property_deep_notify_watch (GstElement * element,
+ const gchar * property_name, gboolean include_value)
+{
+ const gchar *sep;
+ gchar *signal_name;
+ gulong id;
+
+ g_return_val_if_fail (GST_IS_ELEMENT (element), 0);
+
+ sep = (property_name != NULL) ? "::" : NULL;
+ signal_name = g_strconcat ("deep-notify", sep, property_name, NULL);
+ id = g_signal_connect (element, signal_name,
+ G_CALLBACK (gst_element_property_deep_notify_cb),
+ GINT_TO_POINTER (include_value));
+ g_free (signal_name);
+
+ return id;
+}
+
+/**
+ * gst_element_remove_property_notify_watch:
+ * @element: a #GstElement being watched for property changes
+ * @watch_id: watch id to remove
+ *
+ * Since: 1.10
+ */
+void
+gst_element_remove_property_notify_watch (GstElement * element, gulong watch_id)
+{
+ g_signal_handler_disconnect (element, watch_id);
+}
/* factory management */
GstElementFactory* gst_element_get_factory (GstElement *element);
+/* utility functions */
+gulong gst_element_add_property_notify_watch (GstElement * element,
+ const gchar * property_name,
+ gboolean include_value);
+
+gulong gst_element_add_property_deep_notify_watch (GstElement * element,
+ const gchar * property_name,
+ gboolean include_value);
+
+void gst_element_remove_property_notify_watch (GstElement * element,
+ gulong watch_id);
+
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstElement, gst_object_unref)
#endif
{GST_MESSAGE_HAVE_CONTEXT, "have-context", 0},
{GST_MESSAGE_DEVICE_ADDED, "device-added", 0},
{GST_MESSAGE_DEVICE_REMOVED, "device-removed", 0},
+ {GST_MESSAGE_PROPERTY_NOTIFY, "property-notify", 0},
{0, NULL, 0}
};
gst_structure_id_get (GST_MESSAGE_STRUCTURE (message),
GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL);
}
+
+/**
+ * gst_message_new_property_notify:
+ * @src: The #GstObject whose property changed (may or may not be a #GstElement)
+ * @property_name: name of the property that changed
+ * @val: (allow-none) (transfer full): new property value, or %NULL
+ *
+ * Returns: a newly allocated #GstMessage
+ *
+ * Since: 1.10
+ */
+GstMessage *
+gst_message_new_property_notify (GstObject * src, const gchar * property_name,
+ GValue * val)
+{
+ GstStructure *structure;
+ GValue name_val = G_VALUE_INIT;
+
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ structure = gst_structure_new_id_empty (GST_QUARK (MESSAGE_PROPERTY_NOTIFY));
+ g_value_init (&name_val, G_TYPE_STRING);
+ /* should already be interned, but let's make sure */
+ g_value_set_static_string (&name_val, g_intern_string (property_name));
+ gst_structure_id_take_value (structure, GST_QUARK (PROPERTY_NAME), &name_val);
+ if (val != NULL)
+ gst_structure_id_take_value (structure, GST_QUARK (PROPERTY_VALUE), val);
+
+ return gst_message_new_custom (GST_MESSAGE_PROPERTY_NOTIFY, src, structure);
+}
+
+/**
+ * gst_message_parse_property_notify:
+ * @message: a #GstMessage of type %GST_MESSAGE_PROPERTY_NOTIFY
+ * @object: (out) (allow-none) (transfer none): location where to store a
+ * pointer to the object whose property got changed, or %NULL
+ * @property_name: (out) (allow-none): return location for the name of the
+ * property that got changed, or %NULL
+ * @property_value: (out) (allow-none): return location for the new value of
+ * the property that got changed, or %NULL. This will only be set if the
+ * property notify watch was told to include the value when it was set up
+ *
+ * Parses a property-notify message. These will be posted on the bus only
+ * when set up with gst_element_add_property_notify_watch() or
+ * gst_element_add_property_deep_notify_watch().
+ *
+ * Since: 1.10
+ */
+void
+gst_message_parse_property_notify (GstMessage * message, GstObject ** object,
+ const gchar ** property_name, const GValue ** property_value)
+{
+ const GstStructure *s = GST_MESSAGE_STRUCTURE (message);
+
+ g_return_if_fail (GST_IS_MESSAGE (message));
+ g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_PROPERTY_NOTIFY);
+
+ if (object)
+ *object = GST_MESSAGE_SRC (message);
+
+ if (property_name) {
+ const GValue *name_value;
+
+ name_value = gst_structure_id_get_value (s, GST_QUARK (PROPERTY_NAME));
+ *property_name = g_value_get_string (name_value);
+ }
+
+ if (property_value)
+ *property_value =
+ gst_structure_id_get_value (s, GST_QUARK (PROPERTY_VALUE));
+}
* a #GstDeviceProvider (Since 1.4)
* @GST_MESSAGE_DEVICE_REMOVED: Message indicating a #GstDevice was removed
* from a #GstDeviceProvider (Since 1.4)
+ * @GST_MESSAGE_PROPERTY_NOTIFY: Message indicating a #GObject property has
+ * changed (Since 1.10)
* @GST_MESSAGE_ANY: mask for all of the above messages.
*
* The different message types that are available.
GST_MESSAGE_EXTENDED = (1 << 31),
GST_MESSAGE_DEVICE_ADDED = GST_MESSAGE_EXTENDED + 1,
GST_MESSAGE_DEVICE_REMOVED = GST_MESSAGE_EXTENDED + 2,
+ GST_MESSAGE_PROPERTY_NOTIFY = GST_MESSAGE_EXTENDED + 3,
GST_MESSAGE_ANY = (gint) (0xffffffff)
} GstMessageType;
GstMessage * gst_message_new_device_removed (GstObject * src, GstDevice * device) G_GNUC_MALLOC;
void gst_message_parse_device_removed (GstMessage * message, GstDevice ** device);
+/* PROPERTY_NOTIFY */
+GstMessage * gst_message_new_property_notify (GstObject * src, const gchar * property_name, GValue * val) G_GNUC_MALLOC;
+void gst_message_parse_property_notify (GstMessage * message, GstObject ** object, const gchar ** property_name, const GValue ** property_value);
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstMessage, gst_message_unref)
"GstMessageNeedContext", "GstMessageHaveContext", "context", "context-type",
"GstMessageStreamStart", "group-id", "uri-redirection",
"GstMessageDeviceAdded", "GstMessageDeviceRemoved", "device",
- "uri-redirection-permanent"
+ "uri-redirection-permanent", "GstMessagePropertyNotify", "property-name",
+ "property-value"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];
GST_QUARK_MESSAGE_DEVICE_REMOVED = 171,
GST_QUARK_DEVICE = 172,
GST_QUARK_URI_REDIRECTION_PERMANENT = 173,
- GST_QUARK_MAX = 174
+ GST_QUARK_MESSAGE_PROPERTY_NOTIFY = 174,
+ GST_QUARK_PROPERTY_NAME = 175,
+ GST_QUARK_PROPERTY_VALUE = 176,
+ GST_QUARK_MAX = 177
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
GST_END_TEST;
+/* need to return the message here because object, property name and value
+ * are only valid as long as we keep the message alive */
+static GstMessage *
+bus_wait_for_notify_message (GstBus * bus, GstElement ** obj,
+ const gchar ** prop_name, const GValue ** val)
+{
+ GstMessage *msg;
+
+ do {
+ msg = gst_bus_timed_pop_filtered (bus, -1, GST_MESSAGE_ANY);
+ if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_PROPERTY_NOTIFY)
+ break;
+ gst_message_unref (msg);
+ } while (TRUE);
+
+ gst_message_parse_property_notify (msg, (GstObject **) obj, prop_name, val);
+ return msg;
+}
+
+GST_START_TEST (test_property_notify_message)
+{
+ GstElement *pipeline, *identity;
+ gulong watch_id0, watch_id1, watch_id2, deep_watch_id1, deep_watch_id2;
+ GstBus *bus;
+
+ pipeline = gst_pipeline_new (NULL);
+ identity = gst_element_factory_make ("identity", NULL);
+ gst_bin_add (GST_BIN (pipeline), identity);
+
+ bus = GST_ELEMENT_BUS (pipeline);
+
+ /* need to set state to READY, otherwise bus will be flushing and discard
+ * our messages */
+ gst_element_set_state (pipeline, GST_STATE_READY);
+
+ watch_id0 = gst_element_add_property_notify_watch (identity, NULL, FALSE);
+
+ watch_id1 = gst_element_add_property_notify_watch (identity, "sync", FALSE);
+
+ watch_id2 = gst_element_add_property_notify_watch (identity, "silent", TRUE);
+
+ deep_watch_id1 =
+ gst_element_add_property_deep_notify_watch (pipeline, NULL, TRUE);
+
+ deep_watch_id2 =
+ gst_element_add_property_deep_notify_watch (pipeline, "silent", FALSE);
+
+ /* Now test property changes and if we get the messages we expect. We rely
+ * on the signals being fired in the order that they were set up here. */
+ {
+ const GValue *val;
+ const gchar *name;
+ GstMessage *msg;
+ GstElement *obj;
+
+ /* A - This should be picked up by... */
+ g_object_set (identity, "dump", TRUE, NULL);
+ /* 1) the catch-all notify on the element (no value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless (obj == identity);
+ fail_unless_equals_string (name, "dump");
+ fail_unless (val == NULL);
+ gst_message_unref (msg);
+ /* 2) the catch-all deep-notify on the pipeline (with value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless_equals_string (name, "dump");
+ fail_unless (obj == identity);
+ fail_unless (G_VALUE_HOLDS_BOOLEAN (val));
+ fail_unless_equals_int (g_value_get_boolean (val), TRUE);
+ gst_message_unref (msg);
+
+ /* B - This should be picked up by... */
+ g_object_set (identity, "sync", TRUE, NULL);
+ /* 1) the catch-all notify on the element (no value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless (obj == identity);
+ fail_unless_equals_string (name, "sync");
+ fail_unless (val == NULL);
+ gst_message_unref (msg);
+ /* 2) the "sync" notify on the element (no value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless (obj == identity);
+ fail_unless_equals_string (name, "sync");
+ fail_unless (val == NULL);
+ gst_message_unref (msg);
+ /* 3) the catch-all deep-notify on the pipeline (with value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless_equals_string (name, "sync");
+ fail_unless (obj == identity);
+ fail_unless (G_VALUE_HOLDS_BOOLEAN (val));
+ fail_unless_equals_int (g_value_get_boolean (val), TRUE);
+ gst_message_unref (msg);
+
+ /* C - This should be picked up by... */
+ g_object_set (identity, "silent", FALSE, NULL);
+ /* 1) the catch-all notify on the element (no value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless (obj == identity);
+ fail_unless_equals_string (name, "silent");
+ fail_unless (val == NULL);
+ gst_message_unref (msg);
+ /* 2) the "silent" notify on the element (with value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless (obj == identity);
+ fail_unless_equals_string (name, "silent");
+ fail_unless (val != NULL);
+ fail_unless (G_VALUE_HOLDS_BOOLEAN (val));
+ fail_unless_equals_int (g_value_get_boolean (val), FALSE);
+ gst_message_unref (msg);
+ /* 3) the catch-all deep-notify on the pipeline (with value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless_equals_string (name, "silent");
+ fail_unless (obj == identity);
+ fail_unless (G_VALUE_HOLDS_BOOLEAN (val));
+ fail_unless_equals_int (g_value_get_boolean (val), FALSE);
+ gst_message_unref (msg);
+ /* 4) the "silent" deep-notify on the pipeline (without value) */
+ msg = bus_wait_for_notify_message (bus, &obj, &name, &val);
+ fail_unless_equals_string (name, "silent");
+ fail_unless (obj == identity);
+ fail_unless (val == NULL);
+ gst_message_unref (msg);
+ }
+
+ gst_element_remove_property_notify_watch (identity, watch_id0);
+ gst_element_remove_property_notify_watch (identity, watch_id1);
+ gst_element_remove_property_notify_watch (identity, watch_id2);
+ gst_element_remove_property_notify_watch (pipeline, deep_watch_id1);
+ gst_element_remove_property_notify_watch (pipeline, deep_watch_id2);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
static Suite *
gst_element_suite (void)
{
tcase_add_test (tc_chain, test_link);
tcase_add_test (tc_chain, test_link_no_pads);
tcase_add_test (tc_chain, test_pad_templates);
+ tcase_add_test (tc_chain, test_property_notify_message);
return s;
}
gst_double_range_get_type
gst_element_abort_state
gst_element_add_pad
+ gst_element_add_property_deep_notify_watch
+ gst_element_add_property_notify_watch
gst_element_change_state
gst_element_class_add_metadata
gst_element_class_add_pad_template
gst_element_register
gst_element_release_request_pad
gst_element_remove_pad
+ gst_element_remove_property_notify_watch
gst_element_request_pad
gst_element_seek
gst_element_seek_simple
gst_message_new_need_context
gst_message_new_new_clock
gst_message_new_progress
+ gst_message_new_property_notify
gst_message_new_qos
gst_message_new_request_state
gst_message_new_reset_time
gst_message_parse_info
gst_message_parse_new_clock
gst_message_parse_progress
+ gst_message_parse_property_notify
gst_message_parse_qos
gst_message_parse_qos_stats
gst_message_parse_qos_values