嵌入式 vlc从接收到数据流到播放视频的过程分析(经典)

我的整理:html

Vlc流播放流程web

 vlc源码目录树:shell

目录名称macos

说明vim

bindings服务器

Java, CIL 和Python绑定网络

docsocket

帮助文档 (不是更新的)tcp

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,MPEG I-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使用的其余部分功能,如线程系统,消息队列等.

 

1、首先介绍一下vlc启动动态加载模块的过程

 

1. 最早程序段入口是文件Vlc.c(./bin/)中的main()函数完成的Functions(parse command line, start interface and spawn threads),在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是一个无限循环,是完成流媒体的整个发布过程。

2、分别介绍获取、转化、播放

 

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 developer documentation

Chapter 5.  The video output layer 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 a video decoder thread needs. Please refer to this file for more information. Typically, p_data will be a pointer to YUV planar picture.

Note also the subpicture_t structure. In fact the VLC SPU decoder only parses the SPU header, and converts the SPU graphical data to an internal format which can be rendered much faster. So a part of the "real" SPU decoder lies in src/video_output/video_spu.c.

The vout_thread_t structure is much more complex, but you needn't understand everything. Basically the video output thread manages a heap of pictures and subpictures (5 by default). Every picture has a status (displayed, destroyed, empty...) and eventually a presentation time. The main job of the video output is an infinite loop 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 YUV overlay). Rendering will call an optimized YUV plug-in, which will also do the scaling, add subtitles and an optional picture information field.

  • Sleep until the specified date.

  • Display the picture (plug-in function). For outputs which display RGB data, it is often accomplished with a buffer switching. p_vout->p_buffer is an array of two buffers where the YUV transform takes place, and p_vout->i_buffer_index indicates the currently displayed buffer.

  • Manage events.

Methods used by video decoders

The video output exports a bunch of functions so that decoders can send their decoded data. The most important function is vout_CreatePicture which allocates the picture buffer to the size indicated by the video decoder. It then just needs to feed (void *) p_picture->p_data with the decoded data, and call vout_DisplayPicture and vout_DatePicture upon necessary.

  • picture_t * vout_CreatePicture ( vout_thread_t *p_vout, int i_type, int i_width, int i_height ) : Returns an allocated picture buffer. i_type will be for instance YUV_420_PICTURE, and i_width and i_height are in pixels.

    Warning

    If no picture is available in the heap, vout_CreatePicture will return NULL.

  • vout_LinkPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Increases the refcount of the picture, so that it doesn't get accidently freed while the decoder still needs it. For instance, an I or P picture can still be needed after displaying to decode interleaved B pictures.

  • vout_UnlinkPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Decreases the refcount of the picture. An unlink must be done for every link previously made.

  • vout_DatePicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Gives the picture a presentation date. You can start working on a picture before knowing precisely at what time it will be displayed. For instance to date an I or P picture, you must wait until you have decoded 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 the video output that a picture has been completely decoded and is ready to be rendered. It can be called before or after vout_DatePicture.

  • vout_DestroyPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Marks the picture 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 an allocated subpicture buffer. i_channel is the ID of the subpicture channel, i_type is DVD_SUBPICTURE or TEXT_SUBPICTURE, i_size is the length in bytes of the packet.

  • vout_DisplaySubPicture ( vout_thread_t *p_vout, subpicture_t *p_subpic ) : Tells the video output that a subpicture has been completely decoded. It obsoletes the previous subpicture.

  • vout_DestroySubPicture ( vout_thread_t *p_vout, subpicture_t *p_subpic ) : Marks the subpicture as empty.

  • 来源:http://blog.sina.com.cn/s/blog_8795b0970101ew4n.html