Gstreamer基础概念
ELement
一个element实现一个功能(读取文件,解码,输出等),程序需要创建多个element,并按顺序将其串连起来,构成一个完整的pipeline。
Pad
Pad是一个element的输入/输出接口,分为src pad(生产数据)和sink pad(消费数据)两种。两个element必须通过pad才能连接起来。当element支持多种数据处理能力时,我们可以通过Cap来指定数据类型。
gst-launch-1.0 videotestsrc ! "video/x-raw,width=1280,height=720" ! autovideosink
Bin和Pipeline
Bin是一个容器,用于管理多个element,改变bin的状态时,bin会自动去修改所包含的element的状态,也会转发所收到的消息。如果没有bin,我们需要依次操作我们所使用的element。通过bin降低了应用的复杂度。
Pipeline继承自bin,为程序提供一个bus用于传输消息,并且对所有子element进行同步。当将pipeline的状态设置为PLAYING时,pipeline会在一个/多个新的线程中通过element处理数据。
gst-launch-1.0 filesrc location=sintel_trailer-480p.ogv ! oggdemux name=demux ! queue ! vorbisdec ! autoaudiosink demux. ! queue ! theoradec ! videoconvert ! autovideosink
pipeline由8个element组成,每个element实现各自的功能。
filesrc: 读取文件
oggdemux: 解析文件 提取audio video
queue: 缓存数据
vorbisdec: 解析audio
autoaudiosink: 自动选择音频设备输出
theoradec: 解析video
videoconvert: 转换video数据格式
autovideosink: 自动选择显示设备输出
//只有视频
gst-launch-1.0 filesrc location=sintel_trailer-480p.ogv ! oggdemux name=demux ! queue ! theoradec ! videoconvert ! autovideosink
//只有音频
gst-launch-1.0 filesrc location=sintel_trailer-480p.ogv ! oggdemux name=demux ! queue ! vorbisdec ! autoaudiosink
知识点
1.source element
只能生成数据,不能接收数据的element。如用于文件读取的filesrc等。
对于source element,我们通常用src pad表示element能产生数据,并将其放在element的右边。source element只有src pad,通过设备、文件、网络等方式读取数据后,通过src pad向pipeline发送数据,开始pipeline的处理流程。
2.sink element
只能接收数据,不能产生数据的element。例如播放声音的alsasink等。
对于sink element,我们通常用sink pad表示element能接收处理数据,并将其放在element的左边。sink element只有sink pad,从sink pad读取数据后,将数据发送到指定设备或位置,结束pipeline的处理流程。
3.filter-like element
既能接收数据,又能生成数据的element。例如分离器,解码器,音量控制器等。
对于filter-like element,既包含位于element左边的sink pad,又包含位于element右边的src pad。Element首先从sink pad读取数据,然后对数据进行处理,最后在src pad产生新的数据。
源码分析
创建Element
/* Create the elements */
source = gst_element_factory_make ("videotestsrc", "source");
sink = gst_element_factory_make ("autovideosink", "sink");
对GStreamer初始化后,可以通过gst_element_factory_make创建element。第一个参数element的类型,第二个参数是这个实例中参数的名字。如果第二个参数为NULL,则GStreamer内部会为该element自动生成一个唯一的名字。
videotestsrc: 是一个source element,产生视频数据,用于调试(教程),在实际应用中基本不用。
autovideosink: 是一个sink element, 用于自动选择视频输出设备,创建视频显示窗口,并显示其收到的数据。
创建Pipeline
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("test-pipeline");
我们通过 gst_pipeline_new创建pipeline,参数为管道的名字。
我们知道pipeline会提供播放所必须的时钟以及对消息的处理,所以我们需要把我们创建的element添加到pipeline中。
/* 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;
}
从上面的讲解我们知道pipeline是继承自bin,所以所有bin的方法都可以应用于pipeline,需要注意的是,我们需要通过相应的宏(这里是GST_BIN)来将子类转换为父类,宏内部会对其做类型检查。在这里我们使用gst_bin_add_many将多个element加入到pipeline中,这个函数接受任意多个参数,最后以NULL表示参数列表的结束。如果一次只需要加入一个,可以使用gst_bin_add函数。
我们使用gst_element_link将这些element链接起来。需要注意的是,只有被加入到同一个bin的element才能够被连接在一起,所以我们需要在连接前,将所需要的element加入到pipeline/bin中。
设置属性
/* Modify the source's properties */
g_object_set (source, "pattern", 0, 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 -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);
}
组件状态
一个组件被创建后,不会执行任何操作。所以需要改变组件的状态,使其能做某些事情。组件有四种状态:
GST_STATE_NULL:默认状态,会回收所有被该组件占用的资源。
GST_STATE_READY:准备状态,会得到所有所需的全局资源,这些资源将通过该组件的数据流所使用。如打开设备,分配缓存等,但这种状态下,数据流未开始被处理,数据流的位置信息应自动置0.如数据流打开过,应被关闭。其位置信息、特性信息被重置。
GST_STATE_PAUSED: 开始对流进行处理,但暂停了处理。时钟禁止运行。
GST_STATE_PLAYING: 除了运行时钟外,与PAUSED相同。