您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 冶金工业 > VLC架构和流程的详细解释文档
VLC架构剖析1.VideoLan简介1.1videolan组成Videolan有以下两部分组成:VLC:一个最主要的部分,它可以播放各种类型的媒体文件和流媒体文件,并且可以创造媒体流并保存成各种格式的媒体文件,这些文件的质量要比没保存前的件好。videolan作为客户端可以播放本地文件,httP://,rtsp://。VLS:是一种流服务器,专门用来解决流的各种问题,它也具有一些VLC的特征。videolan作为服务器可以输出httP,rtP,rtsp的流。1.2VLC优点VLC是一种跨平台的媒体播放器和流媒体服务器,最初为videolan的客户端,它是一种非常简便的多媒体播放器,它可以用来播放各种各样的音视频的格式文件(MPEG-1、MPEG-2、MPEG-4、DivX、WMV、mp3、OGG、Vorbis、AC3、AAC等等)流媒体协议,最具特色的功能是可以边下载边观看Divx媒体文件,并可以播放不完全的AVI文件。并且支持界面的更改。VLC支持多种的操作系统,linux(rh9,Debian,Mandrake,Gentoo),BSD,windows,MacOSX,BeOS,Solaris等等。支持带菜单的VCD,SVCD,和DVD,数字卫星频道、数字地球电视频道(digitalterrestrialtelevisionchannels),在这些操作系统下通过宽带IPv4、IPv6网络播放线上影片。此软件开发项目是由法国学生所发起的,参与者来自于世界各地,设计了多平台的支持,可以用于播放网络流媒体及本机多媒体文件,特别是它能直接播放未下载完整的多媒体文件。下图表示出了VideoLan的解决方案:VideoLanClient是VideoLan项目(一个完整的MPEG-2客户/服务器解决方案)的一个组成部分。不过VideoLanClient也可以作为一个独立的程序来播放来自硬盘或者DVDROM的MPEG数据流。它目前支持GTK+、GNOME、KDE和QT,并且可以使用X11、Xvideo、SDL或者DirectX作为视频输出。对于声音,VideoLanClient支持OSS、ALSA和ESD。要访问DVD,VideoLanClient使用的是Libdvdcss库。它是一个简单的专为DVD访问设计的库。它可以像访问块设备一样访问DVD,而不用考虑解密问题。2.VLC整体架构分析2.1LibVLCLibVLC是VLC的核心部分。它是一个提供接口的库,比如给VLC提供些功能接口:流的接入,音频和视频输出,插件管理,线程系统。所有的LibVLC源码位于src\及其子目录:Interface/:包含与用户交互的代码如按键和设备弹出。Playlist/:管理播放列表的交互,如停止,播放,下一个,或者随机播放。Input/:打开一个输入组件,读包,解析它们并且将被还原的基本流传递给解器。Video_output/:初始化video显示器,从解码器得到所有的图片和子图片(如subtitles)。随意将它们转换为其它格式(如:YUV到RGB)并且播放。Audio_output/:初始化音频mixer(混合器)。如:发现正确的播放频率,然后重新制作从解码器接收过来的音频帧。Stream_output/:类似Audio_output。Misc/:被libvlc其它部分使用的杂项,如线程系统,消息队列,CPU探测,对象查询系统,或者特定平台代码。2.2VLCVLC是一个纯粹围绕着LibVLC写成的程序。它是非常小的,但是功能很齐全的媒体播放器,归功于LibVLC的动态组件支持。2.3组件组件位于modules\子目录,在运行时被加载。每一个组件提供不同的特征适应特定的文件的环境。另外,大量的不断编写的可移植功能位于audio_output\,vidco_output\和interface\组件,以支持新的平台(如:BeoSMaeOSX)。组件中的插件被位于src\misc\modules.c和include\modules*.h中的函数动态加载和卸载。写组件的API描述如下,共3种:(l)组件描述宏:声明组件具有哪种优先级的能力(接口,demux2等等),还有GUI组件的实现参数,特定组件的配置变量,快捷方式,子组件等等;(2)Open(vlc_objeet_t*p_object):被VLC调用初始化这个组件,它被组件描述宏赋值给了结构体module_t中的pf_activate函数指针,被Module_Need调用;(3)Close(vlc_objeet_t*p_object):被VLC调用负初始化这个组件,保证消耗Open分配的所有资源。它被组件描述宏赋值给了结构体module_t中的pf_deactivate函数指针,被Module_Unneed调用。用LibVLC写的组件能够直接被编译进VLC,因为有的OS不支持动态加载代码。被静态编译进VLC的组件叫做内置组件。2.4线程分析(l)线程管理:VLC是一个密集的多线程应用。由于解码器必须预先清空和播放工序必须预先做好流程(比如说解码器和输出必须被分开使用,否则无法保证在要求的时间里播放文件),因此VLC不采用单线程方法。目前不支持单线程的客户端,多线程的解码器通常就意味着更多的开销(各线程共享内存的问题等),进程间的通信也会比较复杂。VLC的线程结构基于pthreads线程模型。为了可移植的目的,没有直接使用pthreads函数,而是做了一系列类似的包裹函数:vlc_thread_create,vlc_thread_exit,vlc_thread_join,vlc_mutex_init,vlc_mutex_lock,vlc_mutex_unlock,vlc_mutex_destroy,vlc_cond_init,vlc_cond_signal,vlc_cond_broadcast,vlc_cond_wait,vlc_cond_destroy和类似结构:vlc_thread_t,vlc_mutex_t,andvlc_cond_t。(2)线程同步:VLC的另一个关键特征就是解码和播放是异步的:解码由一个解码器线程工作,播放由音频输出线程或者视频输出线程工作。这个设计的主要目的是不会阻塞任何解码器线程,能够及时播放正确的音频帧或者视频帧。这样实现也导致产生了在接口,输入,解码器和输出之间的一个复杂的通讯结构。虽然当前接口并不允许,但是让若干个输入和视频输出线程在同一时刻读取多个文件是可行的(这是VLC未来改进的主要方向)。现在的客户端就是用这种思想实现的,这就意味着如果没有用到全局锁的话那么一个不能重入的库是不能被使用的(尤其是liba52库)。VLC输出的流里包含时间戳,被传递给解码器,所有有时间戳标记的流也均被记录,这样输出层可以正确及时的播放这些流。时间mtime_t是一个有符号的64-bit整形变量,单位是百万分之一秒,是从1970年7月1日以来的绝对时间。当前时间能够被mdate()函数恢复。一个线程可以被阻塞到mwait(mtime_tdate)等到一个确定的时间才被执行。也可以用msleep(mtime_tdelay)休眠一段时间。如果有重要的事情要处理的话,那么应该在正常时间到来之前被唤醒(如色度变换)。例如在modules\codec\mpeg_vldeo\synchro.c中,通常的解码时间被记录,保证图像被即时解码。3.VLC接口技术分析3.1VLC运行过程通过对相关资料和自己的分析,VLC的运行过程如下:ELF(Linux下可执行文件的格式)先被动态加载,然后主线程就变成了接口线程并且在src/interface/interface.c中开始。它执行下列步骤:1.cpu探测:什么型号?所有能力(MMX,MMXEXT,3DNow,AltiVec等等)2.消息接口初始化;3.命令行选项解析组件4.创建播放列表5.仓库初始化6.加载所有内置和动态组件7.打开接口8.安装信号处理器:SIGHUP,SIGINT和SIGQUIT(捕获一个,忽略后来的并退出)。9.派生音频输出线程;10.派生视频输出线程;11.主循环:事件管理;下图表示了这些步骤的执行过程:VLC的运行过程图3.2消息接口由于printf()函数不是线程安全的,因此在调用printf()函数时一个线程的执行将会受到干扰,当这个线程被另一个函数所调用时就会其状态被破坏而退出程序。所以VLC构造了自己的线程安全的消息接口。VLC的线程安全的消息接口有两种实现方式:如果在config.h里定义了INTF_MSG_QUEUE的话,每一个类似printf()的函数将会把排队的消息放到链表里,这个链表将会在事件循环中被线程接口用红色标记的方式打印出来。如果INTF_MSG_QUEUE没被定义的话,调用线程将会获得一个printlock(用来防止在同一时刻有两个printf操作被执行)同时直接打印出消息(默认操作)。以下为VLC线程安全消息的API:QueueMsg:添加一条消息到消息队列,如果消息队列满了,先打印所有的消息;FlushMsg:打印所有在消息队列里的消息,特别的,消息队列必须被提前加锁,因为该函数不检查锁。PrintMsg:打印一条消息到stderr,可以打印彩色消息。3.3命令行选项VLC用GNU的getopt解析命令行选项。Getopt结构定义在src\extras\getopt.h里。所有的配置也可以用环境变量改变:调用函数main_Put*Variable和main_Get*Variable。所以,.\vlc--height=240和.\vic_height=240./vlc(这种方式用于所有地方,包括插件)是一样的。但是为了线程安全的考虑,当第二个线程派生了,main_Put*Variable便不能被使用了。3.4播放列表管理当VLC得到输入媒体文件的时候播放列表被创建。一个合适的接口插件能够从这个播放列表添加和删除文件。在src/Playlist目录下的这些被使用的函数被描述。播放列表既不是动态组件也不是内置组件,只是可以被外部调用的API:Playlist_Create:初始化播放列表,派生两个线程。一个是播放列表主线程RunThread调用Input_CreateThread为每个被读的文件派生输入线程。一个是播放列表里的项目排队预解析线程RunPreparse。Intf_playlistadd和intf_playlistdelete是两个典型的最常用的添加和删除播放列表的命令函数。此时接口主循环函数inif_manage将被启动同时在必要的时候终止输入的线程。3.5组建仓库在启动的时候,VLC创建一个包含所有插件接口(.so和内置插件)的仓库,每一个插件都会被检查其实现的功能,这些功能如下:MODULE_CAPABILITY_INTF:一个接口插件。MODULE_CAPABILITY_ACCESS:ASam-ism,目前还没有用到。MODULE_CAPABILITY_PUT:一个输入插件比如说PS和DVD的播放要用到。MODULE_CAPABILITY_DECAPS:ASam-ism,unusedatpresent。MODULE_CAPABILITY_ADEC:音频解码器。MODULE_CAPABILITY_VDEC:视频解码器。MODULE_CAPABILITY_MOTION:视频解码器的补充动态组件。MODULE_CAPABILITY_IDCT:视频解码器的IDCT组件。MODULE_CAPABILITY_AOUT:一个音频输出组件。MODULE_CAPABILITY_VOUT:一个视频输出组件。MODULE_CAPABILITY_YUV:视频输出的YUV组件。MODULE_CAPABILITY_AFX:音频输出的音频效果插件,目前还没实现。MODULE_CAPABILITY_VFX:视频输出的音频效果插件,目前还没实现。管理这些插件的API如下:Module_InitBank
本文标题:VLC架构和流程的详细解释文档
链接地址:https://www.777doc.com/doc-6177100 .html