一、目标
在上一篇文章中,我们介绍了如何使用gst_parse_launch
快速创建一个pipeline。本章中我们将学习播放一个test video的流程:
- 什么是GStreamer Element,以及如何创建。
- 如何连接这些元素。
- 如何自定义元素的属性。
- 如何监视总线的错误情况,以及如何从GStreamer message中提取出其信息。
二、代码
int BT02_ManualHelloWorld(int argc, char** argv) { GstElement *pipeline, *source, *sink; GstBus *bus; GstMessage *msg; GstStateChangeReturn ret; int retval = 0; /* 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("No Element Created.\n"); retval = -1; goto out_return; } /* Build the pipeline */ gst_bin_add_many(GST_BIN(pipeline), source, sink, NULL); if (gst_element_link(source, sink) != TRUE) { g_printerr("No Element Link.\n"); retval = -2; goto out_unref; } /* 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"); retval = -3; goto out_unref; } /* 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: g_printerr("Unexpected message received.\n"); break; } gst_object_unref(msg); } gst_object_unref(bus); gst_element_set_state(pipeline, GST_STATE_NULL); out_unref: gst_object_unref(pipeline); out_return: return retval; }
三、解释
source -> filter -> sink
Elements是GStreamer最基本的构造块。它们处理从source(data producers)藉由filter到sink(data consumers)的数据流。
3.1 创建元素
source = gst_element_factory_make("videotestsrc", "source"); sink = gst_element_factory_make("autovideosink", "sink");
通过上述代码我们已知,元素可被gst_element_factory_make()
创建。其第一个参数,指创建的元素的类型(参考BT14,和BT10)。第二个参数是该Element实例化的名字。如果没有保留对应元素的指针,那么使用命名将有助于debug一类的管理。如果传递NULL作为参数,则GStreamer将自动为其命名。
在本例中,我们创建了两个元素,videotestsrc
和autovideosink
。这里没有filter元素,因此整个管线看起来是这样的:
source(videotestsrc) -> sink(autovideosink)
- videotestsrc创建一个测试视频。该视频只在测试中使用,实际项目中并不会用到。
- autovideosink在窗口上显示它所接收到的图像。该命令自动选择适合的sink实例。
3.2 创建管线
所有的元素需要在管线中才能被使用,管线负责传递元素直接的信息和时钟。我们使用pipeline = gst_pipeline_new()
来创建管线。
管线是一种特殊类型的元素,它是一个存放其他元素的容器。在我们创建一条完整的管线时,我们需要先向其中添加元素(gst_bin_add),然后再连接它们(gst_element_link),但是需要注意,在连接时有些元素的pad并不会自动实现。在上面的例子中:
gst_bin_add_many(GST_BIN(pipeline), source, sink, NULL); gst_element_link(source, sink) != TRUE
同时,连接需要注意其顺序。
3.3 特性
GStreamer元素都是特殊的GObject,它是提供property facilities的实体。大多数的元素都有可自定义的属性:可以修改以更改元素的行为(可写属性)或查询以了解元素的内部状态(可读属性)的命名属性。
属性可以通过g_object_get()
获取;通过g_object_set()
设置。g_object_set()
接受以NULL结尾的属性名、属性值对列表,因此可以一次更改多个属性。
g_object_set(source, "pattern", 0 , NULL);
这里通过设置videotestsrc
的pattern
属性,来改变测试视频的输出。
3.4 错误检查
此时我们已经完成了整个管线的建构,下面是一些错误检查。
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"); retval = -3; goto out_unref; }
在上一节教程中,我们同样试了了gst_element_set_state
。但是这次我们需要检查其返回值,以确定语句是否正常运行。关于“更改状态”的更多内容将在下一篇文章中讨论。
/* 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: g_printerr("Unexpected message received.\n"); break; } gst_object_unref(msg); }
gst_bus_timed_pop_filtered
等待执行结束并返回我们之前忽略的GstMessage。我们要求gst_bus_timed_pop_filtered
在遇到错误或者到达EOS(End of Stream)时返回一条GstMessage,因此我们检查这个返回值是错误还是EOS。
GstMessage是一种非常通用的结构,它几乎可以传递所有类型的消息。并且GStreamer为其提供了一系列解析函数。
- 我们首先可以通过
GST_MESSAGE_TYPE()
来解析消息的类型。 - 如果遇到错误,则可以使用
gst_message_parse_error
提取消息到GError
中。
3.5 Gst总线
在这一点上,值得更正式地介绍一下GStreamer总线。它是负责将元素生成的GstMessages按顺序交付给应用程序并交付给应用程序线程的对象。最后一点很重要,因为实际的媒体流是在应用程序之外的另一个线程中完成的。
可以使用gst_bus_timed_pop_filtered()及其同级从总线同步提取消息,或者使用信号异步提取消息(在下一教程中显示)。 您的应用程序应始终关注总线,以便收到有关错误和其他播放相关问题的通知。
gst_object_unref(bus); gst_element_set_state(pipeline, GST_STATE_NULL); out_unref: gst_object_unref(pipeline); out_return: return retval;
余下的这部分代码则是清理。
四、总结
本篇文章描述了:
- 如何使用
gst_element_factory_make
来创建元素。 - 如何使用
gst_pipeline_new
来创建管线。 - 如何使用
gst_bin_add_many
来为管线添加元素。 - 如何使用
gst_element_link
来连接管线中元素。
Comments | NOTHING