- 论坛徽章:
- 0
|
Gstreamer工作原理分析
Guide
Revision
History
Date
Issue
Description
Author
7/03/2008>
First draft
wangfei
目录
TOC \o "1-3" \h \z \u 1. Abstract.. PAGEREF _Toc203462930 \h 3
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330030000000
2. Introduction.. PAGEREF _Toc203462931 \h 3
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330031000000
3. 原理分析.... PAGEREF _Toc203462932 \h 3
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330032000000
3.1 术语介绍.. PAGEREF _Toc203462933 \h 3
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330033000000
3.1.1 元素... PAGEREF _Toc203462934 \h 3
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330034000000
3.1.2 一些特别的元素。... PAGEREF _Toc203462935 \h 3
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330035000000
3.2 插件的工作原理。... PAGEREF _Toc203462936 \h 5
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330036000000
3.3 Gst-launch的工作逻辑... PAGEREF _Toc203462937 \h 7
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330037000000
3.4 动态pipeline的创建原理... PAGEREF _Toc203462938 \h 9
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330038000000
3.5 Decodebin的工作原理... PAGEREF _Toc203462939 \h 10
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900330039000000
3.6 Typefind的实现原理... PAGEREF _Toc203462940 \h 12
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900340030000000
3.7 Setup element. PAGEREF _Toc203462941 \h 12
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900340031000000
3.8 Playbin的工作原理... PAGEREF _Toc203462942 \h 14
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900340032000000
3.9 数据流动... PAGEREF _Toc203462943 \h 16
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900340033000000
3.10 总结... PAGEREF _Toc203462944 \h 20
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900340034000000
4. reference. PAGEREF _Toc203462945 \h 20
08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003200300033003400360032003900340035000000
1.
Abstract
主要讲的是gstreamer的工作原理,包括gst-launch的分析和playbin的分析,以及数据的流动分析。
2.
Introduction
先介绍一些术语,然后介绍了插件的工作原理,后面接着介绍了gst-launch,playbin,decodebin,typefind,数据流动.
3.
原理分析
3.1
术语介绍.
3.1.1
元素
代码里面的类型是GstElement,可以理解为gstreamer里面的基类。
3.1.2 一些特别的元素。
Source:可以理解为源头,也就是数据流的起始地,就像长江的发源地是沱沱河一样。
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image002.gif
Sink:就是这个数据流最终要流向的地方,就像长江最终要流向东海一样。
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image004.gif
Filter:过滤器,就像是筛子一样滤掉我们不感兴趣的东西,流下我们想要的东西,或者从代码上来说就是拦截下数据,对这个数据做一定的修改或者其它动作,当然你什么也不做也是可以的,然后再把数据传出去:
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image006.gif
Pipeline:典型的pipeline是这样的:
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image008.gif
更复杂一点的:
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image010.gif
Bin:有点像pipeline,它们的区别就是pipeline肯定是一个bin,但bin不一定是pipeline,它就像一个盒子,里面放了什么东西你可以不关心。
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image012.gif
Ghostpad:文档上说ghost pad就像linux里面的link文件,我的理解是在一个盒子上开一个口,这样里就可以访问这个盒子了。
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image014.gif
3.2
插件的工作原理。
如下图所示,这个所有的基于插件的程序的工作原理类似,本质上都是通过读取动态库实现的,只需要每个动态库都实现某一个特定的接口就可以了,比如XX_init等,这里就是plugin_init。
里面会有个像注册表一样的数据结构会存储所有的插件的信息。
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image016.gif
3.3
Gst-launch的工作逻辑
它的工作原理就是根据
!号来划分输入的字符串,然后为每个元素构建一个element,最后建立一个pipeline把这些元素加入,最后通过setstate来启动整个数据循环。
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image018.gif
3.4
动态pipeline的创建原理
我们经常需要创建动态的pipeline,因为我们不知道源头是什么格式的,这时候需要这么做:
比如demuxer,
pipeline = gst_pipeline_new
("my_pipeline");
//创建pipeline
source = gst_element_factory_make
("filesrc", "source");
//创建src
g_object_set (source, "location",
argv[1], NULL);
//设置输入文件路径
demux = gst_element_factory_make
("oggdemux", "demuxer");
//创建demux元素
gst_bin_add_many (GST_BIN (pipeline),
source, demux, NULL);
//把这两个元素加入到pipeline里面
gst_element_link_pads (source,
"src", demux, "sink");
//把这两个元素连接起来
g_signal_connect (demux,
"pad-added", G_CALLBACK (cb_new_pad), NULL);
//这里是关键,demux会创建出一个pad,于是发出信号,等待我们设定的函数cb_new_pad.
gst_element_set_state
(GST_ELEMENT (pipeline), GST_STATE_PLAYING);
//启动整个数据流循环
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
//启动gloop事件循环
static void
cb_new_pad (GstElement *element,
GstPad
*pad,
gpointer
data)
{
gchar *name;
name = gst_pad_get_name (pad);
g_print ("A new pad %s was created\n", name);
g_free (name);
/* here, you would setup a new pad link for
the newly created pad */
…...
}
在这里就可以根据不同pad来连接不同的后面的element,比如:
gst_element_link_pads (pad,
"src", fakesink, "sink");
而如何发现源数据的类型则是这样的:
typefind = gst_element_factory_make
("typefind", "typefinder");
g_signal_connect (typefind, "have-type", G_CALLBACK
(cb_typefound), loop);
每当typefine插件查出类型的时候就会发出这个信号。
“Once
a media type has been detected, you can plug an element (e.g. a demuxer or
decoder) to the source pad of the typefind element, and decoding of the media
stream will start right after.”
总结:从上面这些例子可以看出,它的工作过程是这样的:
首先连接能够连接的原素,比如前端src->decodebin,然后后端连接converter->resampler->volume->
audiosink。
通过decodebin的信号,根据源类型创建特定的src
pad,再把这个pad连接到后端(后端可以创建一个ghost pad以方便使用)这样一个pipeline就建好了
3.5
Decodebin的工作原理
3.4节已经用文字介绍了decodebin的工作原理,下面的图是讲它的内部实现的:
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image020.gif
3.6
Typefind的实现原理
这里是讲程序是如何查找出对应文件应该选用什么解码器之类的,可以简单理解为source识别。
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image022.gif
3.7
Setup
element
这里主要讲的是如何把这些播放一个source所需要的element连接起来的:
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image024.gif
3.8
Playbin的工作原理
有了上面几个步骤就可以很容易理解playbin的工作原理,不过细节依然非常的复杂,我只是画了框架图:
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image026.gif
3.9
数据流动
下面讲的是里面最复杂的数据流动的分析,我主要分析了src的流动和sink的流动,因为中间的数据流动太多,比如解码器,filter等等,实在没空,但是我想有这两元素的分析,其它的元素就很容易了:
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image028.gif
file:///C:/DOCUME%7E1/wangfei/LOCALS%7E1/Temp/msohtml1/01/clip_image030.gif
![]()
文件:gstreamer工作原理分析.rar
大小:815KB
下载:
下载
3.10 总结
.时间有限,我只能分析这些框架了,估计看懂这几个图也不容易,
两个关键的函数是change_state,这是一个经常被重载的函数,基本上元素的初始化,状态的改变都会在这里面会被处理, 另外一个非常关键的chaingfunc这个函数是开启数据流动的关键函数,通常src调用chainfunc函数,在这个函数里面会取出peer pad 的chainfunc,然后调用src对应的sink的chainfunc,另外一个让我迷惑了很久的是到sink的数据是如何流动的,最后分析的 结果是它使用了一个环行缓冲,并且使用了线程同步操作来实现生产者消费者 的模式以加快数据的传递,所以数据的最终传递是通过发出p、v操作来实现的,里面先把数据取出来调用memcpy来copy到环行缓冲,然后发出v操作,对应的消费者被唤醒调用sink插件的write操作把数据写到设备里面去,这里面还有几块我没有分析的,比如时间戳的处理,各种元素之间的延迟的协商,以及音频视频之间的同步播放等,这里面涉及很多多线程问题,如果要分析估计得花很多的时间。
4.
reference
[1] http://gstreamer.freedesktop.org/documentation/
补充:
#playbin的工作流程
1,创建source。
2,创建decodebin。
3,为decodebin添加typefind。
4,在向bin添加元素的时候都会发出element-added的信号。
5,向decodebin添加fakesink。
6,把decodebin加入到playbin.
7, 等待typefind元素发出的have-type信号,并调用回调函数,注意这里的信号实际是只包含了caps信息,而后,根据注册表里面的每个factory取出其提供的caps与typefind提供的caps取交集,如果有交集则加入到一个list表中(find_compatibles)。
8,取出list里面的元素来连接,如果找到一个就结束,找到后把这个元素与src元素连接起来,递归的进行这个元素本身的sinkpad的连接,直到收到了no_more_pads的消息。
9,decodebin收到no_more_pads消息后也会发出同样的消息,其余处理逻辑请看文档工作原理》.
注意:close_pad_link
1,通常每一个element在被创建的时候都会添加自己的pad,所以都会发出pad-added的信号。
2,close_link
(GstElement * element, GstDecodeBin * decode_bin)
try_to_link_1
(GstDecodeBin * decode_bin, GstElement * srcelement, GstPad * pad, GList *
factories):这个函数的意思是从这个factories里面取出某个能够连接到pad的元素,和srcelement连接起来,连接起来后还要为这个刚连接起来的元素寻找到它的归属,也就是为它寻找它的sink,调用的函数是close_link,当从这个函数返回的时候,或则它的sinkpad已经被装上或则如果是动态的则已经装上了信号处理器等待sink
pad被动态装上,于是gst_element_set_state
(element, GST_STATE_PAUSED);当这个函数执行完后,所有的需要安装sink的元素都已经好了,这个函数会发出pad-added信号,而这个信号的处理函数是new_pad,在这个函数里面会调用close_pad_link根据pad和caps寻找适合这个pad的sink
pad,所有实际是从这个函数返回后,几乎所有的setup工作都已经over了,可以理解为将要从typefind元素的have-type信号的信号处理函数type_fount返回了,当然之前还会收到no_more_pads的信号执行处理函数no_more_pads,于是decodebin发出了no_more_pads的信号,于是playbin会根据这个信号执行处理函数group_commit.
3,close_pad_link
(GstElement * element, GstPad * pad, GstCaps * caps, GstDecodeBin * decode_bin,
gboolean more):这个函数是根据pad和caps为它寻找到一个可以与之连接的一个链表,或则如果这个caps代表raw数据则创建并添加一个ghostpad到decodebin里面去。
4,find_compatibles
(GstDecodeBin * decode_bin, const GstCaps * caps):这个函数的意思是根据这个caps从注册表里面找出和它有交集的GstElementFactory,并加入到list中返回。
5,close_link
(GstElement * element, GstDecodeBin * decode_bin):这个函数的意思是为element添加sink,如果它的src
pad是动态的,则调用dynamic_add来添加信号处理函数,等待它的动态的pad被添加上,如果不是动态的就调用close_pad_link来从注册表里面选择合适的sink
pad来加入。
TYPE_FIND_REGISTER
(plugin, "video/mp4", GST_RANK_PRIMARY, m4v_type_find,
mp4_exts, M4V_CAPS, NULL, NULL);
行;需要移掉gstdecodebin.c
和gstdecodebin2.c里面的函数find_compatibles里面的to_try
= g_list_reverse (to_try)
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/67984/showart_1341704.html |
|