plugin: add API for plugins to provide status info messages

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>
This commit is contained in:
Tim-Philipp Müller 2023-01-27 19:08:37 +00:00 committed by GStreamer Marge Bot
parent 59c09eb029
commit bc4f7040fa
7 changed files with 342 additions and 2 deletions

View 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"/>

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

View 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");
}

View 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);

View 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:

View 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')

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