Vlc流播放流程
vlc源码目录树:
目录名称 |
说明 |
bindings |
Java, CIL 和Python绑定 |
doc |
帮助文档 (不是更新的) |
extras |
另叙。 |
include |
VLC 头文件 |
libs |
SRTP库和装载库 |
lxdialog |
制作 menuconfig的文件 |
m4 |
Automake和autoconf的宏文件 |
modules |
除了src目录外最重要的目录。参考“功能模块目录树”一节 |
po |
i18n (语言翻译)文件 |
projects |
建立在 libvlc的项目,如Mozilla插件,ActiveX 插件和MacOS X Framework |
share |
图标,脚本等等 |
src |
除了功能模块以外最重要的目录。 |
test |
一些脚本或测试代码 |
extras 的内容
extras/analyser |
一些代码风格编辑器 (vim,emacs)的宏和一些valgrindsuppressions |
extras/buildsystem |
可选的编译系统 |
extras/contrib |
需要的库文件 (包括Makefiles自动下载和编译(或交叉编译),补丁)。 |
extras/deprecated |
deprecated 文件 |
extras/misc |
未分类文件 |
extras/package |
用于软件发布的文件如ipkg,不同的 rpm 规范文件,win32和Mac OS X安装文件。 |
目录名称 |
子目录 |
说明 |
access |
通过网络获取视频流的协议(http,ftp,fake,tcp,udp等),获取物理媒体介质的媒体内容如cd,dvd。 |
|
cdda |
读取CD音频的输入模块 |
|
dshow |
DirectShow获取插件,用于WINDOWS平台下的编码卡。 |
|
dvb |
使用V4L2API的输入模块,用于DVB-S/C/T媒体流。 |
|
mms |
基于TCP,UDP的MMS和HTTP获取模块 |
|
rtsp |
||
screen |
获取屏幕图像的输入模块。 |
|
vcd |
获取VCD数据的输入模块。 |
|
vcdx |
获取VCD输入模块,可以导航,静止 |
|
access-filter |
包含下面的滤波器:timeshift, record, dump |
|
access-output |
||
audio-filter |
各种音频滤波器如解码,均衡,转换。 |
|
channel-mixer |
各种混合器,解码器如 Dolby解码器 |
|
converter |
定点或浮点音频格式转换如 AC/3,MPEGI-II 音频层1,2, 3 解码 |
|
resampler |
各种音频重采样模块 |
|
audio-mixer |
混合器插件 |
|
audio-output |
音频输出插件如ALSA,OSS和 DirectX音频 |
|
codec |
各种编解码,特别是ffmpeg |
|
cmml |
持续媒体标记语言,脚本/超链接解释器 |
|
dmo |
一个DirectMediaObject解码器,利用DirectMedia对WMV3视频解码 |
|
ffmpeg |
ffmpeg 库的视频解码器 |
|
spudec |
RLE DVD 小标题解码 |
|
xvmc |
XVMC视频输出和解码 |
|
control |
控制播放器的各种接口:手势, 热键,lirc,远程控制和telnet |
|
http |
HTTP远程控制 |
|
demux |
不同的解复用程序 |
|
asf |
ASF 解复器 |
|
avi |
AVI文件流解复器 |
|
mp4 |
MP4文件输入模块 |
|
mpeg |
||
playlist |
播放清单导入模块 |
|
gui |
不同平台的用户界面和 ncurses接口 |
|
beos |
用于BeOS的音频输出,视频输出和用户界面输出。 |
|
macosx |
Mac OS X 视频输出和用户界面模块 |
|
pda |
iPaq用户接口,使用Gtk2+widget集. |
|
qnx |
QNX RTOS 插件 |
|
qt4 |
使用Qt4库交叉编译的用户界面模块。该模块是默认的界面库 |
|
skins2 |
换夫模块。 |
|
wince |
Pocket PC 接口 |
|
wxwidgets |
使用wxWindows库跨平台的接口。作为默认的接口的VLC版本是0.86a. |
|
meta-engine |
||
misc |
||
dummy |
哑 (没有GUI)音频输出,视频输出,用户接口和输入模块。 |
|
memcpy |
内存快拷贝模块 |
|
notify |
通知,使用libnotify |
|
playlist |
||
probe |
||
testsuite |
||
xml |
LibXML 和 xtagxml 解析 |
|
mux |
Various Muxers |
|
mpeg |
||
rtp |
||
packetizer |
打包模块,用于H264/AVC和MPEG 4音视频流。 |
|
services-discovery |
||
stream-out |
||
transrate |
||
video-chroma |
图像格式转换,如 YUV到 RGB |
|
video-filter |
各种视频滤波模块如Deinterlace,Transform, Wall, Crop,Panoramix 等等。 |
|
video-output |
||
directx |
WINDOWS视频输出模块,使用Direct3D和Direct X API,OpenGL |
|
qte |
QT嵌入式视频输出模块 |
|
x11 |
X11 API视频输出模块 |
|
visualization |
多种可视化模块,包括goom |
|
galaktos |
输出到 OpenGL的可视化模块 |
|
visual |
可视化系统 |
vlc核心的是libvlc,它提供界面,应用处理功能,所有的libvlc的源代码都放在src目录及其子目录
./config/: 从命令行和配置文件中加载配置./control/:提供动作控制功能,如播放等操作
./extras/: 大多是平台的特殊代码
./modules/: 模块管理
./network/: 提供网络接口(socket管理,网络接口)
./osd/: 显示屏幕上的操作
./test/: libvlc测试模块
./text/: 字符集
./interface/: 提供代码中可以调用的接口,如按键后的硬件作出反应
./playlist/: 管理播放功能
./input/: 建立并读取一个输入流,并且分离其中的音频和视频,然后把分离好的音频和视频流发给解码器
./audio_output/:初始化音频混合器,即设置正确的同步频率,并对从解码器传来的音频流重新取样
./video_output/:初始化视频播放器,把从解码器得到视频画面转化格式从yuv到rgb,然后播放
./stream_output/ 输出音频流和视频流到网络
./misc/: libvlc使用的其他部分功能,如线程系统,消息队列等.
一、首先介绍一下vlc启动动态加载模块的过程:
1. 最先程序段入口是文件Vlc.c(./bin/)中的main()函数完成的Functions(parsecommand line, start interface and spawnthreads),在main中程序会调用libvlc_new函数(./lib/Core.c)接口,实现创建一个VLC运行实例libvlc_instance_t,该实例在程序运行过程中唯一。
2. 在libvlc_new函数接口中,调用了libvlc_InternalInit()函数实现具体的初始化工作。
3. libvlc_InternalInit(./src/Libvlc.c)函数中,首先通过system_Init()函数完成传入参数对系统的相关初始化,接着通过module_InitBank()(./src/modules/Bank.c)函数初始化module_bank结构体,并创建了main模块,然后(不支持动态载入的时候则通过module_LoadBuiltins载入静态模块)通过module_LoadPlugins(./src/modules/Bank.c)函数载入动态模块,通过module_need(./src/modules/Modules.c)函数载入并激活memcpy模块,通过playlist_Create(./src/playlist/playlist.c)函数,创建了一个playlist播放管理的线程,其线程处理函数为RunThread(./src/stream_out/sap.c),通过intf_Create(./src/interface/Interface.c)函数添加并激活hotkeys模块,最后根据系统设置定义了宏HAVE_X11_XLIB_H,因此还需要添加screensaver模块。
4. 此时加载的模块有main,hotkeys,screensaver,memcpy;多创建了一个线程,用于管理playlist,该线程无限循环,直到p_playlist->b_die状态为止。
5. 其次程序中创建VLM对象,该接口调用的是vlm_New(./src/input/Vlm.c)函数,实现VLM对象的创建,函数返回值是指向vlm_t的指针。
6. vlm_New函数中,创建了一个vlm管理线程,线程处理函数为Manage(./modueles/video_output/msw/Glwin32.c)。该函数循环处理当前各种媒体(vod、broadcast、schedule)的播放实例,控制其每个播放细节(如:从一个input切换到下一个input;schedule周期循环调度等)。与playlist线程不同的是,Manage主要针对播放实例的操作,而RunThread主要针对播放列表的管理,也就是说VLC管理是分级的,播放列表级和播放列表中媒体播放实例级。
7. 其次程序载入播放节目单,该接口调用的是ExecuteLoad(./src/input/Vlmshell.c)函数,在该函数中,依次调用如下函数:stream_UrlNew、stream_Seek、stream_Read、Load。
8. 接着程序调用libvlc_vlm_play_media(./lib/Vlm.c)将节目流发布出去,实质是调用ExecuteCommand(./src/input/Vlmshell.c),完成对命令的执行,根据命令类型,由ExecuteControl(./src/input/Vlmshell.c)函数处理。
9. 然后由vlm_ControlMediaInstanceStart(./src/input/Vlm.c)函数完成播放实例的初始化,并调用input_CreateAndStart(./src/input/input.c)函数,input_CreateAndStart实际调用的是input_Create和input_Start(./src/input/input.c),在input_Start函数中实际调用vlc_clone最终完成播放线程的,线程的处理函数为Run(./src/input/input.c)。
10. Run线程是整个VLC作为流媒体服务器的核心。其主要分为如下几个步骤:Init、MainLoop和End。其中MainLoop是一个无限循环,是完成流媒体的整个发布过程。
二、分别介绍获取、转化、播放
Rtsp协议获取rtp数据包:
1. 调用用函数rtsp_connect(./modules/access/rtsp/Rtsp.c)向服务器发出rtsp请求,然后函数rtsp_get_answers将会处理rtsp服务器反馈回来的信息,如果建立成功,则进入下一步。
2. 然后进行建立rtsp交互,依次调用的函数是:rtsp_request_optionsàrtsp_request_describeàrtsp_request_setupàrtsp_request_setparameteràrtsp_request_playàrtsp_request_tearoff,完成建立交互和关闭交互。
3. 详细的是在成功建立之后然后调用的是rtsp_read_data(./modules/access/rtsp/Rtsp.c)函数进行获取不透明的rtp数据实际填充的rtsp_client_t结构体最终实现完成数据的获取。
Rtp数据包的转换:
1. 获取rtp数据之后进行的转换就是yuv格式到rgb格式,使用的文件是 i420_rgb.c(./modules/video_chroma/i420_rgb.c)来是完成视频格式的转换。
2. 首先要对rtp数据流进行解码,调用的函数是Rtp.c(./modules/access/rtp/Rtp.c)对rtp数据流进行demux,实际首先调用rtp_autodetect(./modules/access/rtp/Rtp.c)去探测rtp数据包,然后调用函数codec_decode(./modules/access/rtp/Rtp.c)把rtp数据包发送到decoder线程进行解码。
3. 在codec_decode函数中实际调用的接口是es_out_Control(./include/Vlc_es_out.h)和es_out_Send(./include/Vlc_es_out.h)来完成传送数据包到解码器,然后进入Decode.c(./src/input/Decodec.c)DecodeCreate等函数接口进行流解码。
rgb数据的播放:
1. 在进行图像格式的转换成rgb格式之后由vout_new_buffer(./src/input/Decodec.c)接口实现由解码器送到显示器模块,在显示器通过vout_Request(./src/video_output/video_output.c)接口去获取解码之后的rgb格式的图片或者子图片。
2. 在vout_Request(./src/video_output/video_output.c)接口中如果vout原来存在的话就会进行尝试重使用,通过spu_Attach(./src/video_output/vout_subpictures.c)函数接口进行流单元的附属操作,完成再使用vout。
3. 如果vout不存在的,则转向VoutCreate(./src/video_output/video_output.c)函数接口进行创建vout,在该函数接口调用spu_Create(./include/Vlc_spu.h)进行流单元的创建,最终完成vout的创建,并创建处理线程Thread。
4. 处理线程Thread(./src/video_output/video_output.c)来实际调用ThreadDisplaySubpicture以及结合其他控制函数接口来完成流的控制和播放。
参考资料:vlc官网:http://wiki.videolan.org/Developers_Corner
从接收到数据流到播放视频的过程分析
从网络接收到流->对数据流进行视频和音频分离->对视频用解码器解码->显示解码后的视频流
视频显示部分走势线:分离->解码->新的VOUT缓冲区->VOUT线程
Demux(modules\demux\mpeg\ps.c)->DemuxPs(modules\demux\mpeg\system.c)->ParsePS->input_SelectES(src\input\input_programs.c)->input_RunDecoder(src\input\input_dec.c)->CreateDecoder->
vout_new_buffer->vout_Request(src\video_output\video_output.c)->vout_Create->RunThread->vout_RenderPicture(src\video_output\vout_pictures.c)->pf_display
注意:p_dec->pf_vout_buffer_new =vout_new_buffer的pf_vout_buffer_new在ffmpeg_NewPictBuf(modules\codec\ffmpeg\video.c)函数中激活
解码部分走势线:
Demux(modules\demux\mpeg\ps.c)->DemuxPs(modules\demux\mpeg\system.c)->ParsePS->input_SelectES(src\input\input_programs.c)->input_RunDecoder(src\input\input_dec.c)->CreateDecoder->DecoderThread
注意:在解码线程中对数据流(AUDIO 或者VIDEO)进行解码
详细资料 http://developers.videolan.org/vlc/ VLC API documentation 或者VLC developerdocumentation
Chapter 5. The video outputlayer Data structures and main loop
Important data structures are defined in include/video.h and include/video_output.h.The main data structure is picture_t, which describes everything avideo decoder thread needs. Please refer to this file for moreinformation. Typically, p_data willbe a pointer to YUV planar picture.
Note also the subpicture_t structure. In fact the VLC SPU decoderonly parses the SPU header, and converts the SPU graphical data toan internal format which can be rendered much faster. So a part ofthe "real" SPU decoder lies in src/video_output/video_spu.c.
The vout_thread_t structure is much more complex, but you needn'tunderstand everything. Basically the video output thread manages aheap of pictures and subpictures (5 by default). Every picture hasa status (displayed, destroyed, empty...) and eventually apresentation time. The main job of the video output is an infiniteloop to : [this is subject to change in the near future]
Find the next picture to display in the heap.
Find the current subpicture to display.
Render the picture (if the video output plug-in doesn't support YUVoverlay). Rendering will call an optimized YUV plug-in, which willalso do the scaling, add subtitles and an optional pictureinformation field.
Sleep until the specified date.
Display the picture (plug-in function). For outputs which displayRGB data, it is often accomplished with a bufferswitching. p_vout->p_buffer isan array of two buffers where the YUV transform takes place, andp_vout->i_buffer_index indicates the currentlydisplayed buffer.
Manage events.
Methods used by video decoders
The video output exports a bunch of functions so that decoders cansend their decoded data. The most important functionis vout_CreatePicture whichallocates the picture buffer to the size indicated by the videodecoder. It then just needs to feed (void*) p_picture->p_data withthe decoded data, and call vout_DisplayPicture and vout_DatePicture uponnecessary.
-
picture_t * vout_CreatePicture (vout_thread_t *p_vout, int i_type, int i_width, int i_height) : Returns anallocated picture buffer. i_type willbe for instance YUV_420_PICTURE,and i_width and i_height are in pixels.
WarningIf no picture is available in the heap, vout_CreatePicture willreturn NULL.
vout_LinkPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Increasesthe refcount of the picture, so that it doesn't get accidentlyfreed while the decoder still needs it. For instance, an I or Ppicture can still be needed after displaying to decode interleavedB pictures.
vout_UnlinkPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Decreasesthe refcount of the picture. An unlink must be done for every linkpreviously made.
vout_DatePicture (vout_thread_t *p_vout, picture_t *p_pic ) : Gives thepicture a presentation date. You can start working on a picturebefore knowing precisely at what time it will be displayed. Forinstance to date an I or P picture, you must wait until you havedecoded all previous B pictures (which are indeed placed after -decoding order != presentation order).
vout_DisplayPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Tells thevideo output that a picture has been completely decoded and isready to be rendered. It can be called before orafter vout_DatePicture.
vout_DestroyPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Marks thepicture as empty (useful in case of a stream parsing error).
subpicture_t * vout_CreateSubPicture (vout_thread_t *p_vout, int i_channel, int i_type ) : Returns anallocated subpicture buffer. i_channel isthe ID of the subpicture channel, i_type is DVD_SUBPICTURE or TEXT_SUBPICTURE, i_size isthe length in bytes of the packet.
vout_DisplaySubPicture (vout_thread_t *p_vout, subpicture_t *p_subpic ) : Tells thevideo output that a subpicture has been completely decoded. Itobsoletes the previous subpicture.
vout_DestroySubPicture (vout_thread_t *p_vout, subpicture_t *p_subpic ) : Marks thesubpicture as empty.
- 来源:http://blog.sina.com.cn/s/blog_8795b0970101ew4n.html