深入理解VLC(一)纵观全局
VLC系列文章
深入理解VLC之代码流程
VLC,著名的开源播放器项目,它虽然很庞大,但是在架构设计上也高度模块化。幸运的是,官方wiki非常详细,无论是大的架构设计,还是每一个模块里面的代码细节,都有详尽的介绍。wiki链接:https://wiki.videolan.org/Hacker_Guide/。
本文主要以vlc-android项目为例,介绍vlc的架构设计,参考了一篇对vlc架构分析得很好的文章:https://jiya.io/archives/vlc_learn_2.html
1. 代码结构
下载vlc-android项目代码并编译之后,得到主要目录结构如下
libvlc jni层以及java api
medialibrary 媒体数据库相关的代码
vlc native代码,后面分析的重点
vlc-android 应用的代码,编出来的apk就在vlc-andoird/debug目录下
在介绍vlc目录下的代码结构之前,先来说一下vlc的架构设计:
vlc的架构设计可以分作两层:
第一层是对整条播放通路(pipeline)的抽象,包含以下几个抽象概念
playlist: playlist表示播放列表,VLC在启动后,即创建一个playlist thread,用户输入后,动态创建input。
input: input表示输入,当用户通过界面输入一个文件或者流地址时,input thread 被动态创建,该线程的生命周期直到本次播放结束。
access: access表示访问,是VLC抽象的一个层,该层向下直接使用文件或网络IO接口,向上为stream层服务,提供IO接口。
stream: stream表示流,是VLC抽象的一个层,该层向下直接使用access层提供的IO接口,向上为demux层服务,提供IO接口。
demux: demux表示解复用,该层向下直接使用stream层提供的IO接口,数据出来后送es_out。
es_out: es_out表示输出,是VLC抽象的一个层,该层获取demux后的数据,送decode解码。
decode: decode表示解码,是视频技术中的概念,获取es_out出来的数据(通过一个fifo交互),解码后送output。
output: output表示输出,获取从decode出来的数据,送readerer。
readerer: readerer表示显示,获取从output出来的数据(通过一个fifo交互),然后显示。
第二层是对播放通路中每一个环节,都提供了诸多可选的module,例如decode,就同时提供了包含ffmpeg软解以及android mediacodec硬解在内的多个可选解码module。
在播放流程开始后,就按照平台、媒体格式选择合适的module,当然,我们也可以设置参数强制要求使用某些module。
有了以上概念之后,再来看vlc目录下的主要代码结构,如下(参考https://wiki.videolan.org/VLC_source_tree/)
.
├──contrib 依赖库相关,所有依赖库列表参见https://wiki.videolan.org/Contrib_Status
│ ├── arm-linux-androideabi build之后的依赖库
│ ├── contrib-android-arm-linux-androideabi 依赖库代码
│ ├── src 依赖库的patch和makefile
│ └── tarballs 下载的依赖库tar包
├── lib libvlc的api
├── modules 各个模块的代码
│ ├── access
│ ├── audio_filter audio resample与格式转换
│ ├── audio_output audio输出,包含android audiotrack与opensl等
│ ├── codec
│ ├── demux
│ ├── text_renderer 文本绘制
│ ├── video_chroma 视频颜色格式转换
│ ├── video_filter 视频filter,如deinterlace,还包含一些滤镜,如老电影效果
│ ├── video_output 视频输出,包含android nativewindow,opengl等
├── src
├── android Android平台相关代码
├── audio_output 初始化audio mixer,从decoder拿到audio frames处理后输出
├── config 命令行参数解析
├── input
├── interface UI相关
├── linux linux 平台相关代码
├── misc 杂项,包含消息队列,picture fifo, mime type, cpu检测等功能的代码
├── modules module的选择与加载
├── network 网络通信相关
├── playlist 播放列表相关
├── stream_output vlc不仅是一个播放器,还能做推流,这里是推流相关代码
├── text 文本相关,如字符编码等
├── video_output 从decoder拿到视频帧和字幕,处理后输出
2. Java API使用
vlc也提供了一套MediaPlayer的API,但是没有按照原生Android的MediaPlayer接口进行封装,所以用起来会比较别扭,需要重新封装一下。使用方法可以参考https://code.videolan.org/videolan/libvlc-android-samples.git
import org.videolan.libvlc.IVLCVout;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;mLibVLC = new LibVLC(this, args);//设置启动参数
mMediaPlayer = new MediaPlayer(mLibVLC);
final IVLCVout vlcVout = mMediaPlayer.getVLCVout();
vlcVout.setVideoView(mVideoSurface);//设置视频显示surface
vlcVout.setSubtitlesView(mSubtitlesSurface);//设置字幕显示surface
vlcVout.attachViews(this);//设置IVLCVout.OnNewVideoLayoutListener的回调,注意:想要使用ANativeWindow的话,这里必须注册回调
final Media media = new Media(mLibVLC, getAssets().openFd(ASSET_FILENAME));
mMediaPlayer.setMedia(media);//相当于setdatasource
media.release();
mMediaPlayer.play();//停止播放
mMediaPlayer.stop();
mMediaPlayer.getVLCVout().detachViews();
mMediaPlayer.release();
mLibVLC.release();//设置显示窗口的size,宽高比,scale
mMediaPlayer.getVLCVout().setWindowSize(sw, sh);
mMediaPlayer.setAspectRatio("16:9");
mMediaPlayer.setScale(0);
3. 线程模型
在前面提到的参考文献中有一张很经典的图,如下
vlc中的线程都是通过vlc_clone_attr方法来创建,我们可以给这个方法加上一个线程名参数,方便调试,如下
src/android/thread.c
static int vlc_clone_attr (vlc_thread_t *th, void *(*entry) (void *),void *data, bool detach, const char* threadName /*线程名*/)
{vlc_thread_t thread = malloc (sizeof (*thread));...pthread_attr_t attr;pthread_attr_init (&attr);pthread_attr_setdetachstate (&attr, detach ? PTHREAD_CREATE_DETACHED: PTHREAD_CREATE_JOINABLE);ret = pthread_create (&thread->thread, &attr,detach ? detached_thread : joinable_thread, thread);pthread_attr_destroy (&attr);pthread_setname_np(thread->thread, threadName); //设置线程名pthread_sigmask (SIG_SETMASK, &oldset, NULL);*th = thread;return ret;
}
我自己加了一些线程名之后,播放一个流,用adb shell debuggerd -b 看一下都有哪些线程,如下
vlc-input: 即input thread
vlc-fetcher: 即playlist的FetcherThread
vlc-videooutput: 即src/video_output/video_output.c中的
static void *Thread(void *object)
{vout_thread_t *vout = object;vout_thread_sys_t *sys = vout->p;msg_Dbg(vout, "video output tid is %u", syscall(SYS_gettid));mtime_t deadline = VLC_TS_INVALID;bool wait = false;for (;;) {vout_control_cmd_t cmd;if (wait){const mtime_t max_deadline = mdate() + 100000;deadline = deadline <= VLC_TS_INVALID ? max_deadline : __MIN(deadline, max_deadline);} else {deadline = VLC_TS_INVALID;}while (!vout_control_Pop(&sys->control, &cmd, deadline))if (ThreadControl(vout, cmd))return NULL;deadline = VLC_TS_INVALID;wait = ThreadDisplayPicture(vout, &deadline) != VLC_SUCCESS;const bool picture_interlaced = sys->displayed.is_interlaced;vout_SetInterlacingState(vout, picture_interlaced);vout_ManageWrapper(vout);}
}
NDK MediaCodec_:即NDK MediaCodec的线程
CodecLooper: 即stagefright中MediaCodec的线程
vlc-decoder: 即视频对应的DecoderThread,在src/input/decoder.c中
android_audiotrack:即音频对应的DecoderThread,其实也是个vlc-decoder,不过在modules/audio_output/audiotrack.c中调用android_getEnv,即AttachCurrentThread后线程名变了而已
AudioTrack:即framework的audiotrack线程
vlc-audiotrack:即音频输出线程,对应modules/audio_output/audiotrack.c中的AudioTrack_Thread
可以看到,和上面图片所描述的一致。
关注公众号,掌握更多安卓、多媒体领域知识与资讯,开启精彩程序人生
文章帮到你了?可以扫描如下二维码进行打赏,打赏多少您随意~
深入理解VLC(一)纵观全局相关推荐
- 《数据分析变革:大数据时代精准决策之道》一2.3 纵观全局看待大数据
本节书摘来自异步社区<数据分析变革:大数据时代精准决策之道>一书中的第2章,第2.3节,作者[美]Bill Franks(比尔•弗兰克斯),更多章节内容可以访问云栖社区"异步社区 ...
- 【机器学习笔记】- 纵观全局 监督学习中的4个重要内容:模型、Loss/Cost、目标和优化
[机器学习笔记]- 纵观全局 监督学习中的4个重要内容:模型.Loss/Cost.目标和优化 监督学中的4个重要内容:模型.Loss/Cost.目标.优化 发现想做数据分析,除了要学习概率统计,也真的 ...
- 深入理解Python中的全局解释锁GIL
深入理解Python中的全局解释锁GIL 转自:https://zhuanlan.zhihu.com/p/75780308 注:本文为蜗牛学院资深讲师卿淳俊老师原创,首发自公众号https://mp. ...
- 《ANTLR 4权威指南》——第2章纵观全局
本节书摘来自华章社区<ANTLR 4权威指南>一书中的第2章纵观全局,作者[美] 特恩斯·帕尔(Terence Parr),更多章节内容可以访问云栖社区"华章社区"公众 ...
- Xcode江湖录-第02章 纵观全局——布局探索
第02章 纵观全局--布局探索 2.1 工作区 Xcode工作区:由上到下,由左到右依次有:工具栏-[导航器区域-编辑器区域-工具区域]-调试区域: 1:工具栏从左到右依次有: 1.1:运行按钮(可以 ...
- Zookeeper研究系列之纵观全局
架构图 用途 ZooKeeper is a centralized service for maintaining configuration information, naming, providi ...
- 【Tensorflow入门教程一】纵观全局:tensorflow各函数块解析。
作为深度学习的最热门工具之一,Tensorflow可以为我们的模型搭建以及数据运算带来极大的便利.作为一门工具,必不可少地是要对它有一个全局的了解.私以为,如果对它的整体的模块架构有一个了解的话,再结 ...
- 机房收费系统之纵观全局
验收项目的时候,师父们从四方面进行了审核:界面.功能.代码.业务.之后师父布置了三项任务:用自己的理解将一般用户.操作员还有管理员的主要职能搞清楚:将本系统的主要功能化成流程图:"谈钱不伤系 ...
- 纵观全局,洞察未来物联网转型空间 | 洞见物联网
迈入虎年,各行各业正在以万分活力投入复工复产之中."虎"寓意着压倒一切.所向无敌的威力,在充满不确定性的时代,更需要我们铆足"虎"力来迎接变局中诸多挑战与机遇. ...
最新文章
- 台式计算机无线设置,台式电脑怎么设置无线网络?
- 征战蓝桥 —— 2014年第五届 —— C/C++A组第3题——神奇算式
- 国内芯片60个细分领域重要代表企业【收藏】
- ENVI扩展工具:利用波段运算修改NaN方法总结
- Qt使用invokeMethod反射机制实现进程间的通信
- arcgis栅格邻域统计_地理工具学习--arcgis篇:单工具学习(14)
- RTOS原理与实现05:事件控制块实现
- 谁该为马化腾表态这个乌龙尴尬?
- 中文问题-Mobile-UrlEncode
- 在Win10系统的服务器上离线安装SQL Server 2012中出现“启用windows功能NetFx3时出错”
- ADS仿真遇到error如何查找原因
- BUUCTF-Misc-No.3
- 进程调度之5:系统调用exit与wait4
- 怎么检测计算机硬件好坏,鲁大师如何检测硬件好坏?硬件好坏检测方法介绍
- html滚动图片代码加文字,HTML代码制作滚动文字
- 《见识》吴军——读后感
- 基于安卓的毕业设计题目推荐
- Matlab中plot画图线型、标记和颜色
- arcgis像元大小和分辨率_ArcGIS教程:栅格像元大小和重采样
- 25_类和面向对象的概念