快捷搜索:

用 GStreamer 简化 Linux 多媒体开发

一、基础观点

GStreamer 作为 GNOME 桌面情况保举的流媒体利用框架,采纳了基于插件(plugin)和管道(pipeline)的体系布局,框架中的所有的功能模块都被实现成可以插拔的组件(component), 并且在必要的时刻能够很方便地安装到随意率性一个管道上,因为所有插件都经由过程管道机制进行统一的数据互换,是以很轻易使用已有的各类插件“组装”出一个功能完善的多媒体利用法度榜样。

1.1 元件处置惩罚

对付必要利用 GStreamer 框架的法度榜样员来讲,GstElement 是一个必须理解的观点,由于它是组成管道的基础构件,也是框架中所有可用组件的根基,这也难怪 GStreamer 框架中的大年夜部分函数都邑涉及到对 GstElement 工具的操作。从 GStreamer 自身的不雅点来看,GstElement 可以描述为一个具有特定属性的黑盒子,它经由过程连接点(link point)与外界进行交互,向框架中的另外部分表征自己的特点或者功能。

按照各自功能上的差异,GStreamer 又将 GstElement 细分成如下几类:

•Source Element 数据源元件 只有输出端,它仅能用来孕育发生供管道破费的数据,而不能对数据做任何处置惩罚。一个范例的数据源元件的例子是音频捕获单元,它认真从声卡读取原始的音频数据,然后作为数据源供给给其它模块应用。

•Filter Element 过滤器元件 既有输入端又有输出端,它从输入端得到响应的数据,并在颠末特殊处置惩罚之后通报给输出端。一个范例的过滤器元件的例子是音频编码单元,它首先从外界得到音频数据,然后根据特定的压缩算法对其进行编码,着末再将编码后的结果供给给其它模块应用。

•Sink Element 接管器元件 只有输入端,它仅具有破费数据的能力,是整条媒体管道的终端。一个范例的接管器元件的例子是音频回放单元,它认真将接管到的数据写到声卡上,平日这也是音频处置惩罚历程中的着末一个环节。

图1将有助于你更好地舆解数据源元件、过滤器元件和接管器元件三者的差别,同时也不丢脸出它们是若何互相共同形成管道的:

图1

必要留意的是,过滤器元件的详细形式是异常机动的,GStreamer并没有严格规定输入端和输出真个数目,事实上它们都可所以一个或者多个。图2是一个AVI分离器的基础布局,它能够将输入数据分离成零丁的音频信息和视频信息,用于实现该功能的过滤器元件很显着只具有一个输入端,但却必要有两个输出端。

图2

要想在利用法度榜样中创建GstElement工具,独一的法子是借助于工厂工具GstElementFactory。因为GStreamer框架供给了多种类型的GstElement工具,是以对应地供给了多种类型的GstElementFactory工具,它们是经由过程特定的工厂名称来进行区分的。例如,下面的代码经由过程gst_element_factory_find()函数得到了一个名为mad的工厂工具,它之后可以用来创建与之对应的MP3解码器元件:

GstElementFactory *factory;

factory = gst_element_factory_find ("mad");

成功得到工厂工具之后,接下来就可以经由过程gst_element_factory_create()函数来创建特定的GstElement工具了,该函数在调用时有两个参数,分手是必要用到的工厂工具,以及即将创建的元件名称。元件名称可以用查询的法子得到,也可以经由过程传入空指针(NULL)来天生工厂工具的默认元件。下面的代码示范了若何使用已经得到的工厂工具,来创建名为decoder的MP3解码器元件:

与元件一样,衬垫的名称也能够动态设置或者读取,这是经由过程调用gst_pad_get_name ()和gst_pad_set_name()函数来完成的。所有元件的衬垫都可以细分成输入衬垫和输出衬垫两种,此中输入衬垫只能接管数据但不能孕育发生数据,而输出衬垫则恰恰相反,只能孕育发生数据但不能接管数据,使用函数gst_pad_get_direction()可以得到指定衬垫的类型。GStreamer框架中的所有衬垫都一定依赖于某个元件之上,调用gst_pad_get_parent()可以得到指定衬垫所属的元件,该函数的返回值是一个指向GstElement的指针。 衬垫从某种程度上可以当作是元件的代言人,由于它要认真向外界描述该元件所具有的能力。GStreamer框架供给了统一的机制来让衬垫描述元件所具有的能力(capability),这是借助数据布局_GstCaps来实现的:

struct _GstCaps {

gchar *name; /* the name of this caps */

guint16 id; /* type id (major type) */

guint refcount; /* caps are refcounted */

GstProps *properties; /* properties for this capability */

GstCaps *next; /* caps can be chained together */

};

以下是对mad元件的能力描述,不丢脸出该元件中实际包孕sink和src两个衬垫,并且每个衬垫都带有特定的功能信息。名为sink的衬垫是mad元件的输入端,它能够吸收MIME类型为audio/mp3的媒体数据,此外还具有layer、bitrate和framed三种属性。名为src的衬垫是mad元件的输出端,它认真孕育发生MIME类型为audio/raw媒体数据,此外还具有format、depth、rate和channels等多种属性。

Pads:

SINK template: ’sink’

Availability: Always

Capabilities:

’mad_sink’:

MIME type: ’audio/mp3’:

SRC template: ’src’

Availability: Always

Capabilities:

’mad_src’:

MIME type: ’audio/raw’:

format: String: int

endianness: Integer: 1234

width: Integer: 16

depth: Integer: 16

channels: Integer range: 1 - 2

law: Integer: 0

signed: Boolean: TRUE

rate: Integer range: 11025 - 48000

GstElement *thread, *pipeline;

// 创建线程工具,同时为其指定独一的名称。

thread = gst_element_factory_make ("thread", NULL);

// 根据给出的名称,创建一个特定的管道工具。

pipeline = gst_pipeline_new ("pipeline_name");

箱柜成功创建之后,就可以调用gst_bin_add()函数将已经存在的元件添加到此中来了:

GstElement *element;

GstElement *bin;

bin = gst_bin_new ("bin_name");

element = gst_element_factory_make ("mpg123", "decoder");

gst_bin_add (GST_BIN (bin), element);

而要从箱柜中找到特定的元件也很轻易,可以借助gst_bin_get_by_name()函数实现:

GstElement *element;

element = gst_bin_get_by_name (GST_BIN (bin), "decoder");

因为GStreamer框架中的一个箱柜能够添加到另一个箱柜之中,是以有可能会呈现箱柜嵌套的环境,gst_bin_get_by_name()函数在查找元件时会对嵌套的箱柜作递归查找。元件有添加到箱柜之中今后,在必要的时刻还可以从中移出,这是经由过程调用gst_bin_remove()函数来完成的:

GstElement *element;

gst_bin_remove (GST_BIN (bin), element);

假如仔细钻研一下图3中描述的箱柜,会发明它没有属于自己的输入衬垫和输出衬垫,是以显然是无法作为一个逻辑整体与其它元件交互的。为了办理这一问题,GStreamer引入了精灵衬垫(ghost pad)的观点,它是从箱柜里面所有元件的衬垫中推举出来的,平日来讲会同时选出输入衬垫和输出衬垫,如图4所示:

图4

假如必要建立起连接的元件都只有一个输入衬垫和一个输出衬垫,那么更简单的做法是调用gst_element_link()函数直接在它们之间建立起连接,或者调用gst_element_unlink()函数断开它们之间的连接:

// 连接

gst_element_link (element1, element2);

// 断开

gst_element_unlink (element1, element2);

三、元件状态

当GStreamer框架中的元件经由过程管道连接好之后,它们就开始了各自的处置惩罚流程,时代一样平常会经历多次状态切换,此中每个元件在特准时候将处于如下四种状态之一:

•NULL 这是所有元件的默认状态,注解它刚刚创建,还没有开始做任何工作。

•READY 注解元件已经做好筹备,随时可以开始处置惩罚流程。

•PAUSED 注解元件因某种缘故原由暂时竣事处置惩罚数据。

•PLAYING 注解元件正在进行数据处置惩罚。

所有的元件都从NULL状态开始,依次经历NULL、READY、PAUSED、PLAYING等状态间的转换。元件当前所处的状态可以经由过程调用gst_element_set_state()函数进行切换:

GstElement *bin;

/* 创建元件,并将其连接成箱柜bin */

gst_element_set_state (bin, GST_STATE_PLAYING);

默认环境下,管道及其包孕的所有元件在创建之后将处于NULL状态,此时它们不会进行任何操作。当管道应用完毕之后,不要忘怀从新将管道的状态切换回NULL状态,让此中包孕的所有元件能够有时机开释它们正在占用的资本。

管道真正的处置惩罚流程是从第一次将其切换到READY状态时开始的,此时管道及其包孕的所有元件将做好响应的初始化事情,来为即将履行的数据处置惩罚历程做好筹备。对付一个范例的元件来讲,处于READY状态时必要履行的操作包括打开媒体文件和音频设备等,或者试图与位于远真个媒体办事器建立起连接。

/* 创建用来容纳元件的新管道 */

pipeline = gst_pipeline_new ("pipeline");

数据源元件认真从磁盘文件中读取数据,它具着名为location的属性,用来指明文件在磁盘上的位置。应用标准的GObject属性机制可以为元件设置响应的属性:

/* 创建数据源元件 */

filesrc = gst_element_factory_make ("filesrc", "disk_source");

g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);

过滤器元件认真完成对MP3款式的数据进行解码,最简单的法子是安装mad这一插件,借助它来完成响应的解码事情:

/* 创建过滤器元件 */

decoder = gst_element_factory_make ("mad", "decoder");

接管器元件认真将解码后的数据使用声卡播放出来:

/* 创建接管器元件 */

audiosink = gst_element_factory_make ("audiosink", "play_audio");

已经创建好的三个元件必要整个添加到管道中,并按顺序连接起来:

/* 添加元件到管道中 */

gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);

/* 经由过程衬垫连接元件 */

gst_element_link_many (filesrc, decoder, audiosink, NULL);

所有筹备事情都做好之后,就可以经由过程将管道的状态切换到PLAYING状态,来启动全部管道的数据处置惩罚流程:

/* 启动管道 */

gst_element_set_state (pipeline, GST_STATE_PLAYING);

因为没有用到线程,是以必须经由过程赓续调用gst_bin_iterate()函数的法子,来判断管道的处置惩罚历程会在何时停止:

您可能还会对下面的文章感兴趣: