gstreamer源码阅读笔记:插件系统

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

https://www.cnblogs.com/xleng/p/10763739.html

热门文章

暂无图片
编程学习 ·

exe4j详细使用教程(附下载安装链接)

一、exe4j介绍 ​ exe4j是一个帮助你集成Java应用程序到Windows操作环境的java可执行文件生成工具,无论这些应用是用于服务器,还是图形用户界面(GUI)或命令行的应用程序。如果你想在任务管理器中及Windows XP分组的用户友好任务栏…
暂无图片
编程学习 ·

AUTOSAR从入门到精通100讲(126)-浅谈车载充电系统通信方案

01 引言 本文深入研究车载充电系统策略,设计出一套基于电动汽车电池管理系统与车载充电机的CAN通信协议,可供电动汽车设计人员参考借鉴。 02 电动汽车充电系统通讯网络 电动汽车整车控制系统中采用的是CAN总线通信方式,由一个整车内部高速CAN网络、内部低速CAN网络和一个充电…
暂无图片
编程学习 ·

CMake(九):生成器表达式

当运行CMake时,开发人员倾向于认为它是一个简单的步骤,需要读取项目的CMakeLists.txt文件,并生成相关的特定于生成器的项目文件集(例如Visual Studio解决方案和项目文件,Xcode项目,Unix Makefiles或Ninja输入文件)。然…
暂无图片
编程学习 ·

47.第十章 网络协议和管理配置 -- 网络配置(八)

4.3.3 route 命令 路由表管理命令 路由表主要构成: Destination: 目标网络ID,表示可以到达的目标网络ID,0.0.0.0/0 表示所有未知网络,又称为默认路由,优先级最低Genmask:目标网络对应的netmaskIface: 到达对应网络,应该从当前主机哪个网卡发送出来Gateway: 到达非直连的网络,…
暂无图片
编程学习 ·

元宇宙技术基础

请看图: 1、通过AR、VR等交互技术提升游戏的沉浸感 回顾游戏的发展历程,沉浸感的提升一直是技术突破的主要方向。从《愤怒的小鸟》到CSGO,游戏建模方式从2D到3D的提升使游戏中的物体呈现立体感。玩家在游戏中可以只有切换视角,进而提升沉浸…
暂无图片
编程学习 ·

flink的伪分布式搭建

一 flink的伪分布式搭建 1.1 执行架构图 1.Flink程序需要提交给 Job Client2.Job Client将作业提交给 Job Manager3.Job Manager负责协调资源分配和作业执行。 资源分配完成后,任务将提交给相应的 Task Manage。4.Task Manager启动一个线程以开始执行。Task Manage…
暂无图片
编程学习 ·

十进制正整数与二进制字符串的转换(C++)

Function one: //十进制数字转成二进制字符串 string Binary(int x) {string s "";while(x){if(x % 2 0) s 0 s;else s 1 s;x / 2;}return s; } Function two: //二进制字符串变为十进制数字 int Decimal(string s) {int num 0, …
暂无图片
编程学习 ·

[含lw+源码等]微信小程序校园辩论管理平台+后台管理系统[包运行成功]Java毕业设计计算机毕设

项目功能简介: 《微信小程序校园辩论管理平台后台管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序做的辩论管理前台和Java做的后台管理系统: 微信小程序——辩论管理前台涉及技术:WXML 和 WXS…
暂无图片
编程学习 ·

树莓派驱动DHT11温湿度传感器

1,直接使用python库 代码如下 import RPi.GPIO as GPIO import dht11 import time import datetimeGPIO.setwarnings(True) GPIO.setmode(GPIO.BCM)instance dht11.DHT11(pin14)try:while True:result instance.read()if result.is_valid():print(ok)print(&quo…
暂无图片
编程学习 ·

ELK简介

ELK简介 ELK是三个开源软件的缩写,Elasticsearch、Logstash、Kibana。它们都是开源软件。不过现在还新增了一个 Beats,它是一个轻量级的日志收集处理工具(Agent),Beats 占用资源少,适合于在各个服务器上搜集日志后传输给 Logstas…
暂无图片
编程学习 ·

Linux 基础

通常大数据框架都部署在 Linux 服务器上,所以需要具备一定的 Linux 知识。Linux 书籍当中比较著名的是 《鸟哥私房菜》系列,这个系列很全面也很经典。但如果你希望能够快速地入门,这里推荐《Linux 就该这么学》,其网站上有免费的电…
暂无图片
编程学习 ·

Windows2022 无线网卡装不上驱动

想来 Windows2022 和 windows10/11 的驱动应该差不多通用的,但是死活装不上呢? 搜一下,有人提到 “默认安装时‘无线LAN服务’是关闭的,如果需要开启,只需要在“添加角色和功能”中,选择开启“无线LAN服务…
暂无图片
编程学习 ·

【嵌入式面试宝典】版本控制工具Git常用命令总结

目录 创建仓库 查看信息 版本回退 版本检出 远程库 Git 创建仓库 git initgit add <file> 可反复多次使用&#xff0c;添加多个文件git commit -m <message> 查看信息 git status 仓库当前的状态git diff 差异对比git log 历史记录&#xff0c;提交日志--pret…
暂无图片
编程学习 ·

用Postman生成测试报告

newman newman是一款基于nodejs开发的可以运行postman脚本的工具&#xff0c;使用Newman&#xff0c;可以直接从命令运行和测试postman集合。 安装nodejs 下载地址&#xff1a;https://nodejs.org/en/download/ 选择自己系统相对应的版本内容进行下载&#xff0c;然后傻瓜式安…
暂无图片
编程学习 ·

Java面向对象之多态、向上转型和向下转型

文章目录前言一、多态二、引用类型之间的转换Ⅰ.向上转型Ⅱ.向下转型总结前言 今天继续Java面向对象的学习&#xff0c;学习面向对象的第三大特征&#xff1a;多态&#xff0c;了解多态的意义&#xff0c;以及两种引用类型之间的转换&#xff1a;向上转型、向下转型。  希望能…