[GStreamer] (1) GStreamer-plugin 基础

这篇具有很好参考价值的文章主要介绍了[GStreamer] (1) GStreamer-plugin 基础。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

插件编写者指南

GStreamer 插件基础
创建 高级 元素类型
创建 高级特殊元素类型

介绍

- 在本指南中,您将学习如何应用基本的 GStreamer 编程概念来编写一个简单的插件。

编写插件的基础流程
  1. 构建样板

    • 通过下载模板参考,重写、添加相应的函数
      • $ cd ~/gst-template/gst-plugin/src
      • $ …/tools/make_element MyFilter
      • 大写对于插件的名称很重要。请记住,在某些操作系统下,大写通常在指定目录和文件名时也很重要。
    • 得到 gstmyfilter.c和gstmyfilter.h.
    //  数据结构 && 双构造函数(gst_XXX_class_init + XXX_init )

    typedef struct _GstMyFilter {
        GstElement element;

        GstPad *sinkpad, *srcpad;

        gboolean silent; 
    } GstMyFilter;

    gst_XXX_class_init(){
    // 1. 设置属性  
        gst_my_filter_set_property();
        gst_my_filter_set_property();
        g_object_class_install_property() ; 
    // 2. 元素元数据  元素详细信息 数据提供额外的元素信息。
        gst_element_class_set_details_simple() || 
        gst_element_class_set_metadata() || gst_element_class_set_static_metadata();   
    // 3. pad模版: GstStaticPadTemplate 是对元素将(或可能)创建和使用的pad的描述。
        static GstStaticPadTemplate sink_factory =
        GST_STATIC_PAD_TEMPLATE (
            "sink",
            GST_PAD_SINK,
            GST_PAD_ALWAYS,
            GST_STATIC_CAPS ("ANY")  // or others
        ); 
        gst_element_class_add_pad_template ( gst_static_pad_template_get() ). 
    // 4. 管理过滤器状态
        element_class->change_state = gst_my_filter_change_state;
    // 5. 
    }; 

    xxxxxx_init(){
        GST_DEBUG_CATEGORY_INIT();
        gst_element_register();
    /* 一旦我们编写了定义插件所有部分的代码,我们就需要编写 plugin_init() / xxxxxx_init() 函数。
     * 这是一个特殊的函数,它在插件加载后立即被调用,并且应该返回 TRUE 或FALSE,
     * 具体取决于它是否正确加载了任何依赖项。
     * 此外,在此函数中,应注册插件中任何受支持的元素类型。
     * 返回的信息将缓存在中央注册表中。
     */
    }GST_PLUGIN_DEFINE(); 
  1. 自定义/指定 pad: 数据进出元素的端口

    • 静态 pad 模板如何将 pad 模板注册到元素类。
    • 事件功能:_event () -function 配置特定格式以及如何注册函数以让数据流过元素。
    • 创建 pad 后,您必须设置一个 _chain ()函数指针,该指针将接收和处理 sinkpad 上的输入数据。
    • dequery 询问功能:
static void
gst_my_filter_init (GstMyFilter *filter)
{ 
  filter->sinkpad = gst_pad_new_from_static_template (
    &sink_template, "sink");// "src"  is same
 
//   gst_pad_set_event_function (filter->sinkpad,
//       GST_DEBUG_FUNCPTR (gst_my_filter_sink_event));
//   gst_pad_set_chain_function (filter->sinkpad,
//       GST_DEBUG_FUNCPTR (gst_my_filter_chain));
//   gst_pad_set_query_function (filter->sinkpad,
//       GST_DEBUG_FUNCPTR (gst_my_filter_src_query)); 


  GST_PAD_SET_PROXY_CAPS (filter->sinkpad);
  gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
    
  filter->silent = FALSE;
}
  1. PAD ->_chain 功能: 是进行所有数据处理的函数。
    • SISO 函数,线性函数
    • 因此对于每个传入缓冲区,也会有一个缓冲区流出。
    • 缓冲区并不总是可写的。
    static GstFlowReturn
    gst_my_filter_chain(GstPad    *pad,   GstObject *parent, GstBuffer *buf){
        // ...
        return gst_pad_push (filter->srcpad, buf);
    }
  1. PAD ->_事件功能: 事件函数
    • 会通知您数据流中发生的特殊事件(例如 caps、end-of-stream、newsegment、tags 等)。
    • 事件可以在上游和下游传播,因此您可以在接收垫和源垫上接收它们。
static gboolean gst_my_filter_sink_event (GstPad    *pad,
                                          GstObject *parent,
                                          GstEvent  *event){
    switch (GST_EVENT_TYPE (event)) {
        
    default: 
        ret = gst_pad_event_default (pad, parent, event);
        break;
    }
  return ret;
};
  1. PAD -> dequery() 查询功能 必须回复

    • 诸如位置、持续时间之类的查询,
    • 查询可以在上游和下游传播,
    static gboolean
    gst_my_filter_src_query (GstPad    *pad,
                    GstObject *parent,
                    GstQuery  *query){
        switch (GST_QUERY_TYPE (query)) {
            
        default: 
            ret = gst_pad_query_default (pad, parent, query);
            break;
        }
        return ret;
    };
    
  2. 4 种 states 状态:状态描述了元素实例是否已初始化、是否准备好传输数据以及当前是否正在处理数据

    • GST_STATE_NULL
      GST_STATE_NULL是元素的默认状态。
      在这种状态下,它没有分配任何运行时资源,它没有加载任何运行时库,它显然不能处理数据。
    • GST_STATE_READY
      GST_STATE_READY是元素可以处于的下一个状态。
      在 READY 状态下,元素分配了所有默认资源(运行时库、运行时内存)。但是,它还没有分配或定义任何特定于流的东西。
      当从 NULL 变为 READY 状态 ( GST_STATE_CHANGE_NULL_TO_READY) 时,元素应分配任何非流特定资源并应加载运行时可加载库(如果有)。
      当反过来(从 READY 到 NULL, GST_STATE_CHANGE_READY_TO_NULL)时,元素应该卸载这些库并释放所有分配的资源。
      这种资源的例子是硬件设备。
      请注意,文件通常是流,因此应将它们视为特定于流的资源;因此,不应在此状态下分配它们。
    • GST_STATE_PAUSED
      GST_STATE_PAUSED是元素准备好接受和处理数据的状态。
      对于大多数元素,此状态与 PLAYING 相同。此规则的唯一例外是接收器元素。接收器元素只接受一个数据缓冲区然后阻塞。此时管道已“预卷”并准备好立即呈现数据。
    • GST_STATE_PLAYING
      GST_STATE_PLAYING是元素可以处于的最高状态。对于大多数元素,此状态与 PAUSED 完全相同,
      它们接受并处理带有数据的事件和缓冲区。只有 sink 元素需要区分 PAUSED 和 PLAYING 状态。在 PLAYING 状态下,sink 元素实际渲染传入的数据,例如将音频输出到声卡或将视频图片渲染到图像接收器。
    1. 派生自新的基类之一, 重写基类的 start() 和 stop() 虚函数

    2. 从 GstElement 或其他未构建在基类之上的类派生: 实现自己的状态更改函数才能收到状态更改的通知. as demuxer 或 muxer

      • 可以通过虚函数指针通知元素状态变化。在此函数中,元素可以初始化元素所需的任何类型的特定数据,并且可以选择无法从一种状态转到另一种状态。
      • 不要为未处理的状态更改 g_assert;这由 GstElement 基类处理。
    static GstStateChangeReturn
    gst_my_filter_change_state (GstElement *element, GstStateChange transition){

        switch (transition) {
            case GST_STATE_CHANGE_NULL_TO_READY:
            case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
        };
        /*  向上 (NULL=>READY, READY=>PAUSED, PAUSED=>PLAYING)
         *  向下 (PLAYING=>PAUSED, PAUSED=>READY, READY=>NULL) 状态更改在两个单独的switch块中处理
         * 向下状态更改只有在我们链接到父类的状态更改函数之后才能处理。为了安全地处理多个线程的并发访问 
         */
        switch (transition) {
            case GST_STATE_CHANGE_READY_TO_NULL:
        }; 

        GST_ELEMENT_CLASS (parent_class)->change_state (element, transition) == GST_STATE_CHANGE_FAILURE;  
    };  
  1. 属性 成员变量 控制
    • 控制元素行为方式的主要和最重要的方法
static void
gst_my_filter_set_property (GObject      *object,
                guint         prop_id,
                const GValue *value,
                GParamSpec   *pspec);
static void
gst_my_filter_get_property (GObject    *object,
                guint       prop_id,
                GValue     *value,
                GParamSpec *pspec);
  1. signal

    • GObject signal 可用于通知应用程序特定于该对象的事件。
  2. 测试 plugin 的程序代码

    初始化 GStreamer 核心库 gst_init ()/gst_init_get_option_group ()

    使用 创建元素gst_element_factory_make ()

    链接期间-运行期间

    永远不要忘记清理插件或测试应用程序中的内存。
    当进入 NULL 状态时,你的元素应该清理分配的内存和缓存 应该关闭所有对可能的支持库的引用 应用程序应该unref ()通过管道并确保它不会崩溃。文章来源地址https://www.toymoban.com/news/detail-431931.html

#include <gst/gst.h>

static gboolean
bus_call (GstBus     *bus,
      GstMessage *msg,
      gpointer    data)
{
  GMainLoop *loop = data;

  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS:
      g_print ("End-of-stream\n");
      g_main_loop_quit (loop);
      break;
    case GST_MESSAGE_ERROR: {
      gchar *debug = NULL;
      GError *err = NULL;

      gst_message_parse_error (msg, &err, &debug);

      g_print ("Error: %s\n", err->message);
      g_error_free (err);

      if (debug) {
        g_print ("Debug details: %s\n", debug);
        g_free (debug);
      }

      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }

  return TRUE;
}

gint
main (gint   argc,
      gchar *argv[])
{
  GstStateChangeReturn ret;
  GstElement *pipeline, *filesrc, *decoder, *filter, *sink;
  GstElement *convert1, *convert2, *resample;
  GMainLoop *loop;
  GstBus *bus;
  guint watch_id;

  /* initialization */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);
  if (argc != 2) {
    g_print ("Usage: %s <mp3 filename>\n", argv[0]);
    return 01;
  }

  /* create elements */
  pipeline = gst_pipeline_new ("my_pipeline");

  /* watch for messages on the pipeline's bus (note that this will only
   * work like this when a GLib main loop is running) */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  watch_id = gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  filesrc  = gst_element_factory_make ("filesrc", "my_filesource");
  decoder  = gst_element_factory_make ("mad", "my_decoder");

  /* putting an audioconvert element here to convert the output of the
   * decoder into a format that my_filter can handle (we are assuming it
   * will handle any sample rate here though) */
  convert1 = gst_element_factory_make ("audioconvert", "audioconvert1");

  /* use "identity" here for a filter that does nothing */
  filter   = gst_element_factory_make ("my_filter", "my_filter");

  /* there should always be audioconvert and audioresample elements before
   * the audio sink, since the capabilities of the audio sink usually vary
   * depending on the environment (output used, sound card, driver etc.) */
  convert2 = gst_element_factory_make ("audioconvert", "audioconvert2");
  resample = gst_element_factory_make ("audioresample", "audioresample");
  sink     = gst_element_factory_make ("pulsesink", "audiosink");

  if (!sink || !decoder) {
    g_print ("Decoder or output could not be found - check your install\n");
    return -1;
  } else if (!convert1 || !convert2 || !resample) {
    g_print ("Could not create audioconvert or audioresample element, "
             "check your installation\n");
    return -1;
  } else if (!filter) {
    g_print ("Your self-written filter could not be found. Make sure it "
             "is installed correctly in $(libdir)/gstreamer-1.0/ or "
             "~/.gstreamer-1.0/plugins/ and that gst-inspect-1.0 lists it. "
             "If it doesn't, check with 'GST_DEBUG=*:2 gst-inspect-1.0' for "
             "the reason why it is not being loaded.");
    return -1;
  }

  g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);

  gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, convert1, filter,
                    convert2, resample, sink, NULL);

  /* link everything together */
  if (!gst_element_link_many (filesrc, decoder, convert1, filter, convert2,
                              resample, sink, NULL)) {
    g_print ("Failed to link one or more elements!\n");
    return -1;
  }

  /* run */
  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    GstMessage *msg;

    g_print ("Failed to start up pipeline!\n");

    /* check if there is an error message with details on the bus */
    msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0);
    if (msg) {
      GError *err = NULL;

      gst_message_parse_error (msg, &err, NULL);
      g_print ("ERROR: %s\n", err->message);
      g_error_free (err);
      gst_message_unref (msg);
    }
    return -1;
  }

  g_main_loop_run (loop);

  /* clean up */
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  g_source_remove (watch_id);
  g_main_loop_unref (loop);

  return 0;
}

到了这里,关于[GStreamer] (1) GStreamer-plugin 基础的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【音视频处理】基础框架介绍,FFmpeg、GStreamer、OpenCV、OpenGL

    大家好,欢迎来到停止重构的频道。  本期我们介绍 音视频处理的基础框架 。 包括FFmpeg、GStreamer、OpenCV、OpenGL 。 我们按这样的分类介绍 : 1、编解码处理:FFmpeg、GStreamer 2、图像分析:OpenCV 3、复杂图像生成:OpenGL 首先是编解码处理的基础框架,这类基础框架的 应用场景

    2024年02月08日
    浏览(48)
  • SystemUI之插件Plugin

    一、为何要用插件plugin SystemUI模块非常多,结构自然也就非常复杂,而且SystemUI是一个常驻的进程,不能随意做修改升级,如果修改不到位,很可能会存在bug,这是修复就非常难。另外一个原因是可以方便客户客制化,如需要改变状态栏的背景色、显示时钟的风格、锁屏壁纸

    2024年03月20日
    浏览(38)
  • Vue-插件(plugin)

    插件是vue中特别强大并且特别简单的一个东西,它可以帮助我们增强vue 插件本质来说就是一个对象,但是这个对象必须包含install(安装)方法,由vue帮助我们调用 只要插件写的足够的好,就可以帮助我们实现很多的功能,提高开发效率,而我们只需要简单的引入并且use下即可

    2024年02月09日
    浏览(33)
  • ChatGPT 插件Plugin集合

    ChatGPT的插件功能推出一段时间了,陆陆续续的上架了得有200+了。 但是其中大部分都不是很好用,并且找起来也复杂。 推荐一个不知名热心人做的导航页。 ChatGPT Plugins Overview 基本上集合了所有的插件,并且还在实时更新中。  需要升级4.0,可以参考这:24年最新版升级 Cha

    2024年03月15日
    浏览(44)
  • 插件(Plugins)

    插件是什么? Kong Gateway是一个Lua应用程序,旨在加载和执行Lua或Go模块,我们通常称为插件。Kong提供了一组标准的Lua插件,这些插件与Kong Gateway捆绑在一起。您可以访问的插件集取决于您的安装方式:开源、企业版或在Kubernetes上运行的这些Kong Gateway选项之一。 Kong社区也可以

    2024年01月23日
    浏览(33)
  • 手写一个webpack插件(plugin)

    熟悉 vue 和 react 的小伙伴们都知道,在执行过程中会有各种生命周期钩子,其实webpack也不例外,在使用webpack的时候,我们有时候需要在 webpack 构建流程中引入自定义的行为,这个时候就可以在 hooks 钩子中添加自己的方法。 创建插件 webpack 加载 webpack.config.js 中所有配置,此

    2024年02月08日
    浏览(45)
  • IDEA plugins 好用的插件集

    IDEA plugins RestfulToolkit 1. 安装插件 File–Settings -- plugins -- RestfulToolkit 2.插件有点: 2.1、帮助把项目中的 RestURL 按照项目汇总出来,找到对应URL直接在IDEA上面进行请求测试。 2.2、开发Java Web页面项目,经常开发或者修复bug需要找到处理对应的Java Controller,在浏览器的console -- n

    2024年04月22日
    浏览(47)
  • flutter plugins插件【二】【FlutterAssetsGenerator】

    2、FlutterAssetsGenerator 介绍地址:https://juejin.cn/post/6898542896274735117 配置assets目录 ​ 插件会从 pubspec.yaml 文件下读取assets目录,因此要使用本插件,你需要在 pubspec.yaml 下配置资源目录 注意1:图片拖动或者粘贴到asstes/images/目录下就会触发在指定文件自动生成对应的图片路径 

    2024年02月10日
    浏览(34)
  • flutter plugins插件【一】【FlutterJsonBeanFactory】

    注意: 5.1.3版本,新生成一个entity的话需要重新运行flutter项目才行,否则 1、FlutterJsonBeanFactory 在Setting-Tools-FlutterJsonBeanFactory里边自定义实体类的后缀,默认是entity 复制json到粘贴板,右键自己要存放实体的目录,可以看到JsonToDartBeanAction Class Name 是实体名字,会默认加上ent

    2024年02月10日
    浏览(37)
  • ElasticSearch插件plugin ik分词器,报错plugin-descriptor.properties

    @ES日志中报错plugin-descriptor.properties NoSuchFileException 找不到这个文件plugin-descriptor.properties。 ` 如下图所示,下载的zip文件解压之后的情况,这里是不能放到elasticsearch的plugins中的。 分析:由于是java开发的分词器,这里很明显是maven项目的目录结构。所以要执行打包命令,生成

    2024年02月11日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包