gstreamer的插件系统需要满足若干最基本的需求
1.能动态扩展
插件的属性决定了插件应该可加载可不加载,在需要的时候加载,在不需要的时候能卸载,能随时加载,而且插件的功能要能扩展。主模块不知道插件的具体实现方式,只能与插件按照约定的接口进行交互。
2.能兼容主模块
gstreamer中使用GObject类型和对象系统。Gstreamer主模块可以很方便的管理类型和对象,方便的创建和销毁对象,便捷的使用signal机制来控制响应流程,设置和修改数据。所有的功能由若干个GObject对象承担。插件也应该如此,由最基本的GObject对象组成,能注册到GObject系统,能由GObject系统创建、引用、发送信号、解引用、销毁。
Gstreamer的插件采用动态链接库的形式,主模块加载动态链接库时,按照数据接口,找到插件的初始化函数地址。这个插件的初始化的实现方式其实是把插件内的定义的类型和对象注册到主模块的对象系统中。调用链如下:
主模块中调用链:
gst.c
static gboolean init_post (GOptionContext * context, GOptionGroup * group, gpointer data, GError ** error)//程序启动后初始化
gstregistry.c
gboolean gst_update_registry (void) //更新插件信息缓存文件
static gboolean ensure_current_registry (GError ** error) //
gstregistrybinary.c
gboolean priv_gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
gstregistry.c
static GstRegistryScanAndUpdateResult scan_and_update_registry (GstRegistry * default_registry,const gchar * registry_file, gboolean write_changes, GError ** error)
static gboolean gst_registry_scan_path_internal (GstRegistryScanContext * context,
const gchar * path)
static gboolean gst_registry_scan_path_level (GstRegistryScanContext * context,
const gchar * path, int level)
static gboolean gst_registry_scan_plugin_file (GstRegistryScanContext * context,
const gchar * filename, off_t file_size, time_t file_mtime)
gstplugin.c
GstPlugin * gst_plugin_load_file (const gchar * filename, GError ** error)
{
GstPluginDesc *desc;
GstPlugin *plugin;
GModule *module;
gboolean ret;
gpointer ptr;
GStatBuf file_status;
GstRegistry *registry;
gboolean new_plugin = TRUE;
GModuleFlags flags;
g_return_val_if_fail (filename != NULL, NULL);
registry = gst_registry_get ();
g_mutex_lock (&gst_plugin_loading_mutex);
plugin = gst_registry_lookup (registry, filename);
if (plugin) {
if (plugin->module) {
/* already loaded */
g_mutex_unlock (&gst_plugin_loading_mutex);
return plugin;
} else {
/* load plugin and update fields */
new_plugin = FALSE;
}
}
GST_CAT_DEBUG (GST_CAT_PLUGIN_LOADING, "attempt to load plugin \"%s\"",
filename);
if (g_module_supported () == FALSE) {
GST_CAT_DEBUG (GST_CAT_PLUGIN_LOADING, "module loading not supported");
g_set_error (error,
GST_PLUGIN_ERROR,
GST_PLUGIN_ERROR_MODULE, "Dynamic loading not supported");
goto return_error;
}
if (g_stat (filename, &file_status)) {
GST_CAT_DEBUG (GST_CAT_PLUGIN_LOADING, "problem accessing file");
g_set_error (error,
GST_PLUGIN_ERROR,
GST_PLUGIN_ERROR_MODULE, "Problem accessing file %s: %s", filename,
g_strerror (errno));
goto return_error;
}
flags = G_MODULE_BIND_LOCAL;
/* libgstpython.so is the gst-python plugin loader. It needs to be loaded with
* G_MODULE_BIND_LAZY.
*
* Ideally there should be a generic way for plugins to specify that they
* need to be loaded with _LAZY.
* */
if (strstr (filename, "libgstpython"))
flags |= G_MODULE_BIND_LAZY;
module = g_module_open (filename, flags);
if (module == NULL) {
GST_CAT_WARNING (GST_CAT_PLUGIN_LOADING, "module_open failed: %s",
g_module_error ());
g_set_error (error,
GST_PLUGIN_ERROR, GST_PLUGIN_ERROR_MODULE, "Opening module failed: %s",
g_module_error ());
/* If we failed to open the shared object, then it's probably because a
* plugin is linked against the wrong libraries. Print out an easy-to-see
* message in this case. */
g_warning ("Failed to load plugin '%s': %s", filename, g_module_error ());
goto return_error;
}
ret = g_module_symbol (module, "gst_plugin_desc", &ptr);
if (!ret) {
GST_DEBUG ("Could not find plugin entry point in \"%s\"", filename);
g_set_error (error,
GST_PLUGIN_ERROR,
GST_PLUGIN_ERROR_MODULE,
"File \"%s\" is not a GStreamer plugin", filename);
g_module_close (module);
goto return_error;
}
desc = (GstPluginDesc *) ptr;
if (priv_gst_plugin_loading_have_whitelist () &&
!priv_gst_plugin_desc_is_whitelisted (desc, filename)) {
GST_INFO ("Whitelist specified and plugin not in whitelist, not loading: "
"name=%s, package=%s, file=%s", desc->name, desc->source, filename);
g_set_error (error, GST_PLUGIN_ERROR, GST_PLUGIN_ERROR_MODULE,
"Not loading plugin file \"%s\", not in whitelist", filename);
g_module_close (module);
goto return_error;
}
if (new_plugin) {
plugin = g_object_newv (GST_TYPE_PLUGIN, 0, NULL);
plugin->file_mtime = file_status.st_mtime;
plugin->file_size = file_status.st_size;
plugin->filename = g_strdup (filename);
plugin->basename = g_path_get_basename (filename);
}
plugin->module = module;
plugin->orig_desc = desc;
if (new_plugin) {
/* check plugin description: complain about bad values and fail */
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, name, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, description, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, version, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, license, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, source, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, package, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, origin, filename);
if (plugin->orig_desc->name != NULL && plugin->orig_desc->name[0] == '"') {
g_warning ("Invalid plugin name '%s' - fix your GST_PLUGIN_DEFINE "
"(remove quotes around plugin name)", plugin->orig_desc->name);
}
if (plugin->orig_desc->release_datetime != NULL &&
!check_release_datetime (plugin->orig_desc->release_datetime)) {
GST_ERROR ("GstPluginDesc for '%s' has invalid datetime '%s'",
filename, plugin->orig_desc->release_datetime);
plugin->orig_desc->release_datetime = NULL;
}
}
GST_LOG ("Plugin %p for file \"%s\" prepared, calling entry function...",
plugin, filename);
/* this is where we load the actual .so, so let's trap SIGSEGV */
_gst_plugin_fault_handler_setup ();
_gst_plugin_fault_handler_filename = plugin->filename;
GST_LOG ("Plugin %p for file \"%s\" prepared, registering...",
plugin, filename);
if (!gst_plugin_register_func (plugin, plugin->orig_desc, NULL)) {
/* remove signal handler */
_gst_plugin_fault_handler_restore ();
GST_DEBUG ("gst_plugin_register_func failed for plugin \"%s\"", filename);
/* plugin == NULL */
g_set_error (error,
GST_PLUGIN_ERROR,
GST_PLUGIN_ERROR_MODULE,
"File \"%s\" appears to be a GStreamer plugin, but it failed to initialize",
filename);
goto return_error;
}
/* remove signal handler */
_gst_plugin_fault_handler_restore ();
_gst_plugin_fault_handler_filename = NULL;
GST_INFO ("plugin \"%s\" loaded", plugin->filename);
if (new_plugin) {
gst_object_ref (plugin);
gst_registry_add_plugin (gst_registry_get (), plugin);
}
g_mutex_unlock (&gst_plugin_loading_mutex);
return plugin;
return_error:
{
if (plugin)
gst_object_unref (plugin);
g_mutex_unlock (&gst_plugin_loading_mutex);
return NULL;
}
}
static GstPlugin *
gst_plugin_register_func (GstPlugin * plugin, const GstPluginDesc * desc,
gpointer user_data)
{
if (!gst_plugin_check_version (desc->major_version, desc->minor_version)) {
if (GST_CAT_DEFAULT)
GST_WARNING ("plugin \"%s\" has incompatible version, not loading",
GST_STR_NULL (plugin->filename));
return NULL;
}
if (!desc->license || !desc->description || !desc->source ||
!desc->package || !desc->origin) {
if (GST_CAT_DEFAULT)
GST_WARNING ("plugin \"%s\" has incorrect GstPluginDesc, not loading",
GST_STR_NULL (plugin->filename));
return NULL;
}
if (!gst_plugin_check_license (desc->license)) {
if (GST_CAT_DEFAULT)
GST_WARNING ("plugin \"%s\" has invalid license \"%s\", not loading",
GST_STR_NULL (plugin->filename), desc->license);
return NULL;
}
if (GST_CAT_DEFAULT)
GST_LOG ("plugin \"%s\" looks good", GST_STR_NULL (plugin->filename));
gst_plugin_desc_copy (&plugin->desc, desc);
/* make resident so we're really sure it never gets unloaded again.
* Theoretically this is not needed, but practically it doesn't hurt.
* And we're rather safe than sorry. */
if (plugin->module)
g_module_make_resident (plugin->module);
if (user_data) {
if (!(((GstPluginInitFullFunc) (desc->plugin_init)) (plugin, user_data))) {
if (GST_CAT_DEFAULT)
GST_WARNING ("plugin \"%s\" failed to initialise",
GST_STR_NULL (plugin->filename));
return NULL;
}
} else {
if (!((desc->plugin_init) (plugin))) {
if (GST_CAT_DEFAULT)
GST_WARNING ("plugin \"%s\" failed to initialise",
GST_STR_NULL (plugin->filename));
return NULL;
}
}
if (GST_CAT_DEFAULT)
GST_LOG ("plugin \"%s\" initialised", GST_STR_NULL (plugin->filename));
return plugin;
}
插件模块中的接口如下:
plugin.c
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (mpegpspesfilter_debug, "mpegpspesfilter", 0,
"MPEG-PS PES filter");
if (!gst_element_register (plugin, "mpegpsdemux", GST_RANK_PRIMARY,
GST_TYPE_FLUPS_DEMUX))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
mpegpsdemux,
"MPEG-PS demuxer",
plugin_init, VERSION,
GST_LICENSE_UNKNOWN, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
gstplugin.h
#ifdef GST_PLUGIN_BUILD_STATIC
#define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin) \
G_BEGIN_DECLS \
GST_PLUGIN_EXPORT void G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void); \
\
void \
G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void) \
{ \
gst_plugin_register_static (major, minor, G_STRINGIFY(name), \
description, init, version, license, \
PACKAGE, package, origin); \
} \
G_END_DECLS
#else /* !GST_PLUGIN_BUILD_STATIC */
#define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin) \
G_BEGIN_DECLS \
GST_PLUGIN_EXPORT GstPluginDesc gst_plugin_desc = { \
major, \
minor, \
G_STRINGIFY(name), \
(gchar *) description, \
init, \
version, \
license, \
PACKAGE, \
package, \
origin, \
__GST_PACKAGE_RELEASE_DATETIME, \
GST_PADDING_INIT \
}; \
G_END_DECLS
#endif
https://blog.csdn.net/ysu_liuyang/article/details/83145352
https://blog.csdn.net/yanbixing123/article/details/52970804
https://blog.csdn.net/chudaiao7567/article/details/100817127