vlc播放流程分析–1

  • Post author:
  • Post category:其他



本文基于windows下的vlc,vlc版本为2.2.0。


1、 cpu性能检测:


该功能在加载libvlccore.dll时由系统调用该动态库的DllMain()(/src/win32/thread.c,该函数再调用vlc_CPU_Init())执行的,即发生在WinMain()函数执行之前,加载vlc.exe的依赖库时。通过dumpbin工具查看vlc.exe,可知vlc.exe依赖于libvlc.dll;同样可知,libvlc.dll依赖于libvlccore.dll。




2、获取命令行参数:


获取命令行参数,并在命令行参数中添加如下几个参数:”–media-library”,”–stats”,”–no-ignore-config”。




3、调用libvlc_new()创建一个libvlc(libvlc_instance_t)实例:


1. 调用libvlc_threads_init()初始化线程系统;


2. 调用vlc_custom_create(libvlc_InternalCreate())创建一个libvlc_int_t对象;


从vlc_custom_create()可以看出,实际创建的是vlc_object_internal_t和libvlc_priv_t两个连在一起的对象,返回的是libvlc_priv_t中的libvlc_int_t对象的指针:


vlc_object_internal_t


libvlc_priv_t


libvlc_int_t












3. 调用libvlc_InternalInit()初始化刚刚创建的libvlc_int_t对象:


a. 调用system_Init()初始化特定的系统(windows主要是设置multi media时钟精度和初始化winsock);


b. 调用module_InitBank()初始化模块银行:


b.1 调用module_InitStatic()注册核心模块(libvlccore,入口为vlc_entry_core),注意,核心模块是不可卸载的;


b.2 调用module_StoreBank()将核心模块放入模块银行;


b.3 调用config_SortConfig()对(核心模块的)配置项进行排序,并放在config表中;


c. 调用config_LoadCmdLine()解析命令行选项(影响模块加载);


d. 调用vlc_LogInit()初始化日志系统(获取并设置日志等级);


e. 调用vlc_threads_setup()初始化线程环境??(该函数仅调用SelectClockSource()设置时钟源,默认为multimedia时钟);


f.  调用module_LoadPlugins()加载所有的模块(描述符)到模块银行:


该函数最终调用CacheLoad()从模块缓存文件(<vlc path>\plugins\plugins.dat)中 读取缓存的插件信息,然后递归调用AllocatePluginDir()从<vlc path>\plguins及


其子目录下获取可用的插件信息,实际获取可用插件信息是由AllocatePluginFile()完成的,该函数主要功能为:


1) 调用CacheFind()查找插件是否已加载;


2) 对于未加载的插件,调用module_InitDynamic()加载插件并初始化(调用入口函数);


3) 如果该模块是可卸载的,则调用module_Unload()卸载掉该模块;(即我们只是为了获取模块的描述信息,而直到真正需要时才加载模块);


4) 如果模块的配置信息中包含回调函数,则强制加载此模块;(???)


5) 调用module_StoreBank()将模块存入模块银行;


6) 调用CacheAdd()将模块信息放入缓存中;


在加载完所有的模块信息后,先调用config_UnsortConfig()释放掉之前的配置项链表,在调用config_SortConfig()重新收集并排序配置项;


g. 调用config_LoadConfigFile()从配置文件中读取配置项的值并保存到config表中();


h.  调用config_LoadCmdLine()从命令行参数中读取配置项的值并保存到config表中。


4、调用libvlc_InterfnalAddIntf(libvlc_add_intf())创建并启动一个hotkeys interface 插件:


1. 调用playlist_Create(intf_GetPlaylist())创建一个播放列表(获取播放列表,如果没有则创建一个):


a. 调用vlc_custom_create()创建一个播放列表对象;


b. 调用input_Read(playlist_MLLoad())初始化一个输入线程,运行它直到它停止(???);


c. 调用playlist_preparse_New()创建一个input resource对象;


d. 调用input_resource_New()创建一个input_resource对象;


e. 调用aout_New(input_resource_GetAout())创建一个音频输出对象(其中有加载音频输出模块,安装一系列回调函数);


f. 调用playlist_Active()启动playlist线程(线程函数为src\playlist\Thread.c的Thread());


2. 调用intf_Create()创建和启动hotkeys接口(libhotkeys_plugin.dll)插件(通过module_need()查找合适的插件并加载和启动);




5、调用libvlc_add_intf()创建globalhotkeys接口:

加载了libwin_hotkeys_plugin.dll插件;启动了globalhotkeys线程(线程函数为\modules\control\globalhotkeys\win32.c的Thread)。

6、调用libvlc_add_intf()创建默认界面接口:

加载了libqt4_plugin.dll插件;启动了QT4线程(线程函数为\modules\gui\qt4\qt4.cpp的Thread()),另外,QT线程还会自己启动4个其它线程(???)。

7、调用libvlc_playlist_play()启动播放(由于刚开始时playlist里还无内容,所以无实际动作)。

8、调用libvlc_wait()等待播放退出;

9、释放libvlc实例,程序退出。




从上,可以看出,启动过程中,VLC先进行了CPU性能检测;然后扫描了所有可用插件的配置参数,并从命令行及配置参数中读取了配置参数的值;启动完成后,总共有4个线程(不包括QT启动的那几个线程)在运行:主线程(等待播放退出消息),QT线程,playlist线程及globalhotkeys线程。






版权声明:本文为finewind原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。