plugin: add API for plugins to provide status info messages
authorTim-Philipp Müller <tim@centricular.com>
Fri, 27 Jan 2023 19:08:37 +0000 (19:08 +0000)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 21 Feb 2024 00:58:19 +0000 (00:58 +0000)
This can be used to store informational messages, errors or
warnings which can later be shown to the user in gst-inspect-1.0,
which can be useful for plugins that expose elements dynamically
based on external libraries or hardware capabilities.

Status messages can then provide an indication as to why a
plugin doesn't have any elements listed, for example.

Plus unit test to make sure code paths are exercised a little.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3832>

girs/Gst-1.0.gir
subprojects/gstreamer/gst/gst_private.h
subprojects/gstreamer/gst/gstplugin.c
subprojects/gstreamer/gst/gstplugin.h
subprojects/gstreamer/gst/gstregistrybinary.h
subprojects/gstreamer/gst/gstregistrychunks.c
subprojects/gstreamer/tests/check/gst/gstplugin.c

index 478e1bce784a3710ef19ce6799212b0cdfdae207..d51e422dd75320d81b66acd325c3fb808f049210 100644 (file)
@@ -33428,6 +33428,54 @@ arguments separated by predefined delimiters (see above).</doc>
           </parameter>
         </parameters>
       </method>
+      <method name="add_status_error" c:identifier="gst_plugin_add_status_error" version="1.24">
+        <source-position filename="../subprojects/gstreamer/gst/gstplugin.h"/>
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="plugin" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">a #GstPlugin</doc>
+            <type name="Plugin" c:type="GstPlugin*"/>
+          </instance-parameter>
+          <parameter name="message" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">the status error message</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="add_status_info" c:identifier="gst_plugin_add_status_info" version="1.24">
+        <source-position filename="../subprojects/gstreamer/gst/gstplugin.h"/>
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="plugin" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">a #GstPlugin</doc>
+            <type name="Plugin" c:type="GstPlugin*"/>
+          </instance-parameter>
+          <parameter name="message" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">the status info message</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="add_status_warning" c:identifier="gst_plugin_add_status_warning" version="1.24">
+        <source-position filename="../subprojects/gstreamer/gst/gstplugin.h"/>
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="plugin" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">a #GstPlugin</doc>
+            <type name="Plugin" c:type="GstPlugin*"/>
+          </instance-parameter>
+          <parameter name="message" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">the status warning message</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
       <method name="get_cache_data" c:identifier="gst_plugin_get_cache_data">
         <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">Gets the plugin specific data cache. If it is %NULL there is no cached data
 stored. This is the case when the registry is getting rebuilt.</doc>
@@ -33564,6 +33612,51 @@ available.</doc>
           </instance-parameter>
         </parameters>
       </method>
+      <method name="get_status_errors" c:identifier="gst_plugin_get_status_errors" version="1.24">
+        <source-position filename="../subprojects/gstreamer/gst/gstplugin.h"/>
+        <return-value transfer-ownership="full" nullable="1">
+          <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">an array of plugin status error messages, or NULL</doc>
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </return-value>
+        <parameters>
+          <instance-parameter name="plugin" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">a #GstPlugin</doc>
+            <type name="Plugin" c:type="GstPlugin*"/>
+          </instance-parameter>
+        </parameters>
+      </method>
+      <method name="get_status_infos" c:identifier="gst_plugin_get_status_infos" version="1.24">
+        <source-position filename="../subprojects/gstreamer/gst/gstplugin.h"/>
+        <return-value transfer-ownership="full" nullable="1">
+          <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">an array of plugin status info messages, or NULL</doc>
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </return-value>
+        <parameters>
+          <instance-parameter name="plugin" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">a #GstPlugin</doc>
+            <type name="Plugin" c:type="GstPlugin*"/>
+          </instance-parameter>
+        </parameters>
+      </method>
+      <method name="get_status_warnings" c:identifier="gst_plugin_get_status_warnings" version="1.24">
+        <source-position filename="../subprojects/gstreamer/gst/gstplugin.h"/>
+        <return-value transfer-ownership="full" nullable="1">
+          <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">an array of plugin status warning messages, or NULL</doc>
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </return-value>
+        <parameters>
+          <instance-parameter name="plugin" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">a #GstPlugin</doc>
+            <type name="Plugin" c:type="GstPlugin*"/>
+          </instance-parameter>
+        </parameters>
+      </method>
       <method name="get_version" c:identifier="gst_plugin_get_version">
         <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstplugin.c">get the version of the plugin</doc>
         <source-position filename="../subprojects/gstreamer/gst/gstplugin.h"/>
index 9be91ef96e4e28d9cea15b6af8287a4351da17e2..8166a454dadf179c5a04bde1e0fcd3e52ab64dc3 100644 (file)
@@ -84,7 +84,8 @@ typedef struct {
 } GstPluginDep;
 
 struct _GstPluginPrivate {
-  GList *deps;    /* list of GstPluginDep structures */
+  GList *deps;                 /* list of GstPluginDep structures */
+  GstStructure *status_info;
   GstStructure *cache_data;
 };
 
index 669648ccc0970cf9250e893411abee6b1da5442a..4a99635f36cf2f641a8a0f64d7fb2fb3dde464a7 100644 (file)
@@ -156,6 +156,10 @@ gst_plugin_finalize (GObject * object)
     gst_structure_free (plugin->priv->cache_data);
   }
 
+  if (plugin->priv->status_info) {
+    gst_structure_free (plugin->priv->status_info);
+  }
+
   G_OBJECT_CLASS (gst_plugin_parent_class)->finalize (object);
 }
 
@@ -2039,3 +2043,148 @@ gst_plugin_add_dependency_simple (GstPlugin * plugin,
   if (a_names)
     g_strfreev (a_names);
 }
+
+static void
+gst_plugin_add_status_message (GstPlugin * plugin, const gchar * field_name,
+    const gchar * message)
+{
+  const GValue *val = NULL;
+  GValue str_val = G_VALUE_INIT;
+
+  g_return_if_fail (GST_IS_PLUGIN (plugin));
+  g_return_if_fail (message != NULL);
+
+  g_value_init (&str_val, G_TYPE_STRING);
+  g_value_set_string (&str_val, message);
+
+  if (plugin->priv->status_info == NULL)
+    plugin->priv->status_info = gst_structure_new_empty ("plugin-status-info");
+  else
+    val = gst_structure_get_value (plugin->priv->status_info, field_name);
+
+  if (val != NULL) {
+    gst_value_list_append_and_take_value ((GValue *) val, &str_val);
+  } else {
+    GValue list_val = G_VALUE_INIT;
+
+    gst_value_list_init (&list_val, 1);
+    gst_value_list_append_and_take_value (&list_val, &str_val);
+    gst_structure_take_value (plugin->priv->status_info, field_name, &list_val);
+  }
+
+  GST_TRACE_OBJECT (plugin, "Status info now: %" GST_PTR_FORMAT,
+      plugin->priv->status_info);
+}
+
+/**
+ * gst_plugin_add_status_error:
+ * @plugin: a #GstPlugin
+ * @message: the status error message
+ *
+ * Since: 1.24
+ */
+void
+gst_plugin_add_status_error (GstPlugin * plugin, const gchar * message)
+{
+  gst_plugin_add_status_message (plugin, "error-message", message);
+}
+
+/**
+ * gst_plugin_add_status_warning:
+ * @plugin: a #GstPlugin
+ * @message: the status warning message
+ *
+ * Since: 1.24
+ */
+void
+gst_plugin_add_status_warning (GstPlugin * plugin, const gchar * message)
+{
+  gst_plugin_add_status_message (plugin, "warning-message", message);
+}
+
+/**
+ * gst_plugin_add_status_info:
+ * @plugin: a #GstPlugin
+ * @message: the status info message
+ *
+ * Since: 1.24
+ */
+void
+gst_plugin_add_status_info (GstPlugin * plugin, const gchar * message)
+{
+  gst_plugin_add_status_message (plugin, "info-message", message);
+}
+
+static gchar **
+gst_plugin_get_status_messages (GstPlugin * plugin, const gchar * field_name)
+{
+  const GValue *list_val;
+  guint n_vals, i;
+  gchar **arr;
+
+  g_return_val_if_fail (GST_IS_PLUGIN (plugin), NULL);
+
+  if (plugin->priv->status_info == NULL)
+    return NULL;
+
+  list_val = gst_structure_get_value (plugin->priv->status_info, field_name);
+
+  if (list_val == NULL)
+    return NULL;
+
+  n_vals = gst_value_list_get_size (list_val);
+
+  if (n_vals == 0)
+    return NULL;
+
+  arr = g_new0 (gchar *, n_vals + 1);
+
+  for (i = 0; i < n_vals; ++i) {
+    const GValue *str_val = gst_value_list_get_value (list_val, i);
+    arr[i] = g_value_dup_string (str_val);
+  }
+
+  return arr;
+}
+
+/**
+ * gst_plugin_get_status_errors:
+ * @plugin: a #GstPlugin
+ *
+ * Returns: (transfer full) (nullable): an array of plugin status error messages, or NULL
+ *
+ * Since: 1.24
+ */
+gchar **
+gst_plugin_get_status_errors (GstPlugin * plugin)
+{
+  return gst_plugin_get_status_messages (plugin, "error-message");
+}
+
+/**
+ * gst_plugin_get_status_warnings:
+ * @plugin: a #GstPlugin
+ *
+ * Returns: (transfer full) (nullable): an array of plugin status warning messages, or NULL
+ *
+ * Since: 1.24
+ */
+gchar **
+gst_plugin_get_status_warnings (GstPlugin * plugin)
+{
+  return gst_plugin_get_status_messages (plugin, "warning-message");
+}
+
+/**
+ * gst_plugin_get_status_infos:
+ * @plugin: a #GstPlugin
+ *
+ * Returns: (transfer full) (nullable): an array of plugin status info messages, or NULL
+ *
+ * Since: 1.24
+ */
+gchar **
+gst_plugin_get_status_infos (GstPlugin * plugin)
+{
+  return gst_plugin_get_status_messages (plugin, "info-message");
+}
index 7bb33568dea11835a99e951cf512edb47d6831a7..acbd71afb27e01175297add8c090db521a011b68 100644 (file)
@@ -392,6 +392,24 @@ void                    gst_plugin_add_dependency_simple (GstPlugin   * plugin,
                                                           const gchar * paths,
                                                           const gchar * names,
                                                           GstPluginDependencyFlags flags);
+GST_API
+void                    gst_plugin_add_status_error      (GstPlugin   * plugin,
+                                                          const gchar * message);
+GST_API
+void                    gst_plugin_add_status_warning    (GstPlugin   * plugin,
+                                                          const gchar * message);
+GST_API
+void                    gst_plugin_add_status_info       (GstPlugin   * plugin,
+                                                          const gchar * message);
+GST_API
+gchar **                gst_plugin_get_status_errors     (GstPlugin   * plugin);
+
+GST_API
+gchar **                gst_plugin_get_status_warnings   (GstPlugin   * plugin);
+
+GST_API
+gchar **                gst_plugin_get_status_infos      (GstPlugin   * plugin);
+
 GST_API
 void                    gst_plugin_list_free (GList *list);
 
index 22e56d19615c571af4b43990f1116d73fb175caf..6bf712c87ea8f50be82338fb2400fea89810bf96 100644 (file)
@@ -55,7 +55,7 @@ G_BEGIN_DECLS
  * This _must_ be updated whenever the registry format changes,
  * we currently use the core version where this change happened.
  */
-#define GST_MAGIC_BINARY_VERSION_STR "1.3.0"
+#define GST_MAGIC_BINARY_VERSION_STR "1.23.90"
 
 /*
  * GST_MAGIC_BINARY_VERSION_LEN:
index 24b01029a2b79c26b7844f639f5c4b67b34830f4..7c1aa96108981b72f257b8bda230e00d25099120 100644 (file)
@@ -478,6 +478,14 @@ _priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
     gst_registry_chunks_save_const_string (list, "");
   }
 
+  /* pack status info */
+  if (plugin->priv->status_info) {
+    gchar *status_str = gst_structure_to_string (plugin->priv->status_info);
+    gst_registry_chunks_save_string (list, status_str);
+  } else {
+    gst_registry_chunks_save_const_string (list, "");
+  }
+
   /* pack plugin element strings */
   gst_registry_chunks_save_const_string (list,
       (plugin->desc.release_datetime) ? plugin->desc.release_datetime : "");
@@ -826,6 +834,7 @@ _priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
   gchar *start = *in;
 #endif
   GstRegistryChunkPluginElement *pe;
+  const gchar *status_str = NULL;
   const gchar *cache_str = NULL;
   GstPlugin *plugin = NULL;
   guint i, n;
@@ -866,6 +875,11 @@ _priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
   if (plugin->desc.release_datetime[0] == '\0')
     plugin->desc.release_datetime = NULL;
 
+  /* unpack status info */
+  unpack_string_nocopy (*in, status_str, end, fail);
+  if (status_str != NULL && *status_str != '\0')
+    plugin->priv->status_info = gst_structure_from_string (status_str, NULL);
+
   /* unpack cache data */
   unpack_string_nocopy (*in, cache_str, end, fail);
   if (cache_str != NULL && *cache_str != '\0')
index a114597afa989097fe2f1f156421689ee1e230ff..dac7a8ca912486a07041a039943113360bc5a845 100644 (file)
@@ -296,6 +296,70 @@ GST_START_TEST (test_version_checks)
 
 GST_END_TEST;
 
+static gboolean
+register_check_status_messages (GstPlugin * plugin)
+{
+  gst_plugin_add_status_info (plugin, "Hello World!");
+  gst_plugin_add_status_warning (plugin, "This not so good");
+  gst_plugin_add_status_warning (plugin, "Not good either!");
+  gst_plugin_add_status_error (plugin, "Oh no!");
+  return TRUE;
+}
+
+GST_START_TEST (test_status_messages)
+{
+  GstPlugin *plugin;
+
+  fail_unless (gst_plugin_register_static (GST_VERSION_MAJOR,
+          GST_VERSION_MINOR, "status-messages", "status-messages",
+          register_check_status_messages, VERSION, GST_LICENSE, PACKAGE,
+          GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN));
+
+  fail_unless (gst_plugin_register_static (GST_VERSION_MAJOR,
+          GST_VERSION_MINOR, "no-status-messages", "no-status-messages",
+          register_check_elements, VERSION, GST_LICENSE, PACKAGE,
+          GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN));
+
+  plugin = gst_registry_find_plugin (gst_registry_get (), "status-messages");
+  fail_unless (plugin != NULL);
+
+  {
+    gchar **info_msgs = gst_plugin_get_status_infos (plugin);
+
+    fail_unless_equals_int (g_strv_length (info_msgs), 1);
+    fail_unless_equals_string (info_msgs[0], "Hello World!");
+    g_strfreev (info_msgs);
+  }
+
+  {
+    gchar **warn_msgs = gst_plugin_get_status_warnings (plugin);
+
+    fail_unless_equals_int (g_strv_length (warn_msgs), 2);
+    fail_unless_equals_string (warn_msgs[0], "This not so good");
+    fail_unless_equals_string (warn_msgs[1], "Not good either!");
+    g_strfreev (warn_msgs);
+  }
+
+  {
+    gchar **err_msgs = gst_plugin_get_status_errors (plugin);
+
+    fail_unless_equals_int (g_strv_length (err_msgs), 1);
+    fail_unless_equals_string (err_msgs[0], "Oh no!");
+    g_strfreev (err_msgs);
+  }
+
+  gst_object_unref (plugin);
+
+  plugin = gst_registry_find_plugin (gst_registry_get (), "no-status-messages");
+  fail_unless (plugin != NULL);
+  fail_unless (gst_plugin_get_status_infos (plugin) == NULL);
+  fail_unless (gst_plugin_get_status_warnings (plugin) == NULL);
+  fail_unless (gst_plugin_get_status_errors (plugin) == NULL);
+  gst_object_unref (plugin);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_plugin_suite (void)
 {
@@ -317,6 +381,7 @@ gst_plugin_suite (void)
   tcase_add_test (tc_chain, test_find_feature);
   tcase_add_test (tc_chain, test_find_element);
   tcase_add_test (tc_chain, test_version_checks);
+  tcase_add_test (tc_chain, test_status_messages);
   //tcase_add_test (tc_chain, test_typefind);
 
   return s;