GStreamer基础教程02 - 基本概念
摘要
在 Gstreamer基础教程01 - Hello World中,我们介绍了如何快速的通过一个字符串创建一个简单的pipeline。为了能够更好的控制pipline中的element,我们需要单独创建element,然后再构造pipeline,下面将介绍GStreamer的一些基本概念并展示pipeline的另一种构造方式。
基本概念
Element
我们知道element是构建GStreamer pipeline的基础,element在框架中的类型为GstElement,所有GStreamer提供的解码器(decoder),编码器(encoder), 分离器(demuxer), 音视频输出设备都是派生自GstElement。
那么element到底是什么呢?
从应用的角度,我们可以将一个element认为是一个功能块,他实现一个特定的功能,比如:数据读取,音频解码,声音输出等。各个功能块之间可以通过某种特定的数据接口(这种接口称为pad,将在后续章节讲述)进行数据传输。每个element有唯一的类型,还有相应的属性,用于控制element的行为。
为了更直观的展现element,我们通常用一个框来表示一个element,在element内部使用小框表示pad。
这些功能块有些可以生成数据,有些只接收数据,有些先接收数据,再生成数据。为了便于区分这些element,我们把他们分为三类:
1. source element
只能生成数据,不能接收数据的element称为source element。例如用于文件读取的filesrc等。
对于source element,我们通常用src pad表示element能产生数据,并将其放在element的右边。source element只有src pad,通过设备、文件、网络等方式读取数据后,通过src pad向pipeline发送数据,开始pipeline的处理流程。如下图:
2. sink element
只能接收数据,不能产生数据的element称为sink element。例如播放声音的alsasink等。
对于sink element,我们通常用sink pad表示element能接收处理数据,并将其放在element的左边。sink element只有sink pad,从sink pad读取数据后,将数据发送到指定设备或位置,结束pipeline的处理流程。如下图:
3. filter-like element
既能接收数据,又能生成数据的element称为filter-like element。例如分离器,解码器,音量控制器等。
对于filter-like element,既包含位于element左边的sink pad,又包含位于element右边的src pad。Element首先从sink pad读取数据,然后对数据进行处理,最后在src pad产生新的数据。如下图:
对于这些的element,可能包含多个src pad,也可能包含多个sink pad,例如mp4的demuxer(qtdemux)会将mp4文件中的音频和视频的分离到audio src pad和video src pad。而mp4的muxer(mp4mux)则相反,会将audio sink pad和video sink pad的数据合并到一个src pad,再经其他element将数据写入文件或发送到网络。demuxer如下图:
连接element
当我们有很多element时,我们需要将他们按数据的传输路径将其串联起来,src pad只能联接到sink pad,这样才能够实现相应的功能。
Bin和Pipeline
我们将element串联起来后就能实现相应的功能,为什么我们还需要bin和pipline呢?我们首先来看看在GStreamer框架中element,bin,pipeline对象之间的继承关系:
GObject
╰──GInitiallyUnowned
╰──GstObject
╰──GstElement
╰──GstBin
╰──GstPipeline
这里bin和pipeline都是一个element,那么bin和pipeline都在element的基础上实现了什么功能,解决了什么问题呢?
我们在创建了element多个element后,我们需要对element进行状态/资源管理,如果每次状态改变时,都需要依次去操作每个element,这样每次编写一个应用都会有大量的重复工作,这时就有了bin。
Bin继承自element后,实现了容器的功能,可以将多个element添加到bin,当操作bin时,bin会将相应的操作转发到内部所有的element中,我们可以将bin认为认为是一个新的逻辑element,由bin来管理其内部element的状态及资源,同事转发其产生的消息。常见的bin有decodebin,autovideoconvert等。
Bin实现了容器的功能,那pipeline又有什么功能呢?
在多媒体应用中,音视频同步是一个基本的功能,需要支持这样的功能,所有的element必须要有一个相同的时钟,这样才能保证各个音频和视频在同一时间输出。pipeline就会为其内部所有的element选择一个相同的时钟,同时还为应用提供了bus系统,用于消息的接收。
Bus
刚才我们提到pipeline会提供一个bus,这个pipeline上所有的element都可以使用这个bus向应用程序发送消息。Bus主要是为了解决多线程之间消息处理的问题。由于GStreamer内部可能会创建多个线程,如果没有bus,应用程序可能同时收到从多个线程的消息,如果应用程序在发送线程中通过回调去处理消息,应用程序有可能阻塞播放线程,造成播放卡顿,死锁等其他问题。为了解决这类问题,GStreamer通常是将多个线程的消息发送到bus系统,由应用程序从bus中取出消息,然后进行处理。Bus在这里扮演了消息队列的角色,通过bus解耦了GStreamer框架和应用程序对消息的处理,降低了应用程序的复杂度。
Element Hello World
在有上面的知识后,我们通过一个示例来看看element是如何创建及使用的。
#include <gst/gst.h> int main (int argc, char *argv[])
{
GstElement *pipeline, *source, *filter, *sink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret; /* Initialize GStreamer */
gst_init (&argc, &argv); /* Create the elements */
source = gst_element_factory_make ("videotestsrc", "source");
filter = gst_element_factory_make ("timeoverlay", "filter");
sink = gst_element_factory_make ("autovideosink", "sink"); /* Create the empty pipeline */
pipeline = gst_pipeline_new ("test-pipeline"); if (!pipeline || !source || !filter || !sink) {
g_printerr ("Not all elements could be created.\n");
return -;
} /* Build the pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, filter, sink, NULL);
if (gst_element_link_many (source, filter, sink, NULL) != TRUE) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline);
return -;
} /* Modify the source's properties */
g_object_set (source, "pattern", , 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 -;
} /* 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 ;
}
编译并运行示例,可以看到弹出的窗口中播放着测试视频,并且还显示着播放时间。
$ gcc basic-tutorial-.c -o basic-tutorial- `pkg-config --cflags --libs gstreamer-1.0`
$ ./basic-tutorial-
源码分析
创建Element
/* Create the elements */
source = gst_element_factory_make ("videotestsrc", "source");
filter = gst_element_factory_make ("timeoverlay", "filter");
sink = gst_element_factory_make ("autovideosink", "sink");
在对GStreamer进行初始化后,我们可以通过gst_element_factory_make创建element。第一个参数是element的类型,可以通过这个字符串,找到对应的类型,从而创建element对象。第二个参数指定了创建element的名字,当我们没有保存创建element的对象指针时,我们可以通过gst_bin_get_by_name从pipeline中取得该element的对象指针。如果第二个参数为NULL,则GStreamer内部会为该element自动生成一个唯一的名字。
我们在当前示例中创建了3个element:videotestsrc,timeoverlay,autovideosink,其作用分别为:
- videotestsrc是一个source element,用于产生视频数据,通常用于调试。
- timeoverlay是一个filter-like element,可以在视频数据中叠加一个时间字符串。
- autovideosink上一个sink element,用于自动选择视频输出设备,创建视频显示窗口,并显示其收到的数据。
创建Pipeline
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("test-pipeline");
Pipeline通过gst_pipeline_new创建,参数为pipeline的名字。
我们知道pipeline会提供播放所必须的时钟以及对消息的处理,所以我们需要把我们创建的element添加到pipeline中。
/* Build the pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, filter, sink, NULL);
if (gst_element_link_many (source, filter, sink, NULL) != TRUE) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline);
return -;
}
从上面的讲解我们知道pipeline是继承自bin,所以所有bin的方法都可以应用于pipeline,需要注意的是,我们需要通过相应的宏(这里是GST_BIN)来将子类转换为父类,宏内部会对其做类型检查。在这里我们使用gst_bin_add_many将多个element加入到pipeline中,这个函数接受任意多个参数,最后以NULL表示参数列表的结束。如果一次只需要加入一个,可以使用gst_bin_add函数。
在将element加入bin后,我们需要将其连接起来才能完成相应的功能,由于有多个element,所以我们这里使用gst_element_link_many,element会根据参数的顺序依次将element连接起来。
需要注意的是,只有被加入到同一个bin的element才能够被连接在一起,所以我们需要在连接前,将所需要的element加入到pipeline/bin中。
至此,我们已经完成了pipeline的创建,test-pipeline可以表示为:
设置element属性
/* Modify the source's properties */
g_object_set (source, "pattern", , NULL);
大部分的element都有自己的属性。有的属性只能被读取,这种属性常用于查询element的状态。有的属性同时支持修改,这种属性常用于控制element的行为。
由于GstElement继承于GObject,同时GObject对象系统提供了 g_object_get()用于读取属性,g_object_set()用于修改属性,g_object_set()支持以NULL结束的属性-值的键值对,所以可以一次修改element的多个属性。
我们这里通过g_object_set()来修改videotestsrc的pattern属性。pattern属性可以控制测试图像的类型,可以尝试将0修改为1,查看输出结果有何不同。
我们可以通过gst-inspect-1.0 videotestsrc命令来查看pattern所支持的所有值。
设置播放状态
/* 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 -;
}
在完成pipeline的创建以及属性的修改后,我们将pipeline的状态设置为PLAYING,这里与上一文章中的示例相同,只增加来错误处理,其他的返回值处理讲在后续章节讲述。
等待播放结束与释放资源
这部分内容与上一文章中的示例相同,这里只增加了消息类型的判断。更多关于消息的内容将在后续章节讲述。
由于videotestsrc会持续输出视频数据,所以我们在这个例子中不会受到EOS消息,只有当我们关闭视频窗口时会收到error消息,发送消息的element名和具体的消息内容会通过终端输出。
总结
在本教程中,我们掌握了:
- GStreamer element,bin,pipeline,bus的基本概念。
- 如何使用gst_element_factory_make ()创建element。
- 如何使用gst_pipeline_new ()创建pipeline。
- 如何使用gst_bin_add_many ()将多个element加入pipeline。
- 如何使用gst_element_link_many ()将多个element连接起来。
在这两篇文章中,我们介绍了pipeline的两种创建方式,下一篇文章我们将介绍GStreamer是如何保证element可以正确的连接在一起。
引用
https://gstreamer.freedesktop.org/documentation/tutorials/basic/concepts.html?gi-language=c
https://gstreamer.freedesktop.org/documentation/application-development/basics/elements.html?gi-language=c
https://gstreamer.freedesktop.org/documentation/application-development/basics/bins.html?gi-language=c
https://gstreamer.freedesktop.org/documentation/gstreamer/gstpipeline.html?gi-language=c
GStreamer基础教程02 - 基本概念的更多相关文章
- 【GStreamer开发】GStreamer基础教程02——GStreamer概念
上一个教程演示了如何自动生成一个pipeline.这次我们打算用一个个element来手动搭建一个pipeline.我们这个教程会演示: 1. 什么是GStreamer的element以及如何建立一个 ...
- 【GStreamer开发】GStreamer基础教程05——集成GUI工具
目标 本教程展示了如何在GStreamer集成一个GUI(比如:GTK+).最基本的原则是GStreamer处理多媒体的播放而GUI处理和用户的交互. 在这个教程里面,我们可以学到: 如何告诉GStr ...
- RabbitMq基础教程之基本概念
RabbitMq基础教程之基本概念 RabbitMQ是一个消息队列,和Kafka以及阿里的ActiveMQ从属性来讲,干的都是一回事.消息队列的主要目的实现消息的生产者和消费者之间的解耦,支持多应用之 ...
- (转)OpenLayers3基础教程——OL3基本概念
http://blog.csdn.net/gisshixisheng/article/details/46756275 OpenLayers3基础教程——OL3基本概念 从本节开始,我会陆陆续续的更新 ...
- GStreamer基础教程09 - Appsrc及Appsink
摘要 在我们前面的文章中,我们的Pipline都是使用GStreamer自带的插件去产生/消费数据.在实际的情况中,我们的数据源可能没有相应的gstreamer插件,但我们又需要将数据发送到GStre ...
- GStreamer基础教程12 - 常用命令工具
摘要 GStreamer提供了不同的命令行工具用于快速的查看信息以及验证Pipeline的是否能够正确运行,在平时的开发过程中,我们也优先使用GStreamer的命令行工具验证,再将Pipeline集 ...
- 【GStreamer开发】GStreamer基础教程13——播放速度
目标 快进,倒放和慢放是trick模式的共同技巧,它们有一个共同点就是它们都修改了播放的速度.本教程会展示如何来获得这些效果和如何进行逐帧的跳跃.主要内容是: 如何来变换播放的速度,变快或者变慢,前进 ...
- 【GStreamer开发】GStreamer基础教程14——常用的element
目标 本教程给出了一系列开发中常用的element.它们包括大杂烩般的eleemnt(比如playbin2)以及一些调试时很有用的element. 简单来说,下面用gst-launch这个工具给出一个 ...
- 【GStreamer开发】GStreamer基础教程10——GStreamer工具
目标 GStreamer提供了一系列方便使用的工具.这篇教程里不牵涉任何代码,但还是会讲一些有用的内容: 如何在命令行下建立一个pipeline--完全不使用C 如何找出一个element的Capab ...
随机推荐
- 无桌面的linux 安装VMWare Tools
1.在vmware虚拟机选项下,选择安装vmware-tools 2.将vmware安装目录下的linux.iso装载到系统中 2.1.选择需安装VMWareTools的虚拟机,右击--可移动设备-- ...
- 【Linux】Vi中的各种命令
Ctrl+u:向文件首翻半屏: Ctrl+d:向文件尾翻半屏: Ctrl+f:向文件尾翻一屏: Ctrl+b:向文件首翻一屏: Esc:从编辑模式切换到命令模式: ZZ:命令模式下保存当前文件所做的修 ...
- 从XMLHttpRequest中获取请求的URL
在编写Ajax通用错误处理程序时,经常需要记录发生错误的XMLHttpRequest的请求URL.但查询文档,并未找到从XMLHttpRequest中获取请求URL的方法. 在javascript - ...
- BSGS-BabyStepGiantStep算法+拓展
学习数学真是一件赛艇的事. BSGS名字听起来非常有意思,力拔山兮气盖世,北上广深,小步大步...算法其实更有意思,它是用来求解一个方程的 A^x ≡ B (mod P) 是不是特别眼熟,有几个式子长 ...
- 【JSP】简单登陆界面
学生登陆查询系统 1 程序的主要功能及特点 实现一个登录界面的基本功能,具体要求: 登录界面login.jsp含有表单,用户能够输入用户名和密码,并提交表单给verify.jsp. Verify.js ...
- MATLAB图形界面设计(上)
参考https://www.cnblogs.com/BlueMountain-HaggenDazs/p/4307777.html 一.图形句柄 1.定义 MATLAB在创建每一个图形对象时,都会给该对 ...
- linux backtrace()详细使用说明,分析Segmentation fault
linux backtrace()详细使用说明,分析Segmentation fault 在此之前,开发eCos应用程序时,经常碰到程序挂掉后,串口打印输出一大串让人看不懂的数据.今天才明白,原来这些 ...
- Git server出现cache大回收分析
实例 git server是一个io密集型的服务,当cache量很大的时候,cache会全部一次释放,导致那么一瞬间,IO read压力很大,因为,用户的大量请求,需要重新从磁盘读到内存,但是这个时刻 ...
- js 中this到底指向哪里?
其实js的this指向很简单.我们记住下面3种情况. this 指向的是浏览器中的window.代码如下: function fn(){ this.name='yangkun'; this.age=2 ...
- 51Nod - 1134 最长递增子序列【动态规划】
给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递增的) 例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10. Input 第1行:1个数N ...