嵌入式 vlc从接收到数据流到播放视频的过程分析(经典)
个人整理:
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,MPEG |
|
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, |
|
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(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是一个无限循环,是完成流媒体的整个发布过程。
二、分别介绍获取、转化、播放
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
嵌入式 vlc从接收到数据流到播放视频的过程分析(经典)的更多相关文章
- php接收二进制数据流转换成图片
<?php /** * 图片类 * @author Haroldphp@163.com * @version 1.0 * PHP默认只识别application/x-www.form-urlen ...
- 用vlc SDK创建一个播放视频文件和RTSP流视频的Demo
#include <stdio.h> #include <tchar.h> #include <time.h> #include <windows.h> ...
- Android使用TextureView播放视频
1.引言 如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的TextureView做到. 1).TextureView的兄弟SurfaceView 应用 ...
- WPF播放视频
在现在的项目中需要使用到播放视频的功能,本来打算使用VLC来做的.后来发现WPF 4.0之后新增了MediaElement类,可以实现视频播放. <Grid> <Grid.RowDe ...
- .net利用本地播放器播放视频文件代码
前台点击按钮,执行js事件,跳转到后台代码: function funShowVideo(index) { var iTop = (window.screen.availHeig ...
- MediaPlayer简单使用,绑定surfaceView实现播放视频的功能
转载自 Android MediaPlayer使用方法简单介绍 播放音频 android中播放音频可以使用MediaPlayer类来实现,一下是它的一些方法: 方法名 功能描述 setDataSour ...
- IOS 播放视频 MPMoviePlayerController
在unity游戏的开头播放视频 , 根据需求 , 最后决定用 MPMoviePlayerController 来实现播放, 实现如下: by Tin 需要在AppController.mm的 Open ...
- TextureView+SurfaceTexture+OpenGL ES来播放视频(三)
引自:http://www.jianshu.com/p/291ff6ddc164 做好的Demo截图 opengl-video 前言 讲了这么多,可能有人要问了,播放视频用个android封装的Vid ...
- Atitit.web预览播放视频的总结
Atitit.web预览播放视频的总结 1. 浏览器类型的兼容性(chrome,ff,ie) 1 2. 操作系统的兼容性 1 3. 视频格式的内部视频格式跟播放器插件的兼容性.. 2 4. 指定播放器 ...
随机推荐
- Oracle的“ORA-00937: 不是单组分组函数” 如何解决?
之前在编写oracle的sql语句时遇到这个问题,这里做个记录 问题描述:ORA-00937: 不是单组分组函数 问题原因:select语句中又在查询某一列的值,其中还有聚合函数 原先本人编写SQL是 ...
- <c:forEach>, <c:forTokens> 标签
这些标签封装了Java中的for,while,do-while循环. 相比而言,<c:forEach>标签是更加通用的标签,因为它迭代一个集合中的对象. <c:forTokens&g ...
- Mockito 的用法
本文为博主原创,转载请注明出处: Mockito 是一个基于MIT协议的开源java测试框架. Mockito区别于其他模拟框架的地方主要是允许开发者在没有建立“预期”时验证被测系统的行为.对于moc ...
- 如何更换linux shell中所显示目录的颜色?
答: 往~/.bashrc中加入以下内容即可: LS_COLORS='no=00:fi=00:di=01;33;40:ln=01;36;40:' export LS_COLORS
- git rebase命令
使用git rebase合并多次commit. 当年提交代码后,管理员发现,你的代码不能提交到服务器上,注意原因在于,你的commit中的commit和服务器中的有些commit不在同一时间轴上,即: ...
- Linux下SQL Server安装及数据库迁移
有客户使用Linux服务器,SQL Server从2017开始已支持Linux,从未用过,今天测试了一下,比较简单,记录一下. Linux:CentOS 7.0 首先更新源: curl -o /etc ...
- vue-cli webpack打包开启Gzip 报错—— Cannot find module 'compression-webpack-plugin
异常描述: 复用以前框架,打包的时候报异常提示: Cannot find module 'compression-webpack-plugin" 然后安装插件: npm install -- ...
- (原创)C++ 同步队列
(原创)C++ 同步队列 同步队列作为一个线程安全的数据共享区,经常用于线程之间数据读取,比如半同步半异步线程池的同步队列. 其实做起来比较简单,要用到list.锁和条件变量,条件变量的作用是在队列满 ...
- MSSQL附加数据库时提示以下错误: 无法打开物理文件“***.mdf”。操作系统错误 5:“5(拒绝访问。)”。 (Microsoft SQL Server,错误: 5120)
MSSQL附加数据库时提示以下错误: 无法打开物理文件“***.mdf”.操作系统错误 5:“5(拒绝访问.)”. (Microsoft SQL Server,错误: 5120) ***** 解决方法 ...
- VS找不到头文件但是系统路径已经设置
有时候会出现打不开Include文件的问题,但是在系统包含include路径中已经设置,编译也没问题,就是一直有错误提示 这时候可以尝试在项目上点击右键,选择“下载项目”,然后再选择加载 如果还是不行 ...