Board logo

标题: 用 GStreamer 简化 Linux 多媒体开发--实现 [打印本页]

作者: look_w    时间: 2018-5-9 19:47     标题: 用 GStreamer 简化 Linux 多媒体开发--实现

二、元件连接在引入了元件和衬垫的概念之后,GStreamer对多媒体数据的处理过程就变得非常清晰了:通过将不同元件的衬垫依次连接起来构成一条媒体处理管道,使数据在流经管道的过程能够被各个元件正常处理,最终实现特定的多媒体功能。
图1就描述了一条很简单的管道,它由三个基本元件构成:数据源元件只负责产生数据,它的输出衬垫与过滤器元件的输入衬垫相连;过滤器元件负责从自己的输入衬垫中获取数据,并在经过特定的处理之后,将结果通过输出衬垫传给与之相连的接收器元件;接收器元件只负责接收数据,它的输入衬垫与过滤器元件的输出衬垫相连,负责对最终结果进行相应的处理。
GStreamer框架中的元件是通过各自的衬垫连接起来的,下面的代码示范了如何将两个元件通过衬垫连接起来,以及如何在需要的时候断开它们之间的连接:
1
2
3
4
5
6
7
GstPad *srcpad, *sinkpad;
srcpad = gst_element_get_pad (element1, "src");
sinpad = gst_element_get_pad (element2, "sink");
// 连接
gst_pad_link (srcpad, sinkpad);
// 断开
gst_pad_unlink (srcpad, sinkpad);




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




三、元件状态当GStreamer框架中的元件通过管道连接好之后,它们就开始了各自的处理流程,期间一般会经历多次状态切换,其中每个元件在特定时刻将处于如下四种状态之一:
所有的元件都从NULL状态开始,依次经历NULL、READY、PAUSED、PLAYING等状态间的转换。元件当前所处的状态可以通过调用gst_element_set_state()函数进行切换:
1
2
3
GstElement *bin;
/* 创建元件,并将其连接成箱柜bin */
gst_element_set_state (bin, GST_STATE_PLAYING);




默认情况下,管道及其包含的所有元件在创建之后将处于NULL状态,此时它们不会进行任何操作。当管道使用完毕之后,不要忘记重新将管道的状态切换回NULL状态,让其中包含的所有元件能够有机会释放它们正在占用的资源。
管道真正的处理流程是从第一次将其切换到READY状态时开始的,此时管道及其包含的所有元件将做好相应的初始化工作,来为即将执行的数据处理过程做好准备。对于一个典型的元件来讲,处于READY状态时需要执行的操作包括打开媒体文件和音频设备等,或者试图与位于远端的媒体服务器建立起连接。
处于READY状态的管道一旦切换到PLAYING状态,需要处理的多媒体数据就开始在整个管道中流动,并依次被管道中包含的各个元件进行处理,从而最终实现管道预先定义好的某种多媒体功能。GStreamer框架也允许将管道直接从NULL状态切换到PLAYING状态,而不必经过中间的READY状态。
正处于播放状态的管道能够随时切换到PAUSED状态,暂时停止管道中所有数据的流动,并能够在需要的时候再次切换回PLAYING状态。如果需要插入或者更改管道中的某个元件,必须先将其切换到PAUSED或者NULL状态,元件在处于PAUSED状态时并不会释放其占用的资源。
四、实现MP3播放器在理解了一些基本概念和处理流程之后,下面来看看如何利用GStreamer框架提供的组件,来实现一个简单的MP3播放器。在图1中描述的结构能够很容易地映射成MP3播放器,其中数据源元件负责从磁盘上读取数据,过滤器元件负责对数据进行解码,而接受器元件则负责将解码后的数据写入声卡。
与其它众多GNOME项目一样,GStreamer也是用C语言实现的。如果想要在程序中应用GStreamer提供的各种功能,首先必须在主函数中调用gst_init()来完成相应的初始化工作,以便将用户从命令行输入的参数传递给GStreamer函数库。一个典型的GStreamer应用程序的初始化如下所示:
1
2
3
4
5
6
#include <gst/gst.h>
int main (int argc, char *argv[])
{
  gst_init (&argc, &argv);
  /* ... */
}




接下去需要创建三个元件并连接成管道,由于所有GStreamer元件都具有相同的基类GstElement,因此能够采用如下方式进行定义:
1
GstElement *pipeline, *filesrc, *decoder, *audiosink;




管道在GStreamer框架中是用来容纳和管理元件的,下面的代码将创建一条名为pipeline的新管道:
1
2
/* 创建用来容纳元件的新管道 */
pipeline = gst_pipeline_new ("pipeline");




数据源元件负责从磁盘文件中读取数据,它具有名为location的属性,用来指明文件在磁盘上的位置。使用标准的GObject属性机制可以为元件设置相应的属性:
1
2
3
/* 创建数据源元件 */
filesrc = gst_element_factory_make ("filesrc", "disk_source");
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);




过滤器元件负责完成对MP3格式的数据进行解码,最简单的办法是安装mad这一插件,借助它来完成相应的解码工作:
1
2
/* 创建过滤器元件 */
decoder = gst_element_factory_make ("mad", "decoder");




接收器元件负责将解码后的数据利用声卡播放出来:
1
2
/* 创建接收器元件 */
audiosink = gst_element_factory_make ("audiosink", "play_audio");




已经创建好的三个元件需要全部添加到管道中,并按顺序连接起来:
1
2
3
4
/* 添加元件到管道中 */
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
/* 通过衬垫连接元件 */
gst_element_link_many (filesrc, decoder, audiosink, NULL);




所有准备工作都做好之后,就可以通过将管道的状态切换到PLAYING状态,来启动整个管道的数据处理流程:
1
2
/* 启动管道 */
gst_element_set_state (pipeline, GST_STATE_PLAYING);




由于没有用到线程,因此必须通过不断调用gst_bin_iterate()函数的办法,来判断管道的处理过程会在何时结束:
1
while (gst_bin_iterate (GST_BIN (pipeline)));




只要管道内还会继续有新的事件产生,gst_bin_iterate()函数就会一直返回TRUE,只有当整个处理过程都结束的时候,该函数才会返回FALSE,此时就该终止管道并释放占用的资源了:
1
2
3
4
/* 终止管道 */
gst_element_set_state (pipeline, GST_STATE_NULL);
/* 释放资源 */
gst_object_unref (GST_OBJECT (pipeline));




用GStreamer实现的MP3播放器的源代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <gst/gst.h>
int main (int argc, char *argv[])
{
    GstElement *pipeline, *filesrc, *decoder, *audiosink;
    gst_init(&argc, &argv);
    if (argc != 2) {
        g_print ("usage: %s <mp3 filename>\n", argv[0]);
        exit (-1);
    }
    /* 创建一条新的管道 */
    pipeline = gst_pipeline_new ("pipeline");
    /* 生成用于读取硬盘数据的元件 */
    filesrc = gst_element_factory_make ("filesrc", "disk_source");
    g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
    /* 创建解码器元件 */
    decoder = gst_element_factory_make ("mad", "decoder");
    /* 创建音频回放元件 */
    audiosink = gst_element_factory_make ("osssink", "play_audio");
    /* 将生成的元件添加到管道中 */
    gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
    /* 连接各个元件 */
    gst_element_link_many (filesrc, decoder, audiosink, NULL);
    /* 开始播放 */
    gst_element_set_state (pipeline, GST_STATE_PLAYING);
    while (gst_bin_iterate (GST_BIN (pipeline)));
    /* 停止管道处理流程 */
    gst_element_set_state (pipeline, GST_STATE_NULL);
    /* 释放占用的资源 */
    gst_object_unref (GST_OBJECT (pipeline));
    exit (0);
    }




五、小结随着 GNOME 桌面环境的不断普及,GStreamer 作为一个强大的多媒体应用开发框架,已经开始受到越来越多人的关注。Gstreamer在设计时采用了非常灵活的体系结构,并且提供了许多预定义的媒体处理模块,因此能够极大简化在Linux下开发多媒体应用的难度。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0