GStreamer应用开发手册
Foreword 前言
安装GStreamer
在linux系统上安装
教程
基础教程
基础教程 1:世界你好!
基础教程 2:GStreamer 概念
基础教程 3:动态管道
Plugin 写作指南
导言
序言
基础
编写插件
构建模板
-
+
首页
构建模板
Constructing the Boilerplate 构建模板 In this chapter you will learn how to construct the bare minimum code for a new plugin. Starting from ground zero, you will see how to get the GStreamer template source. Then you will learn how to use a few basic tools to copy and modify a template plugin to create a new plugin. If you follow the examples here, then by the end of this chapter you will have a functional audio filter plugin that you can compile and use in GStreamer applications. 在本章中,你将学习如何为一个新插件编写最基本的代码。从零开始,你将看到如何获取 GStreamer 模板源代码。然后,你将学习如何使用一些基本工具来复制和修改模板插件,从而创建一个新插件。如果你按照这里的示例进行操作,那么在本章结束时,你将拥有一个可以编译并在 GStreamer 应用程序中使用的功能性音频滤波器插件。 Getting the GStreamer Plugin Templates 获取 GStreamer 插件模板 There are currently two ways to develop a new plugin for GStreamer: You can write the entire plugin by hand, or you can copy an existing plugin template and write the plugin code you need. The second method is by far the simpler of the two, so the first method will not even be described here. (Errm, that is, “it is left as an exercise to the reader.”) 目前有两种方法为 GStreamer 开发新插件:一种是手工编写整个插件,另一种是复制现有的插件模板,然后编写所需的插件代码。第二种方法是最简单的方法,所以这里就不介绍第一种方法了。(呃,也就是 "留给读者练习")。 The first step is to check out a copy of the gst-template git module to get an important tool and the source code template for a basic GStreamer plugin. To check out the gst-template module, make sure you are connected to the internet, and type the following commands at a command console: 第一步是查看 gst-template git 模块的副本,以获得一个重要工具和基本 GStreamer 插件的源代码模板。要查看 gst-template 模块,请确保您已连接到互联网,并在 acommandconsole 中键入以下命令: shell $ git clone https://gitlab.freedesktop.org/gstreamer/gst-template.git Initialized empty Git repository in /some/path/gst-template/.git/ remote: Counting objects: 373, done. remote: Compressing objects: 100% (114/114), done. remote: Total 373 (delta 240), reused 373 (delta 240) Receiving objects: 100% (373/373), 75.16 KiB | 78 KiB/s, done. Resolving deltas: 100% (240/240), done. This command will check out a series of files and directories into gst-template. The template you will be using is in the gst-template/gst-plugin/ directory. You should look over the files in that directory to get a general idea of the structure of a source tree for a plugin. 该命令将在gst-template中签出一系列文件和目录。您将使用的模板位于gst-template/gst-plugin/目录中。您应该查看该目录下的文件,以便对插件的源代码树结构有一个大致的了解。 If for some reason you can't access the git repository, you can also download a snapshot of the latest revision via the gitlab web interface. 如果由于某些原因无法访问 git 仓库,也可以通过 gitlab 网页界面下载最新版本的快照。 Using the Project Stamp 使用项目印章 The first thing to do when making a new element is to specify some basic details about it: what its name is, who wrote it, what version number it is, etc. We also need to define an object to represent the element and to store the data the element needs. These details are collectively known as the boilerplate. 制作一个新元素的第一件事是指定关于它的一些基本细节:它的名称、编写者、版本号等。我们还需要定义一个对象来表示元素,并存储元素所需的数据。这些细节统称为模板。 The standard way of defining the boilerplate is simply to write some code, and fill in some structures. As mentioned in the previous section, the easiest way to do this is to copy a template and add functionality according to your needs. To help you do so, there is a tool in the ./gst-plugin/tools/ directory. This tool, make_element, is a command line utility that creates the boilerplate code for you. 定义模板的标准方法是编写一些代码并填入一些结构。正如上一节所述,最简单的方法是复制一个模板,然后根据自己的需要添加功能。在./gst-plugin/tools/目录下有一个工具可以帮助您完成这项工作。该工具名为 make_element,是一个命令行实用程序,可为您创建模板代码。 To use make_element, first open up a terminal window. Change to the gst-template/gst-plugin/src directory, and then run the make_element command. The arguments to the make_element are: 要使用 make_element,首先要打开一个终端窗口。切换到gst-template/gst-plugin/src目录,然后运行make_element命令。make_element 的参数是 the name of the plugin, and 插件的名称,以及 the source file that the tool will use. By default, gstplugin is used. 工具将使用的源文件。默认使用 gstplugin。 For example, the following commands create the MyFilter plugin based on the plugin template and put the output files in the gst-template/gst-plugin/src directory: 例如,以下命令根据插件模板创建 MyFilter 插件,并将输出文件放到gst-template/gst-plugin/src目录下: shell $ cd gst-template/gst-plugin/src shell $ ../tools/make_element MyFilter Note 备注 Capitalization is important for the name of the plugin. Keep in mind that under some operating systems, capitalization is also important when specifying directory and file names in general. 大写对于插件名称很重要。请记住,在某些操作系统下,一般指定目录和文件名时,大写也很重要。 The last command creates two files: gstmyfilter.c and gstmyfilter.h. 最后一条命令会创建两个文件:gstmyfilter.c和gstmyfilter.h。 Note 备注 It is recommended that you create a copy of the gst-plugin directory before continuing. 建议您在继续之前创建一个 gst-plugin 目录副本。 Now one needs to run meson setup build from the parent directory to bootstrap the build environment. After that, the project can be built and installed using the well known ninja -C build commands. 现在,我们需要从父级目录运行 meson setup build 来引导构建环境。之后,就可以使用众所周知的 ninja -C build 命令来构建和安装项目了。 Note 备注 Be aware that by default meson will choose /usr/local as a default location. One would need to add /usr/local/lib/gstreamer-1.0 to GST_PLUGIN_PATH in order to make the new plugin show up in a gstreamer that's been installed from packages. 请注意,默认情况下 meson 会选择 /usr/local 作为默认位置。我们需要在GST_PLUGIN_PATH中添加/usr/local/lib/gstreamer-1.0,才能使新插件显示在从软件包安装的 gstreamer 中。 Note 备注 FIXME: this section is slightly outdated. gst-template is still useful as an example for a minimal plugin build system skeleton. However, for creating elements the tool gst-element-maker from gst-plugins-bad is recommended these days. gst-template 仍可作为最小插件构建系统骨架的范例。不过,现在推荐使用 gst-plugins-bad 中的 gst-element-maker 工具来创建元素。 Examining the Basic Code 检查基本代码 First we will examine the code you would be likely to place in a header file (although since the interface to the code is entirely defined by the plugin system, and doesn't depend on reading a header file, this is not crucial.) 首先,我们将检查您可能会放在头文件中的代码(不过,由于代码的接口完全由插件系统定义,并不依赖于读取头文件,因此这一点并不重要)。 #include <gst/gst.h> /* Definition of structure storing data for this element. */ typedef struct _GstMyFilter { GstElement element; GstPad *sinkpad, *srcpad; gboolean silent; } GstMyFilter; /* Standard definition defining a class for this element. */ typedef struct _GstMyFilterClass { GstElementClass parent_class; } GstMyFilterClass; /* Standard macros for defining types for this element. */ #define GST_TYPE_MY_FILTER (gst_my_filter_get_type()) #define GST_MY_FILTER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MY_FILTER,GstMyFilter)) #define GST_MY_FILTER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MY_FILTER,GstMyFilterClass)) #define GST_IS_MY_FILTER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MY_FILTER)) #define GST_IS_MY_FILTER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MY_FILTER)) /* Standard function returning type information. */ GType gst_my_filter_get_type (void); GST_ELEMENT_REGISTER_DECLARE(my_filter) Using this header file, you can use the following macros to setup the Element basics in your source file so that all functions will be called appropriately: 使用该头文件,您可以使用以下宏来设置源文件中的Element基本内容,这样所有函数都会被适当调用: #include "filter.h" G_DEFINE_TYPE (GstMyFilter, gst_my_filter, GST_TYPE_ELEMENT); GST_ELEMENT_REGISTER_DEFINE(my_filter, "my-filter", GST_RANK_NONE, GST_TYPE_MY_FILTER); The macro GST_ELEMENT_REGISTER_DEFINE in combination with GST_ELEMENT_REGISTER_DECLARE allows to register the element from within the plugin or from any other plugin/application by calling GST_ELEMENT_REGISTER (my_filter). 宏 GST_ELEMENT_REGISTER_DEFINE 与 GST_ELEMENT_REGISTER_DECLARE 结合使用,可以通过调用 GST_ELEMENT_REGISTER (my_filter) 从插件内部或任何其他插件/应用程序注册元素。 Element metadata 元素元数据 The Element metadata provides extra element information. It is configured with gst_element_class_set_metadata or gst_element_class_set_static_metadata which takes the following parameters: 元素元数据提供额外的元素信息。使用 gst_element_class_set_metadata 或gst_element_class_set_static_metadata 对其进行配置,需要以下参数: A long, English, name for the element. 元素的英文长名。 The type of the element, see the docs/additional/design/draft-klass.txt document in the GStreamer core source tree for details and examples. 元素的类型,详情和示例请参阅 GStreamer 核心源代码树中的 docs/additional/design/draft-klass.txt 文档。 A brief description of the purpose of the element. 简要说明元素的用途。 The name of the author of the element, optionally followed by a contact email address in angle brackets. 元素作者的姓名,可选择在其后用角括弧标出联系电子邮件地址。 For example: 例如 gst_element_class_set_static_metadata (klass, "An example plugin", "Example/FirstExample", "Shows the basic structure of a plugin", "your name <your.name@your.isp>"); The element details are registered with the plugin during the _class_init () function, which is part of the GObject system. The _class_init () function should be set for this GObject in the function where you register the type with GLib. 元素细节是在_class_init ()函数中向插件注册的,该函数是 GObject 系统的一部分。应在向 GLib 注册类型的函数中为该 GObject 设置_class_init ()函数。 static void gst_my_filter_class_init (GstMyFilterClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] gst_element_class_set_static_metadata (element_class, "An example plugin", "Example/FirstExample", "Shows the basic structure of a plugin", "your name <your.name@your.isp>"); } GstStaticPadTemplate GstStaticPadTemplate A GstStaticPadTemplate is a description of a pad that the element will (or might) create and use. It contains: GstStaticPadTemplate 是对元素将要(或可能)创建和使用的 pad 的描述。它包含 A short name for the pad. 垫子的简称。 Pad direction. 焊盘方向 Existence property. This indicates whether the pad exists always (an “always” pad), only in some cases (a “sometimes” pad) or only if the application requested such a pad (a “request” pad). 存在属性。这表明该便笺是否始终存在("始终 "便笺),或仅在某些情况下存在("有时 "便笺),或仅在应用程序请求时存在("请求 "便笺)。 Supported types by this element (capabilities). 该元素(能力)支持的类型。 For example: 例如 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); Those pad templates are registered during the _class_init () function with the gst_element_class_add_pad_template (). For this function you need a handle to the GstPadTemplate which you can create from the static pad template with gst_static_pad_template_get (). See below for more details on this. 这些 pad 模板将在 _class_init () 函数中通过 gst_element_class_add_pad_template () 注册。为此,您需要一个指向 GstPadTemplate 的句柄,您可以通过 gst_static_pad_template_get () 从静态 pad 模板创建该句柄。有关详细信息,请参阅下文。 Pads are created from these static templates in the element's _init () function using gst_pad_new_from_static_template (). In order to create a new pad from this template using gst_pad_new_from_static_template (), you will need to declare the pad template as a global variable. More on this subject in Specifying the pads. 在元素的 _init () 函数中,使用 gst_pad_new_from_static_template () 从这些静态模板创建焊盘。要使用 gst_pad_new_from_static_template () 从该模板创建新焊盘,需要将焊盘模板声明为全局变量。有关此主题的更多信息,请参阅指定焊盘。 static GstStaticPadTemplate sink_factory = [..], src_factory = [..]; static void gst_my_filter_class_init (GstMyFilterClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory)); } The last argument in a template is its type or list of supported types. In this example, we use 'ANY', which means that this element will accept all input. In real-life situations, you would set a media type and optionally a set of properties to make sure that only supported input will come in. This representation should be a string that starts with a media type, then a set of comma-separates properties with their supported values. In case of an audio filter that supports raw integer 16-bit audio, mono or stereo at any samplerate, the correct template would look like this: 在本例中,我们使用了 "ANY",这意味着该元素将接受所有输入。在实际应用中,你需要设置一个媒体类型,还可以选择设置一组属性,以确保只有受支持的输入才会被输入。这种表示法应该是一个以媒体类型开头的字符串,然后是一组用逗号分隔的属性及其支持的值。如果音频过滤器支持任何采样率的原始整数 16 位音频、单声道或立体声,正确的模板应该是这样的: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ( "audio/x-raw, " "format = (string) " GST_AUDIO_NE (S16) ", " "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]" ) ); Values surrounded by curly brackets (“{” and “}”) are lists, values surrounded by square brackets (“[” and “]”) are ranges. Multiple sets of types are supported too, and should be separated by a semicolon (“;”). Later, in the chapter on pads, we will see how to use types to know the exact format of a stream: Specifying the pads. 用大括号("{"和"}")包围的值是列表,用方括号("["和"]")包围的值是范围。也支持多组类型,并应以分号(";")分隔。稍后,我们将在 "pads "一章中了解如何使用类型来确定数据流的确切格式:指定焊盘 Constructor Functions 构造函数 Each element has two functions which are used for construction of an element. The _class_init() function, which is used to initialise the class only once (specifying what signals, arguments and virtual functions the class has and setting up global state); and the _init() function, which is used to initialise a specific instance of this type. 每个元素都有两个用于构建元素的函数。_class_init() 函数只用于一次初始化该类(指定该类具有哪些信号、参数和虚拟函数,并设置全局状态);_init() 函数用于初始化该类的一个特定实例。 The plugin_init function 插件初始化函数 Once we have written code defining all the parts of the plugin, we need to write the plugin_init() function. This is a special function, which is called as soon as the plugin is loaded, and should return TRUE or FALSE depending on whether it loaded initialized any dependencies correctly. Also, in this function, any supported element type in the plugin should be registered. 在编写了定义插件所有部分的代码后,我们需要编写 plugin_init() 函数。这是一个特殊函数,在插件加载后立即调用,并根据是否正确初始化了任何依赖关系返回 TRUE 或 FALSE。此外,插件中任何受支持的元素类型都应在此函数中注册。 static gboolean plugin_init (GstPlugin *plugin) { return GST_ELEMENT_REGISTER (my_filter, plugin); } GST_PLUGIN_DEFINE ( GST_VERSION_MAJOR, GST_VERSION_MINOR, my_filter, "My filter plugin", plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/" ) Note that the information returned by the plugin_init() function will be cached in a central registry. For this reason, it is important that the same information is always returned by the function: for example, it must not make element factories available based on runtime conditions. If an element can only work in certain conditions (for example, if the soundcard is not being used by some other process) this must be reflected by the element being unable to enter the READY state if unavailable, rather than the plugin attempting to deny existence of the plugin. 请注意,plugin_init() 函数返回的信息将缓存在中央注册表中。因此,该函数必须始终返回相同的信息:例如,它不得根据运行时的条件使元素工厂可用。如果一个元素只能在特定条件下工作(例如,如果声卡未被其他进程使用),这必须通过元素在不可用时无法进入 READY 状态来反映,而不是由插件试图否认该插件的存在。
admin
2024年5月1日 21:45
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码