Gstreamer工作原理分析_第1页
Gstreamer工作原理分析_第2页
Gstreamer工作原理分析_第3页
Gstreamer工作原理分析_第4页
Gstreamer工作原理分析_第5页
免费预览已结束,剩余17页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Gstreamer 工作原理分析GuideTechHowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:RevisionHistoryDateIssueDescriptionAuthorFirstdraftwangfei目录1.ABSTRACT32.INTRODUCTION33.原理分析 33.1术语介绍 33.1.1元素 33.1.2一些特别的元素。33.2插件的工作原理。53.3GST-LAUNCH的工作逻辑 73.4动态PIPELINE的创建原理 93.5DECODEBIN工作原理 10

2、3.6TYPEFIND勺实现原理 123.7SETUPELEMENT123.8PLAYBM勺工作原理 143.9数据流动 163.10总结 204.REFERENCE20HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:Abstract主要讲的是 gstreamerfl 勺工作原理,包括 gst-launch 的分析和 playbin 的分析,以及数据的流动分析。Introduction先介绍一些术语,然后介绍了插件的工作原理,后面接着介绍了gst-launch,playbin,decod

3、ebin,typefind 数据流动.原理分析术语介绍.漀甀爀椀攀爀一攀眀 元素代码里面的类型是 GstElement,可以理解为 gstreameifi 面的基类。漀甀爀椀攀爀一攀眀 一些特别的元素。Source:可以理解为源头,也就是数据流的起始地,就像长江的发源地是沱沱河一样。ntsrcSink:就是这个数据流最终要流向的地方,就像长江最终要流向东海一样。sinlt_elErrient6InkFilter:过滤器, 就像是筛子一样滤掉我们不感兴趣的东西, 流下我们想要的东西, 或者从代码上来说就是拦截下数据,对这个数据做一定的修改或者其它动作,当然你什么也不做也是可以的,然后再把数据传出

4、去:flter6InksrcPipeline:典型的 pipeline 是这样的:HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate: Documentidentifierpipeline更复杂一点的:pip5liieaniic/x-raw-lai:audio/x-mw-jnrBin:有点像 pipeline,它们的区别就是 pipeline 肯定是一个 bin,但 bin 不一定是 pipeline,它就像一个盒子,里面放了什么东西你可以不关心。binGhostpad:文档上说 ghost

5、pad 就像 linux 里面的 link 文件, 我的理解是在一个盒子上开一个口, 这样里就可以访问这个盒子了。decodersinkplay_3udosink.gGOUnsocgdamuxerverbiscfecocbrsinksrc.sinkaudiooonvortersinkscIlaudiooutputsink7即即pli凶凶tknA明明IaucHc/n-Yorbisajio/K-jaw一一fl口出口出ai;di:,比一比一jaw-Ut隆“K7CJtkelEmentlHowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesign

6、DocumentsIssueDate:Documentidentifierbin插件的工作原理。如下图所示,这个所有的基于插件的程序的工作原理类似,本质上都是通过读取动态库实现的,只需要每个动态库都实现某一个特定的接口就可以了,比如 XX_init 等,这里就是 plugin_init。里面会有个像注册表一样的数据结构会存储所有的插件的信息。HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:10/29/2007Documentidentifiermain(gst-launch.c)gst_

7、init_get_option_group#defineGST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origi一一n)GST_PLUGIN_EXPORTGstPluginDescgst_plugin_desc=major,minor,name,description,、init,vversion,1license,PACKAGE,package,、origin,GST_PADDING_INIT%GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,GST_VERSION

8、_MINOR,playbin,playerbin,plugin_initVERSION,GST_LICENSE,GST_PACKAGE_NAME,GST_PACKAGE_ORIGIN)gst_plugin_load_file这里进入每一个插件的入口plugin_init;HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:DocumentidentifierGst-launch 的工作逻辑它的工作原理就是根据!号来划分输入的字符串,然后为每个元素构建一个 element,最后建立一个 pip

9、eline把这些元素加入,最后通过 setstate 来启动整个数据循环。g_main_context_iteration一就M当于进X了g_main_loop_runHowtoMountMaemoFileSystemGuideIssue:HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:DocumentidentifierEvent_loop是消息处理循环, 星而取出能取出的消息并处理,maingst_parse_launchv_gst_parse_escapegst_parse_lau

10、nch把所有的!分割的元素放到一个图里面去,图是由一个chain,和一个list组成的,chain存储的是一条链,链里面包括元素也包由舌links,而list里面存储的是linksgst_element_link_padsfilteredgst_parse_perform_delayed_link把src的pad和sink的pad连接起来,如果有filter就src-1rDelayedLink*data=g_new(DelayedLink,1);data-src_pad=g_strdup(src_pad);data-sink=sink;data-sink_pad=g_strdup(sink_p

11、ad)data-caps=gst_caps_copy(caps);data-signal_id=g_signal_connect(G_OBJECT(src),pad-added,G_CALLBACK(gst_parse_found_pad),data);gst_parse_found_padgst_element_link_pads_filtered到这里的话表示pipeline都已经建立的差不多了,下面就是接收dbus消息,然后设置相应的状态_gst_parse_launchyyparsegst_bin_add(bin,GST_ELEMENT(walk-data);gst_parse_per

12、form_link把这两个元素连接起来把这些元素加到新建立的pipeline!面去fileter-sink这里根据信号产生的新的pad作新的连接SystemAnalysisandDesignDocumentsIssueDate:动态 pipeline 的创建原理我们经常需要创建动态的 pipeline,因为我们不知道源头是什么格式的,这时候需要这么做:比如 demuxer,pipeline=gst_pipeline_new(my_pipeline);/向建 pipelinesource=gst_element_factory_make(filesrc,source);/创建srcg_objec

13、t_set(source,location,argv1,NULL);/国置输入文件路径demux=gst_element_factory_make(oggdemux,demuxer);/创建 demuxT6 素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);/这里

14、是关键,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 事件循环 staticvoidcb_new_pad(GstElement*element,GstPad*pad,gpointerdata)gchar*name;name=gst_pad_get_name(pad);g_print(

15、Anewpad%swascreatedn,name);g_free(name);/*here,youwouldsetupanewpadlinkforthenewlycreatedpad*/在这里就可以根据不同 pa 旅连接不同的后面的 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_typef

16、ound),loop);每 Wtypefin 丽件查出类型的时候就会发出法 b 信号。“Onceamediatypehasbeendetected,youcanpluganelement(e.g.ademuxerordecoder)totheHowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:sourcepadofthetypefindelement,anddecodingofthemediastreamwillstartrightafter.总结:从上面这些例子可以看出,它的工作过程是这样

17、的:首先连接能够连接的原素,比如前端 src-decodebi然后后端连接converter-resampler-volume-audiosink。通过 decodebinfi 勺信号,根据源类型创建特定的 srcpad,再把这个 pad接到后端(后端可以创建一个ghostpacOZ 方便使用)这样一个 pipeline 就建好了Decodebin 的工作原理3.4 节已经用文字介绍了 decodebin 的工作原理,下面的图是讲它的内部实现的:HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDa

18、te: gst_decode_bin_class_init:gstelement_klass-change_state=GST_DEBUG_FUNCPTR(gst_decode_bin_change_sta-te);-dynamic_add:dyn-np_sig_id=g_signal_connect(G_OBJECT(element),pad-added,G_CALLBACK(new_pad),dyn);dyn-nmp_sig_id=g_signal_connect(G_OBJECT(element),no-more-pads,G_CALLBACK(no_more_pads),dyn);gs

19、t_decode_bin_init这里基本上是调用的其父亲的change_state只有在从ready到pause的时候会加一个add_fakesinkgst_bin_add(GST_BIN(decode_bin),decode_bin-typefind)decode_bin-have_type_id=g_signal_connect(G_OBJECT(decode_bin-typefind),have_type,G_CALLBACK(type_found),decodebin);信号调用parent_class-change_state(element,transition);这个函数的作用

20、是这样的:首先由typefind发现源所设定的caps,也就决定了decodebin所提供的sink的类型,这个函数就是用来根据它提供的srccap抹选择我总结:从上可以看出,decodebin的工作其实是依靠typefind来实现的,每当它识别出类型的时候就发出信号,由decodebin接收信号并处理,也就是根据它识别出的类型参数,寻找匹配的pad,如果找到了这个元素就把它加到decodebin里面来。这里需要注意的是queue的作用,queued味着是一个thread,他们之间的同步通过一系列的线程同步函数来实现,所以显得非常的复杂type_foundclose_pad_linkfind_

21、compatibles当没有pads需要添加的时候执行gst_element_no_more_padsg_signal_emit(element,gst_element_signalsNO_MORE_PADS,0);try_to_link_1(decode_bin,element,pad,to_try)如果这个src元素的类型为demux则要先创建个queue;贝U下面的usersrcpad就是queued勺srcpad,到最后的时候会把source的src_消连接至1queue的sink:gst_element_set_state(element,GST_STATE_READY);gst_p

22、ad_link(usedsrcpad,sinkpad)gst_element_set_state(element,GST_STATE_PAUSED);这样的iS源的srcpad就已经连上了demuxer或者其它元素的sink这里的element可以理解为源,而to_try是一个listg里面放的是可能连接这个sr&勺sink,比如mp3文件为element,那么sink就可能是我们的mp3decsinknew_paddecode_bin-typefind=gst_element_factory_make(typefind,typefind);gst_decode_bin_change_

23、stateForeachelementinbintoinvokegst_bin_class_initgstelement_class-change_state=GST_DEBUG_FUNCPTR(gst_bin_change_state_funcgst_bin_change_statefunc们能提供的iteratoractivatefolgstelementsetstatd_with_resync(oclass-set_state)(element,state);调用各自原素重载后的setstategst_element_set_basetimegst_bin_element_setstat

24、eIst_bin_src_pads_activatesink,比如解码器Setupelement这里主要讲的是如何把这些播放一个HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:3.6Typefind 的实现原理这里是讲程序是如何查找出对应文件应该选用什么解码器之类的,可以简单理解为source 识另1J。-gst_type_find_element_init:-gst_pad_set_event_function(typefind-sink,GST_DEBUG_FUNCPTR(gst_t

25、ype_find_element_handle_event);TYPE_FIND_REGISTER这里会被会调雨,这是一个对gst_type_find_register 封装的宏,这星会在二不类似“source 所需要的 element 连接起来的:mpeg4”的字符串设定一个匹配函数,这个函数的作用就是根据一段 buffer 里面的一些字节的特征来识别它的类型,比如像函数:mpeg4_video_type_find 等video/HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:gst_

26、element_get_request_padgst_element_class_get_pad_template这里返回取得的newpadgst_element_class_get_pad_template_list从这个list里面取出和传入参数名字相同的templategst_play_bin_class_init:playbasebin_klass-setup_output_pads=setup_sinks;gen_vis_elementelement=gst_bin_new(abin);sink=gst_element_factory_make(alsasink,audiosink)

27、;Audioconvert,Audioresample,Volume,gst_element_link_pads(,)所以最下的结果薪像京这样的:Audioconvert-audioresample-volume-audiosink最后两点是:gst_element_add_pad(element,gst_ghost_pad_new一一一(sink,pad);一一一建立一个ghostpad在convert的sinkpad上g_hash_table_insert(play_bin-cache,abin,element);把这整个bin插入至Uplaybin的abincache里面去。gst_te

28、e_request_new_pad上接playbin页这里就是取得audio类型的srcpad,然后连接到通过gen_audio_elementJi回的bingen_vis_elementorgen_audio_elementgstelement_class-request_new_padGST_DEBUG_FUNCPTR(gst_tee_request_new_pad);*pad=gst_element_get_pad(group-typeGST_STREAM_TYPE_AUDIO-1.preroll,src);res=add_sink(play_bin,sink,pad,NULL);剩下的

29、逻辑就是建立一个bin,bin里面的内容是如右所示:返回的是包含这些元素的bin,并且建立了一个ghostpad,作为整个bin的代表,te&勺意思就是把一个stream分解成两部分tee在这里设置从这里我们可以推断出preroll的作用应该是前端的,add_sink的作用应该就是何个src和sink连接起来Aqueue-asink这里连接的是video勺pad,前面一行代码是说取一个preroll的srcpad,而后面一行里面的sink就是gen_video_elemen版回的那个bin,add_link的作用就是把这srcpad连接到这个sink。pad=gst_element_g

30、et_pad(group-typeGST_STREAM_TYPE_VIDEO-1.preroll,src);res=add_sink(play_bin,sink,pad,textsrcpad);*lement=gst_bin_new(vbin);构谨一不binconv=gst_element_factory_make(ffmpegcolorspace,conv);构建convertersink=gst_element_factory_make(DEFAULT_VIDEOSINK,sink);构建videosinkgst_bin_add(GST_BIN(element),conv);gst_bi

31、n_add(GST_BIN(element),sink);加入到bin里面去gst_element_link_pads(conv,src,sink,sink);连接这些padspad=gst_element_get_pad(conv,sink);gst_element_add_pad(element,gst_ghost_pad_new(sink,pad);创建ghostpadLVqueue-converter-vis-vsinkHowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:Docume

32、ntidentifierPlaybin 的工作原理有了上面几个步骤就可以很容易理解 playbin 的工作原理,不过细节依然非常的复杂,我只是画了框架图:gen_preroll_elementsinkpad=gst_element_get_request_pad(group-typetype-1.selector,sink%d);gst_pad_link(pad,sinkpad);addstreamno_more_pads_fullpreroll=gst_element_factory_make(queue,name);overrun_sig=g_signal_connect(G_OBJECT

33、(preroll),overrun,G_CALLBACK(queue_overrun),play_base_bin);gst_pad_add_event_probeprobe_triggeredqueue_overrun以下的几个函数在每次新构建组的时候会被执行。group_commitsetup_substreamsres=GST_PLAY_BASE_BIN_GET_CLASS(play_base_bin)-setup_output_pads(play_base_bin,group);下面的工作请看setup页HowtoMountMaemoFileSystemGuideIssue:Syste

34、mAnalysisandDesignDocumentsIssueDate:Documentidentifier这里把sourcedecorder连接起来信号是如何发出信号是如何发出的,请看decodebin页new_decoded_pad_fullgst_play_bin_change_state这里需要特别注意的是,gstreamer里面的状态控制是,先从null-ready,然后从ready-pause,,所以setup_source0勺调用时机就是在从ready至1pause的时候gst_play_base_binchange_stateg_signal_connect(decoder,

35、element-added,G_CALLBACK(decodebin_element_added_cb),play_base_bin);g_signal_connect(G_OBJECT(decoder),new-decoded-pad,G_CALLBACK(new_decoded_pad),play_base_bin);g_signal_connect(G_OBJECT(decoder),no-more-pads,G_CALLBACK(no_more_pads),play_base_bin);上面对decoder做了几个信号连接make_decodergst_element_link信号连接

36、decodebin_elementaddedcbnew_decoded_pad至于程序逻辑如何走到这里请看gst-launch页这里我分析的是最普通的情形, 也就是需要解码的, 如果源数据是raw的走别的路线数, 谁调用的待查?但这里只处理eosf言号prepare_output不同的basebin的子类不同的实现HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:Documentidentifier3.9 数据流动下面讲的是里面最复杂的数据流动的分析,我主要分析了 src 的流动和 sin

37、k 的流动,因为中间的数据流动太多,比如解码器,fHter 等等,实在没空,但是我想有这两元素的分析,其它的元素就很容易了:HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate: klass-set_state=GST_DEBUG_FUNCPTR4-(gst_element_set_state_func);gst_base_src_startgst_element_changestatebclass-start(basesrc);(在init函数里被retval-pool.func=func;

38、gst_element_set_stateCaseGST_STATE_CHANGE_PAUSED_TO_PLAYING:gst_base_src_is_live(basesrc)在这里handlergst_base_src_l00P被赋名了GstTask的funcgst_base_src_loop是在gst_task_create里被我置前,在gst_task_func里通皮调词的gst_base_src_loop请看数据流动页2gst_pad_push(pad,一buf);gst_base_src_set_playingbclass-create(src,offset,length,buf)

39、;gst_base_src_do_syncgst_file_src_class_initgst_pad_start_task(basesrc-srcpad,(GstTaskFunction)gstbasesrcloopklass-pool=g_thread_pool_new(GFunc)gst_task_func,klass,-1,FALSE,NULL);gst_task_funcg_thread_pool_newtask-func(task-INdata);g_thread_create(g_thread_pool_thread_proxy,pool,FALSE,&local_err

40、or);设置),当元素为filesrc的时候task-func=func;gst_pad_push_event设置gst_file_src_create设置gst_task_creategst_task_startinit时状态为GSTgst_task_class_initK_STOPPED,于是调用它gst_base_src_changestategst_base_src_get_rangegst_file_src_create_mmap或者gst_file_src_create_readgstbasesrc_class-create=GST_DEBUG_FUNCPTR(gst_file_s

41、rc_create);gthreadpoolpushpool-pool.func(task,pool-pool.user_data);调用g_async_queue_popunlockedg_thread_pool_startthreadg_thread_pool_threadproxy设置HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDocumentsIssueDate:Documentidentifiergst_pad_emit_havedata_signal(chainfunc二GST_PAD_CHAINFUNC(p

42、ad)ret=chainfunc(pad,buffer);gst_pad_set_chain_function(trans-sinkpad,GST_DEBUG_FUNCPTR(gst_base_transform_cha一in);一gst_base_transform_chain这是volume的处理逻辑gst_base_transform_init从这里整个数据流的循环就开始了, 从src的pad发送数据,调用peer的pad的chainfunc函数,这样一步步的传下去了HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDesignDo

43、cumentsIssueDate:Documentidentifiergst_base_audio_sink_class_init:tbasesink_class-set_caps=GST_DEBUG_FUNCPTR(gst_base_audio_sink_setcaps);res=rclass-acquire(buf,spec);从这个signa厢wait操作就可以看清楚它的脉络了,当数据流开始的时候,writefunc一直等待在那个环行缓冲的地方,等待被唤醒,当数据开始的时候由render函数开始一直到gst_ring_buffer_commit_full函数,这里面把数据用memcpy把

44、数据送到环行数据缓冲区里面,并且发出唤醒信号,于是整个生产者消费者循环开始了,它们之间是通过g_cond_signal来实现同步的GST_AUDIORINGG_BUFFER_SIGNAL(buf);gst_ring_buffer_startVrclass-start(buf);gst_audioringbuffer_class_init:调用调发出信号gstringbuffer_class-start二GST_DEBUG_FUNCPTR(gst_audioringbuffer_start);HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisan

45、dDesignDocumentsIssueDate:3.10 总结.时间有限,我只能分析这些框架了,估计看懂这几个图也不容易,两个关键的函数是 change_statdX 是一个经常被重载的函数,基本上元素的初始化,状态的改变都会在这里面会被处理,另外一个非常关键的 chaingfunc 这个函数是开启数据流动的关键函数,通常 srdM 用 chainfunc 函数,在这个函数里面会取出 peerpad 的 chainfunc,然后调用 src 对应的 sink 的 chainfunc,另外一个让我迷惑了很久的是到 sink 的数据是如何流动的,最后分析的结果是它使用了一个环行缓冲,并且使用了

46、线程同步操作来实现生产者消费者的模式以加快数据的传递,所以数据的最终传递是通过发出 p、v 操作来实现的,里面先把数据取出来调用 memcp 冰 copy 到环行缓冲,然后发出 v 操作,对应的消费者被唤醒调用 sink 插件的 write 操作把数据写到设备里面去,这里面还有几块我没有分析的,比如时间戳的处理,各种元素之间的延迟的协商,以及音频视频之间的同步播放等,这里面涉及很多多线程问题,如果要分析估计得花很多的时间。4.reference1/documentation/补充:#playbin 的工作流程1,创建 source。

47、2,创建 decodebin。3,为 decodebin加 typefind。4,在向 bin 添加元素的时候都会发出 element-added 勺信号。5,向 decodebin力口 fakesink。6,把 decodebinft 口入至1Jplaybin.7,等待 type 巾 nd 元素发出的 have-type1 号,并调用回调函数,注意这里的信号实际是只包含了 caps息,而后,根据注册表里面的每个 factory 取出其提供的 capsftype 巾 nd 提供的 cap飘交集,如果有交集则加入到一个 list 表中(find_compatibles)。8,取出 list 里面的元素来连接,如果找到一个就结束,找到后把这个元素与 src 元素连接起来,递归的进行这个元素本身的 sinkpad 的连接,直到收到了 no_more_pads 勺消息。9,decodebirn 攵到 no_more_pad肖息后也会发出同样的消息,其余处理逻辑请看文档gstreamerX 作原理.HowtoMountMaemoFileSystemGuideIssue:SystemAnalysisandDe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论