您的位置:首页 > 编程语言

VLC代码初探

2012-02-28 10:40 162 查看
/article/7857838.html

VLC代码初探(部分内容鉴于作者智商,基本胡扯)

1 废话

2 代码阅读工具、方法

3 VLC部分框架,结合control的rc说明

4 下一步工作

一废话:

惭愧进度比预计的要慢,有老婆孩子就是麻烦阿,尤其是孩子还在老婆肚子里面的时候。想当年年轻的时候晚上工作到2、3点,第2天早上7:30接着搞,LFS的时候3天时间搞定,包括吃饭睡觉几乎没有离开电脑。(bahbahbah...一通废话和借口)

二代码阅读工具、方法:

回到正题,首先讨论一下如何去学习代码(这里是我的浅见,各位大大如果有好的方法,请一定要不吝赐教!拜一个!)。我的方法是使用CGDB( CGDB - curses frontend to gdb)!用CGDB来走流程,对于这些有源码的项目来说再好不过了,实时观看程序流程,把握各个变量和宏的定义,直观学习函数调用。尤其是那些被#define的函数和各种代码段。同时,CGDB还有一个十分好用的功能,断点和观察点!!用这2个再平常不过的功能,我们直接下到对应的位置,运行程序,然后用bt观看程序调用。多么惬意的事情阿。

有例有真相:(这里只简单列举一些例子,算是抛砖头希望各位大大能够丢点玉下来:)

1 找main函数;代码编译好以后,那个文件是入口?如果没有main.c,或者grep main 有N个结果,怎么办,一个一个找?

cgdb vlc;即可!自动停在main入口。当然找main的方法多的是,比如看map文件等等。

2 watch变量,判断在什么地方赋值:当我们知道结果,轻易的找到其调用过程。

(gdb) watch p_intf->pf_run

Hardware watchpoint 3: p_intf->pf_run

(gdb) c

Continuing.

Hardware watchpoint 3: p_intf->pf_run

Old value = (void (*)(struct intf_thread_t *)) 0

New value = (void (*)(struct intf_thread_t *)) 0xb7a21d49 <Run>

Activate (p_this=0x9c3c800) at rc.c:347

(gdb) bt

#0 Activate (p_this=0x9c3c800) at rc.c:347

#1 0xb7f59634 in __module_need (p_this=0x9c3c800, psz_capability=0xb7f8a14c "interface", psz_name=0x9c3c750 "", b_strict=true)

at modules/modules.c:583

#2 0xb7ef13e0 in intf_Create (p_this=0x9bc7210, psz_module=0xb7f7fb3d "$intf") at interface/interface.c:124

#3 0xb7ed96e3 in libvlc_InternalAddIntf (p_libvlc=0x9bc7210, psz_module=0x0) at libvlc.c:1160

#4 0xb7fa9c73 in libvlc_add_intf (p_i=0x9bc7908, name=0x0, p_e=0xbfbdb38c) at control/core.c:190

#5 0x08048d4a in main (i_argc=4, ppsz_argv=0xbfbdb464) at vlc.c:157

(gdb)

这里是我在跟踪./vlc/modules/control/rc.c时候的输出,可以看出该模块的赋值是通过rc.c中的Activate()函数完成的。

3 自动解析繁琐的#define:

在每个module都有一个vlc_module_begin (),这是一个#define。如果你懒得看,或者用肉眼看起来比较困难的话。

#define vlc_module_begin( ) /

EXTERN_SYMBOL DLL_SYMBOL int CDECL_SYMBOL /

__VLC_SYMBOL(vlc_entry) ( module_t *p_module ); /

/

EXTERN_SYMBOL DLL_SYMBOL int CDECL_SYMBOL /

__VLC_SYMBOL(vlc_entry) ( module_t *p_module ) /

{ /

module_config_t *p_config = NULL; /

const char *domain = NULL; /

if (vlc_module_set (p_module, VLC_MODULE_NAME, /

(const char *)(MODULE_STRING))) /

goto error; /

{ /

module_t *p_submodule = p_module;

对于我们这里rc.c文件的代码,直接在代码中下断点,然后让他跑

下断点:

194| vlc_module_begin ()

195+> set_shortname( N_("RC"))

196| set_category( CAT_INTERFACE )

197| set_subcategory( SU

直接看结果:

(gdb) bt

#0 vlc_entry__1_0_0e (p_module=0x9069ca0) at rc.c:195

#1 0xb7f0cad1 in module_Call (obj=0x906e800, p_module=0x9069ca0) at modules/os.c:120

#2 0xb7f069d4 in AllocatePlugin (p_this=0x906e800, psz_file=0x9035c38 "/home/chenee/workstation/ODM/NetDVR/vlc/modules/control/.libs/librc_plugin.so") at
modules/modules.c:1265

可以看出,这个其实是函数vlc_entry__1_0_0e()而已。当然,对于#define,我们完全可以用gcc -E搞定他。

三 VLC部分框架,结合control的rc说明(这里只针对我这几天研究rc模块谈谈,还有好多地方没有搞清楚)

0 在我们研究代码之前,我的习惯是研究Makefile或者是configure,可以通过./configure --help来搞清楚每个参数是什么意思,尽量精简,尤其是对于VLC这种大代码,尤其是公司的破机器,编译一遍很痛苦的。

1 我这里引用的代码是GIT:6d5cb64b3f15494acb43f48e5152d1a9b113f008,2009-07-21 12:19 Fabio Ritrovato。

2 我们的代码入口main是在./vlc/bin/vlc.c中,而这个文件其实只是一个示例而已,大部分功能是由libvlc来提供的。具体是通过Line 144这个函数来创建一个实例。

/* Initialize libvlc */

libvlc_instance_t *vlc = libvlc_new (argc, argv, &ex);

该函数进一步调用libvlc_InternalInit(),这是一个大的函数,好几百行。会初始化VLC用到的各种变量,读取~/目录下面的cache config等目录、文件,初始化moudle_bank等。在这个函数运行完毕,我们会得到一个完整的程序框架,包括已经读取的cache、config、cmdline,还有通过遍历加载的模块链表。cache/config就是文件操作,cmdline就是使用
getopt_long()而已,不表。其他功能目前没有用到,不胡扯。

3 VLC可以看成libvlc+modules的集合:对于libvlc来说,主要功能是实现模块加载框架并遍历安装目录下面/modules文件夹,读取所有*.so模块信息。而真正的功能是由各个module来实现。这样各个开源贡献者可以只专注自己的部分。下面我就简单说明一些模块加载过程。

3.1 即使精简后的modules目录下面也有几百个modules。

3.2 libvlc按需索取:就是根据当前的应用来判断需要加载那些modules。

3.3 对modules/control/rc.c进行说明,这个module是默认加载的interface类的module实现命令行上的控制,根据功能可以看出,它主要是读取解析cmdline然后调用相应函数。rc全称为remote control,因为我是在本地操作所以没有用到里面的net部分,忽略。(每个模块可能会有部分函数或者格式不一样),rc.c文件2k多行,大部分是处理命令,函数10几个,我们取关键部分,

1 vlc_module_begin 和vlc_module_end部分,其实上面说过,就是vlc_entry__1_0_0e()函数,用于注册到系统的时候提供给VLC一些信息,比如模块的功能和优先级:set_capability( "interface", 20 );模块名称、描述、简称等。。。

2 Activate()函数:激活,顾名思义,用于初始化和创建一部分成员,如果rc用到网络功能,会有网络server部分的初始化。这里有个关键赋值是p_intf->pf_run = Run;这个p_intf->pf_run就是提供给后边thread_create的线程主函数。其他略

3 Run()函数,就是简单的读cmd,然后解析,调用。。。

3.4 模块加载过程简单分析:对于我们rc.c来说,调用堆栈如下。

#0 0xb7efc5cc in __module_need (p_this=0x890b800, psz_capability=0xb7f2d14c "interface", psz_name=0x890b750 "", b_strict=true)

at modules/modules.c:573

#1 0xb7e943e0 in intf_Create (p_this=0x8896210, psz_module=0xb7f22b3d "$intf") at interface/interface.c:124

#2 0xb7e7c6e3 in libvlc_InternalAddIntf (p_libvlc=0x8896210, psz_module=0x0) at libvlc.c:1160

#3 0xb7f4cc73 in libvlc_add_intf (p_i=0x8896908, name=0x0, p_e=0xbfa8022c) at control/core.c:190

#4 0x08048d4a in main (i_argc=4, ppsz_argv=0xbfa80304) at vlc.c:157

到了libvlc_add_intf()这里以后,所有的VLC部分已经初始化完成,libvlc使用module_need函数来加载(dlopen,dlsym。。)并运行(thread_create)。

faint,说了这么多废话,其实就是“vlc通过dlopen打开某些module,然后用线程来运行,over!” 这就是libvlc模块话的全部思想,其它的,暂不关心。

4 下一步工作:

1 改写rc,按需实现我们的控制功能(其它功能,我暂时不负责,所以不考虑)

2 进一步了解vlc,尽量做到熟悉每个变量。结构

3 说到变量才发现我忘记讨论变量和结构了。时间原因,下次吧。

结构部分只要关注VLC_COMMON_MEMBERS部分,和各个结构相互cast。

4 优化,还是存在很多低效的module_list_get()需要想想办法改进。

..........
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: