1. 目录结构 gstreamer-0.10.21 目录 gst 核心文件,实现gst 元件工厂等功能 plugins gstreamer-0.10.21提供的元件 lib 不可被应用调用的元件,但他是某些元件的parent class pkgconfig install tools 都是make install需要拷贝的东西 po 各种语言的翻译文件 tests 测试gstreamer-0.10.21的元件 gst -plugins-base-0.10.21 目录 gst base提供的元件 gst -libs base提供的元件的parent class,应用不可用的元件 ext 需要额外源码库的元件 sys 系统相关的元件(x11,v4l)这2个window就没有 2.细数元件 看 gst 有哪些元件就看 哪些文件调用了gst_element_register grep -nr 'gst_element_register' --include=*.c ./ gstreamer的元件统一注册,别的元件基本都是单独注册 static struct _elements_entry _elements[] = { {"capsfilter", GST_RANK_NONE, gst_capsfilter_get_type}, {"fakesrc", GST_RANK_NONE, gst_fake_src_get_type}, {"fakesink", GST_RANK_NONE, gst_fake_sink_get_type}, #ifdef HAVE_SYS_SOCKET_H {"fdsrc", GST_RANK_NONE, gst_fd_src_get_type}, {"fdsink", GST_RANK_NONE, gst_fd_sink_get_type}, #endif {"filesrc", GST_RANK_PRIMARY, gst_file_src_get_type}, {"identity", GST_RANK_NONE, gst_identity_get_type}, {"queue", GST_RANK_NONE, gst_queue_get_type}, {"filesink", GST_RANK_PRIMARY, gst_file_sink_get_type}, {"tee", GST_RANK_NONE, gst_tee_get_type}, {"typefind", GST_RANK_NONE, gst_type_find_element_get_type}, {"multiqueue", GST_RANK_NONE, gst_multi_queue_get_type}, {NULL, 0}, }; 3.playbin (只说playbin播放视频的情况) playbin元件算是整合的元件,内部建立工厂管道,用到很多元件。 3.1元件流程图 filesrc --> (typefind) -->decodebin -->|--> abin (audioconvert-->audioresample-->volume-->osssink) ··························································|--> vbin (identity-->ffmpegcolorspace-->videoscale-->fbdevsink) 3.2代码分析 应 用程序建立playbin元件后就调用get_element_set_state将playbin设置为 NULL,READY,PAUSED,PLAYING, 在READY-->PAUSED时候(GST_STATE_CHANGE_READY_TO_PAUSED),playbin就把管道建立起来了 gst_play_base_bin_change_state |----setup_source |----|----gen_source_element 建立source元件,也就是filesrc |----|----|----if (play_base_bin->suburi) setup_subtitle 如果playbin的suburi属性被设置了就配置字幕元件 |----|----|----gst_element_make_from_uri |----|----|----|----get_element_factories_from_uri_protocol根据字符串头uri协议search_by_entry确定工厂类型,比如file://则建立filesrc |----|----|----gst_element_factory_create根据确定的工厂类型建立元件(filesrc) |----|----analyse_source分析源是否是raw数据/有动态pad/有输出pad再做相应处理 |----|----|----几种情况都会走到group_commit |----|----|----|----GST_PLAY_BASE_BIN_GET_CLASS (play_base_bin)-> setup_output_pads 也就是gstplaybin.c的setup_sinks |----|----|----|----|----有音频需要可视化调用gen_vis_element |----|----|----|----|----有音频不需要可视化调用gen_audio_element |----|----|----|----|----有视频调用gen_video_element |----|----make_decoder |----|----|----gst_element_factory_make("decodebin", NULL)建立decodebin元件 |----|----gst_element_link (play_base_bin->source, decoder)把filesrc和decodebin链接起来 3.3 playbin目录 目录是gst -plugins-base-0.10.21/gst /playback/ 原本看 着文件挺多,不过是2套playbin,其中一套是非稳定版本playbin2,所以其实真正要看 的文件不多 。 gstplayback.c注册playbin和playbin2 playbin 用到的C文件有(主要是playbin, playbasebin, decodebin) gstplaybin.c gstplaybasebin.c gstdecodebin.c gststreaminfo.c gststreamselector.c gstplaymarshal.c playbin2 用到的C文件有(与playbin,playbasebin, decodebin等价的是playbin2,playsink, decodebin2) gstplaybin2.c gstplaysink.c gstdecodebin2.c 及剩下的一些文件,gsturidecodebin.c和gstdecodebin2.c也是非稳定版本 3.4 playbin元件用到的parent class filesrc 的parent_class是basesrc ,从下面可以看 出来, GST_BOILERPLATE_FULL (GstFileSrc, gst_file_src, GstBaseSrc, GST_TYPE_BASE_SRC, _do_init); 当用户调用set_state时对应内部change_state, 会调用该元件的parent class的change_state。basesrc就像是filesrc的基类 osssink 的parent_class是audiosink ,从下面可以看 出来, osssink_type = g_type_register_static (GST_TYPE_AUDIO_SINK, "GstOssSink", &osssink_info, 0); osssink只是做跟底层相关的工作,音频的逻辑层还是在audiosink和它的parent audiobasesink里面,他们再调用osssink的函数指针做具体读写声卡的操作 3.5 元件的parent class 因为change_state会分发到管道中的每个元件,元件的change_state里都会调用它parent_class的change_state,所以不免想看 看 playbin的parent_class struct _GstPlayBin { GstPlayBaseBin parent; struct _GstPlayBaseBin { GstPipeline pipeline; playbin-->playbasebin-->pipeline已经到管道了 set_state能发送给管道中所有元件的change_state函数 每个元件的change_state函数中都会调用parent_class的change_state, playbin--(parent)-->playbasebin playbasebin--(parent)-->pipeline pipeline--(parent)-->bin 最上一级是bin,看 bin的change_state函数, while (!done) { gpointer data; switch (gst_iterator_next (it, &data)) { case GST_ITERATOR_OK: { GstElement *child; child = GST_ELEMENT_CAST (data); /* set state and base_time now */ ret = gst_bin_element_set_state (bin, child, base_time, current, next); 把bin里的元件一个个取出来发送set_state命令,这样所有元件都会改变状态了 gstclock获得时钟的3种方式 1 systemclock系统时钟 2 音频设备 基于采样率而知道的时钟 3 网络包中包含的时钟信息 我只看 过systemclock, gstclock->gstsystemtclock->g_get_current_time->gettimeofday->(system call) 音视频时间同步到系统时间 并不是音频和视频谁同步谁,而是大家都跟系统时间同步 NS...B...B...EOS NS=new segment C.running_time = absolute_time - base_time (系统) B.running_time = (B.timestamp - NS.start)/NS.abs_rate + NS.accum (元件) 同步就是让B,C的running_time相等, B等待 base_time从NEW_SEGMENT事件发出为基准,比如seek后就是NEW SEGMENT _class_init给klass挂函数指针 gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; gstbasesink_class = (GstBaseSinkClass *) klass; 把一个klass转换为3种数据结构,可以的原因是一级级都是数据结构的第一个成员,传进来的kclass是最大的数据结构,往小转当然可以 struct _GstBaseAudioSink { GstBaseSink element; struct _GstBaseSink { GstElement element; struct _GstElement { GstObject object; 状态变迁 NULL-->READY 1 probe device 2 open device READY-->PAUSED 1 激活pad,返回ASYNC,然后起stream thread线程才把状态改变的事情做完,直到sink pad收到first buffer,阻塞住,这时才真正算状态改变完,用get_state可以查询到 2 管道running_time归零 3 如果是live source返回NO_PREROLL,不产生数据(live source是即使暂停也会产生数据的源,比如net和camera) PAUSED-->PLAYING (大部分元件忽略这个状态) 1 管道选择时钟分发到每个子元件,也就是同步时钟只发生在PLAYING时 2 管道把clock running_time计算出来的base_time分发到每个子元件(change_state时) 3 sink衬垫不再阻塞buffer/event,开始render数据 4 live source开始产生数据 PLAYING-->PAUSED (大部分元件忽略这个状态) 1 如果sink此时无buffer在手一定要等收到buffer才能完成状态改变。看 上面的READY->PAUSED也是sink在进入PAUSED前一定要有buffer,为了PLAYING时不至于让用户等待前面的一小撮时间 2 EOS事件无效,但到PLAYING时会repost 3 sink把preroll上的所有等待都解除阻塞 4 live source停止产生数据 PAUSED-->READY 1 sink解除阻塞preroll,元件解除阻塞设备 2 chain和get_range 返回WRONG_STATE,(buffer相关的函数) 3 pad使无效(deactivate),stream thread停止 4 sink忘记所有的协商格式(negotiation caps) READY-->NULL 1 close device 2 删除所有动态建立的pads
|
|
来自: 开花结果 > 《Gstreamer》