GStreamer应用开发手册
Foreword 前言
安装GStreamer
在linux系统上安装
教程
基础教程
基础教程 1:世界你好!
基础教程 2:GStreamer 概念
基础教程 3:动态管道
Plugin 写作指南
导言
序言
基础
编写插件
构建模板
-
+
首页
基础教程 2:GStreamer 概念
## Goal 目标 The previous tutorial showed how to build a pipeline automatically. Now we are going to build a pipeline manually by instantiating each element and linking them all together. In the process, we will learn: 前面的教程展示了如何自动构建管道。现在,我们将通过实例化每个元素并将它们连接在一起,手动构建一个管道。在此过程中,我们将学习 - What is a GStreamer element and how to create one. - 什么是 GStreamer 元素,如何创建一个。 - How to connect elements to each other. - 如何将元素相互连接。 - How to customize an element's behavior. - 如何自定义元素的行为。 - How to watch the bus for error conditions and extract information from GStreamer messages. - 如何从 GStreamer 信息中观察总线出错情况并提取信息。 ## Manual Hello World 手册 Hello World Copy this code into a text file named basic-tutorial-2.c (or find it in your GStreamer installation). 将此代码复制到名为 basic-tutorial-2.c 的文本文件中(或在 GStreamer 安装文件中找到它)。 basic-tutorial-2.c basic-tutorial-2.c ```c #include <gst/gst.h> #ifdef __APPLE__ #include <TargetConditionals.h> #endif int tutorial_main (int argc, char *argv[]) { GstElement *pipeline, *source, *sink; GstBus *bus; GstMessage *msg; GstStateChangeReturn ret; /* Initialize GStreamer */ gst_init (&argc, &argv); /* Create the elements */ source = gst_element_factory_make ("videotestsrc", "source"); sink = gst_element_factory_make ("autovideosink", "sink"); /* Create the empty pipeline */ pipeline = gst_pipeline_new ("test-pipeline"); if (!pipeline || !source || !sink) { g_printerr ("Not all elements could be created.\n"); return -1; } /* Build the pipeline */ gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); if (gst_element_link (source, sink) != TRUE) { g_printerr ("Elements could not be linked.\n"); gst_object_unref (pipeline); return -1; } /* Modify the source's properties */ g_object_set (source, "pattern", 0, NULL); /* Start playing */ ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) { g_printerr ("Unable to set the pipeline to the playing state.\n"); gst_object_unref (pipeline); return -1; } /* Wait until error or EOS */ bus = gst_element_get_bus (pipeline); msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); /* Parse message */ if (msg != NULL) { GError *err; gchar *debug_info; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &err, &debug_info); g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error (&err); g_free (debug_info); break; case GST_MESSAGE_EOS: g_print ("End-Of-Stream reached.\n"); break; default: /* We should not reach here because we only asked for ERRORs and EOS */ g_printerr ("Unexpected message received.\n"); break; } gst_message_unref (msg); } /* Free resources */ gst_object_unref (bus); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); return 0; } int main (int argc, char *argv[]) { #if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE return gst_macos_main ((GstMainFunc) tutorial_main, argc, argv, NULL); #else return tutorial_main (argc, argv); #endif } ``` ***Information*** *Need help? 需要帮助吗?* *If you need help to compile this code, refer to the Building the tutorials section for your platform: Linux, Mac OS X or Windows, or use this specific command on Linux: 如果在编译代码时需要帮助,请参阅 "构建教程 "部分中有关平台的内容:Linux、Mac OS X 或 Windows,或在 Linux 上使用此特定命令:* `gcc basic-tutorial-2.c -o basic-tutorial-2 'pkg-config --cflags --libs gstreamer-1.0'` *If you need help to run this code, refer to the Running the tutorials section for your platform: Linux, Mac OS X[2] or Windows. 如果您在运行代码时需要帮助,请参阅 "运行教程 "部分,了解您的平台:Linux、Mac OS X[2] 或 Windows。* *This tutorial opens a window and displays a test pattern, without audio 本教程将打开一个窗口并显示测试图案,但不带音频* *Required libraries: 所需的库:gstreamer-1.0. gstreamer-1.0* ## Walkthrough 演练 The elements are GStreamer's basic construction blocks. They process the data as it flows downstream from the source elements (data producers) to the sink elements (data consumers), passing through filter elements. 元素是 GStreamer 的基本构造模块。当数据从源元素(数据生产者)流向下游的汇元素(数据消费者)时,它们通过过滤元素对数据进行处理。 ![](/media/202404/11_1713694326.png) Figure 1. Example pipeline 图 1.管道示例 ### Element creation 创建元素 We will skip GStreamer initialization, since it is the same as the previous tutorial: 我们将跳过 GStreamer 初始化,因为它与上一教程相同: ```c /* Create the elements */ source = gst_element_factory_make ("videotestsrc", "source"); sink = gst_element_factory_make ("autovideosink", "sink"); ``` As seen in this code, new elements can be created with gst_element_factory_make(). The first parameter is the type of element to create (Basic tutorial 14: Handy elements shows a few common types, and Basic tutorial 10: GStreamer tools shows how to obtain the list of all available types). The second parameter is the name we want to give to this particular instance. Naming your elements is useful to retrieve them later if you didn't keep a pointer (and for more meaningful debug output). If you pass NULL for the name, however, GStreamer will provide a unique name for you. 正如本代码所示,新元素可以通过 gst_element_factory_make()创建。第一个参数是要创建的元素类型(Basic tutorial 14: Handyelements 展示了几种常见类型,Basic tutorial 10: GStreamertools 展示了如何获取所有可用类型的列表)。第二个参数是我们要给这个特定实例起的名字。如果没有保存指针,为元素命名对以后检索元素非常有用(而且可以获得更有意义的调试输出)。不过,如果输入 NULL,GStreamer 会为你提供一个唯一的名称。 For this tutorial we create two elements: a videotestsrc and an autovideosink. There are no filter elements. Hence, the pipeline would look like the following: 在本教程中,我们将创建两个元素:一个 videotestsrc 和一个 autovideosink。没有过滤元素。因此,管道看起来如下: ![](/media/202404/2_1713694307.png) Figure 2. Pipeline built in this tutorial 图 2.本教程中构建的管道 videotestsrc is a source element (it produces data), which creates a test video pattern. This element is useful for debugging purposes (and tutorials) and is not usually found in real applications. videotestsrc 是一个源元素(它产生数据),用于创建测试视频模式。该元素用于调试目的(和教程),通常不会出现在实际应用程序中。 autovideosink is a sink element (it consumes data), which displays on a window the images it receives. There exist several video sinks, depending on the operating system, with a varying range of capabilities. autovideosink automatically selects and instantiates the best one, so you do not have to worry with the details, and your code is more platform-independent. autovideosink 是一个sink元素(它消耗数据),可在窗口中显示接收到的图像。根据操作系统的不同,有多种视频 sink,其功能也各不相同。autovideosink会自动选择并实例化最佳的视频sink,因此您不必担心细节问题,您的代码也更不受平台限制。 ### Pipeline creation 创建管道 ```c /* Create the empty pipeline */ pipeline = gst_pipeline_new ("test-pipeline"); ``` All elements in GStreamer must typically be contained inside a pipeline before they can be used, because it takes care of some clocking and messaging functions. We create the pipeline with gst_pipeline_new(). GStreamer 中的所有元素通常都必须包含在管道中才能使用,因为管道需要处理一些时钟和消息传递功能。我们使用 gst_pipeline_new()创建流水线。 ```c /* Build the pipeline */ gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); if (gst_element_link (source, sink) != TRUE) { g_printerr ("Elements could not be linked.\n"); gst_object_unref (pipeline); return -1; } ``` A pipeline is a particular type of bin, which is the element used to contain other elements. Therefore all methods which apply to bins also apply to pipelines. 管道是一种特殊类型的 bin,是用来包含其他元素的元素。因此,所有适用于bin的方法也适用于管道。 In our case, we call gst_bin_add_many() to add the elements to the pipeline (mind the cast). This function accepts a list of elements to be added, ending with NULL. Individual elements can be added with gst_bin_add(). 在我们的例子中,我们调用 gst_bin_add_many(),将元素添加到管道中(注意要进行转换)。该函数接受一个要添加的元素列表,以 NULL 结尾。可以使用 gst_bin_add()添加单个元素。 These elements, however, are not linked with each other yet. For this, we need to use gst_element_link(). Its first parameter is the source, and the second one the destination. The order counts, because links must be established following the data flow (this is, from source elements to sink elements). Keep in mind that only elements residing in the same bin can be linked together, so remember to add them to the pipeline before trying to link them! 不过,这些元素还没有相互链接。为此,我们需要使用 gst_element_link()。它的第一个参数是源,第二个参数是目标。顺序很重要,因为链接必须按照数据流(即从源元素到汇入元素)的顺序建立。请记住,只有位于同一 bin 中的元素才能被链接到一起,因此在尝试链接之前,请记住将它们添加到管道中! ### Properties 属性 GStreamer elements are all a particular kind of GObject, which is the entity offering property facilities. GStreamer 元素都是一种特殊的 GObject,它是提供属性设施的实体。 Most GStreamer elements have customizable properties: named attributes that can be modified to change the element's behavior (writable properties) or inquired to find out about the element's internal state (readable properties). 大多数 GStreamer 元素都有可定制的属性:命名的属性可以通过修改来改变元素的行为(可写属性),或者通过查询来了解元素的内部状态(可读属性)。 Properties are read from with g_object_get() and written to with g_object_set(). 属性用 g_object_get() 读取,用 g_object_set() 写入。 g_object_set() accepts a NULL-terminated list of property-name, property-value pairs, so multiple properties can be changed in one go. g_object_set() 接受以 NULL 结尾的属性名、属性值对列表,因此可以一次性更改多个属性。 This is why the property handling methods have the g_ prefix. 这就是属性处理方法使用 g_ 前缀的原因。 Coming back to what's in the example above, 回到上面的例子、 ```c /* Modify the source's properties */ g_object_set (source, "pattern", 0, NULL); ``` The line of code above changes the “pattern” property of videotestsrc, which controls the type of test video the element outputs. Try different values! 上面的代码行更改了 videotestsrc 的 "pattern "属性,该属性可控制元素输出的测试视频类型。请尝试不同的值! The names and possible values of all the properties an element exposes can be found using the gst-inspect-1.0 tool described in Basic tutorial 10: GStreamer tools or alternatively in the docs for that element (here in the case of videotestsrc). 使用基础教程 10:GStreamer 工具中描述的 gst-inspect-1.0 工具,或者在该元素的文档中(此处以 videotestsrc 为例),可以找到元素暴露的所有属性的名称和可能的值。 ### Error checking 错误检查 At this point, we have the whole pipeline built and setup, and the rest of the tutorial is very similar to the previous one, but we are going to add more error checking: 至此,我们已经构建并设置好了整个管道,教程的其余部分与之前的非常相似,但我们将添加更多的错误检查功能: ```c /* Start playing */ ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) { g_printerr ("Unable to set the pipeline to the playing state.\n"); gst_object_unref (pipeline); return -1; } ``` We call gst_element_set_state(), but this time we check its return value for errors. Changing states is a delicate process and a few more details are given in Basic tutorial 3: Dynamic pipelines. 我们调用 gst_element_set_state(),但这次我们要检查其返回值是否有误。改变状态是一个微妙的过程,更多细节请参见**基础教程 3:动态管道**。 ```c /* Wait until error or EOS */ bus = gst_element_get_bus (pipeline); msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); /* Parse message */ if (msg != NULL) { GError *err; gchar *debug_info; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &err, &debug_info); g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error (&err); g_free (debug_info); break; case GST_MESSAGE_EOS: g_print ("End-Of-Stream reached.\n"); break; default: /* We should not reach here because we only asked for ERRORs and EOS */ g_printerr ("Unexpected message received.\n"); break; } gst_message_unref (msg); } ``` gst_bus_timed_pop_filtered() waits for execution to end and returns with a GstMessage which we previously ignored. We asked gst_bus_timed_pop_filtered() to return when GStreamer encountered either an error condition or an EOS, so we need to check which one happened, and print a message on screen (Your application will probably want to undertake more complex actions). gst_bus_timed_pop_filtered() 等待执行结束,并返回我们之前忽略的 GstMessage。我们要求 gst_bus_timed_pop_filtered() 在 GStreamerenc 遇到错误条件或 EOS 时返回,因此我们需要检查发生了哪种情况,并在屏幕上打印一条信息(您的应用程序可能希望执行更复杂的操作)。 GstMessage is a very versatile structure which can deliver virtually any kind of information. Fortunately, GStreamer provides a series of parsing functions for each kind of message. GstMessage 是一种用途非常广泛的结构,几乎可以传递任何类型的信息。幸运的是,GStreamer 为每种信息都提供了一系列解析函数。 In this case, once we know the message contains an error (by using the GST_MESSAGE_TYPE() macro), we can use gst_message_parse_error() which returns a GLib GError error structure and a string useful for debugging. Examine the code to see how these are used and freed afterward. 在这种情况下,一旦我们知道消息包含错误(通过使用 GST_MESSAGE_TYPE() 宏),我们就可以使用 gst_message_parse_error(),它会返回一个 GLib GError 错误结构和一个用于调试的字符串。请查看代码,了解如何使用和释放它们。 ### The GStreamer bus GStreamer 总线 At this point it is worth introducing the GStreamer bus a bit more formally. It is the object responsible for delivering to the application the GstMessages generated by the elements, in order and to the application thread. This last point is important, because the actual streaming of media is done in another thread than the application. 在此,我们有必要对 GStreamer 总线做一个较为正式的介绍。它是负责将元素生成的 GstMessage 按顺序传送给应用程序和应用程序线程的对象。最后一点非常重要,因为实际的媒体流传输是在应用程序之外的另一个线程中完成的。 Messages can be extracted from the bus synchronously with gst_bus_timed_pop_filtered() and its siblings, or asynchronously, using signals (shown in the next tutorial). Your application should always keep an eye on the bus to be notified of errors and other playback-related issues. 可以使用 gst_bus_timed_pop_filtered() 及其同类工具同步从总线提取信息,也可以使用信号(将在下一教程中介绍)异步提取信息。您的应用程序应始终关注总线,以便在出现错误或其他与回放相关的问题时得到通知。 The rest of the code is the cleanup sequence, which is the same as in Basic tutorial 1: Hello world!. 代码的其余部分是清理序列,与《**基础教程 1:Helloworld!**》相同。 ## Exercise 练习 If you feel like practicing, try this exercise: Add a video filter element in between the source and the sink of this pipeline. Use vertigotv for a nice effect. You will need to create it, add it to the pipeline, and link it with the other elements. 如果你想练习,可以试试这个练习:在该流水线的源和汇之间添加一个视频过滤元件。使用vertigotv 效果更佳。您需要创建它,将其添加到管道中,并将其与其他元素连接起来。 Depending on your platform and available plugins, you might get a “negotiation” error, because the sink does not understand what the filter is producing (more about negotiation in Basic tutorial 6: Media formats and Pad Capabilities). In this case, try to add an element called videoconvert after the filter (this is, build a pipeline of 4 elements. More on videoconvert in Basic tutorial 14: Handy elements). 根据您的平台和可用插件,您可能会收到 "协商 "错误,因为水槽无法理解过滤器生成的内容(有关协商的更多信息,请参阅基础教程 6:媒体格式和 PadCapabilities)。在这种情况下,请尝试在过滤器后添加一个名为 videoconvert 的元素(即构建一个包含 4 个元素的管道)。有关 videoconvert 的更多信息,请参阅 **基础教程 14:Handyelements**)。 ## Conclusion 结论 This tutorial showed: 本教程展示了 - How to create elements with gst_element_factory_make() - 如何使用 gst_element_factory_make() 创建元素 - How to create an empty pipeline with gst_pipeline_new() - 如何使用 gst_pipeline_new()创建空管道 - How to add elements to the pipeline with gst_bin_add_many() - 如何使用 gst_bin_add_many()将元素添加到管道中 - How to link the elements with each other with gst_element_link() - 如何使用 gst_element_link() 链接元素 This concludes the first of the two tutorials devoted to basic GStreamer concepts. The second one comes next. GStreamer 基本概念教程的第一篇到此结束。接下来是第二个教程。 Remember that attached to this page you should find the complete source code of the tutorial and any accessory files needed to build it. 请记住,在本页的附件中,您可以找到教程的完整源代码以及构建教程所需的任何附件文件。 It has been a pleasure having you here, and see you soon! 很高兴你们能来这里,再见!
admin
2024年4月23日 22:41
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码