vlc源码分析--issue (未完待续)

最近分析VLC源码,很是疑惑,虽然来百度也能找到很多关于vlc源码结构的技术博客,不过大体都讲的vlc几个模块的概述而已,寻寻觅觅终无所获,实在太过空虚,不如索性直接探究源码,毕竟,所有的措辞,他就在源码里面,实实在在真真切切,它就在那里,一览无余。自此一入源码深似海。

源码大致的结构,已经在其他文章有所描述,个人也写过关于它的makefile分析和函数流程图的博客,此篇不在赘述,而是想列几个问题:(首先声明,个人编译的版本为vlc 3.0.6,ubuntu 18.04,运行命令行版本,只关注解码业务数据流程,让界面什么的)

Q1: vlc使用模块的方式动态支持各种模块,哪它的这些模块有什么接口要求?

     既是模块化,想来C++是个很好的选择,可惜这是C写的,整个源码里面很多的结构体定义,结构体里面各种指针,包括函数指针,这里的函数指针,就是接口的要求了。不防这么来看,每一个模块文件中有定义自己模块的结构体类型,好比一个类,结构体中的成员,即类的数据成员,函数指针,即类的public 成员函数,一般很多的函数都会声明为 static ,这说明这是这个类的内部私有函数,非接口。  这么看好像容易了些,毕竟这么多的函数在调用的时候都会看到他的 头一个参数一般是本模块的结构体类型,这就好比 c++里面的this指针,不然每次调用一个函数,定位他的 这个参数的来源就相当不好理解了。  现在只要搞清楚这个模块的结构体 什么时候被创建的,相当于 New了一个类,然后后面的调用基本都是通过这个类(传递这个结构体)来调用的

Q2: 实在难找到解码线程在哪里 创建的

    程序启动各种初始化之后,主要的驱动循环input线程,input线程会根据实际的操作需要动态改变解码线程的状态,自然也是有解码需要的时候才会去创建,大概是这样创建的:

补充一下initPrograms的调用源头:
main() ==》libvlc_add_intf() ==> libvlc_InternalAddIntf() ==> intf_GetPlaylist() ==> playlist_Create()

==> playlist_Activate ==> Thread(void *data) 

==> running state ; Next() ==> PlayItem() ==> input_Start() ==> Run() ==> InitPrograms()

Q3:模块是怎么加载的?具体路径在哪里?

  在posix/plugin.c文件中的 module_Load函数里面,printf一下 path这个参数,就可以看到了。

eg:wang plugin->abspath /mnt/hgfs/ubuntu_share/open_prj/vlc-3.0.6/modules/.libs/libavcodec_plugin.so 506 module_Map modules/bank.c (这是在他的上一层调用函数里面的输出)

   拿上面的解码器模块来看,在src/input/decoder.c文件中 LoadDecoder函数,内部加载

 p_dec->p_module = module_need( p_dec, caps[p_dec->fmt_in.i_cat], "$codec", false );

这里模块名称传递的是 $codec, module_need会认为这是一个 variables,它会加载一类模块而不是具体的一个模块,经过层层的筛选调用,走到src/module/bank.c 中的module_Map,这个函数会优先检查对应的模块是否已经加载,如果没有,则调用 plugin.c文件中的 module_Load(vlc_object_t *p_this, const char *path, module_handle_t *p_handle, bool lazy)  ;这个文件有多个定义,因为涉及到具体的动态库的加载操作,和不同的操作系统有关系,为了兼容的源故再此处分开。我这里ubuntu上,走的posix/plugin.c ,里面用dlopen() 来打开动态库文件。在这里面就可以printf 一下这个模块的path

Q4:大名鼎鼎的ffmpeg解码库,怎么用上去的?

  同样是上面的 解码器加载部分,发现它实际加载的是 libavcodec_plugin.so,那这个库怎回事?看一下这个so库竟然大小达到了63M,很有猫腻,分析一下makefile:

libavcodec_plugin.la: $(libavcodec_plugin_la_OBJECTS) $(libavcodec_plugin_la_DEPENDENCIES) $(EXTRA_libavcodec_plugin_la_DEPENDENCIES)

  $(AM_V_CCLD)$(libavcodec_plugin_la_LINK) $(am_libavcodec_plugin_la_rpath) $(libavcodec_plugin_la_OBJECTS) $(libavcodec_plugin_la_LIBADD) $(LIBS)

编译命令:

......

codec/avcodec/libavcodec_plugin_la-video.lo codec/avcodec/libavcodec_plugin_la-subtitle.lo codec/avcodec/libavcodec_plugin_la-audio.lo codec/avcodec/libavcodec_plugin_la-va.lo codec/avcodec/libavcodec_plugin_la-avcodec.lo codec/avcodec/libavcodec_plugin_la-encoder.lo

-L/usr/local/lib -lavcodec -pthread -lm -lswresample  -lm -lavutil -pthread -lm -lm libavcodec_common.la

终于见着大名鼎鼎的ffmpeg了,  libavcodec_plugin.so  连接到了 系统路径 /usr/local/lib 下的 libavcodec

Libswresample 这,就是ffmpeg编译后生成的库,上述的几个vlc中的.c文件,实际上就是包装了部分ffmpeg的功能,以符合

Vlc解码模块的接口要求。

Q5:怎么加一个自己的模块?怎么拆卸我不想要的模块?

Q6:用这个框架搭一个最小需求的例子

Q7:从源码里面把一个MP4文件解复用得到的视频数据直接写到一个文件中,把解码器解码得到的图像数据直接写到文件中

Q8:vlc命令行模式解析命令

Q10:外部调用libvlc图解:

猜你喜欢

转载自blog.csdn.net/u012459903/article/details/88035705