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(一)纵观全局相关推荐

  1. 《数据分析变革:大数据时代精准决策之道》一2.3 纵观全局看待大数据

    本节书摘来自异步社区<数据分析变革:大数据时代精准决策之道>一书中的第2章,第2.3节,作者[美]Bill Franks(比尔•弗兰克斯),更多章节内容可以访问云栖社区"异步社区 ...

  2. 【机器学习笔记】- 纵观全局 监督学习中的4个重要内容:模型、Loss/Cost、目标和优化

    [机器学习笔记]- 纵观全局 监督学习中的4个重要内容:模型.Loss/Cost.目标和优化 监督学中的4个重要内容:模型.Loss/Cost.目标.优化 发现想做数据分析,除了要学习概率统计,也真的 ...

  3. 深入理解Python中的全局解释锁GIL

    深入理解Python中的全局解释锁GIL 转自:https://zhuanlan.zhihu.com/p/75780308 注:本文为蜗牛学院资深讲师卿淳俊老师原创,首发自公众号https://mp. ...

  4. 《ANTLR 4权威指南》——第2章纵观全局

    本节书摘来自华章社区<ANTLR 4权威指南>一书中的第2章纵观全局,作者[美] 特恩斯·帕尔(Terence Parr),更多章节内容可以访问云栖社区"华章社区"公众 ...

  5. Xcode江湖录-第02章 纵观全局——布局探索

    第02章 纵观全局--布局探索 2.1 工作区 Xcode工作区:由上到下,由左到右依次有:工具栏-[导航器区域-编辑器区域-工具区域]-调试区域: 1:工具栏从左到右依次有: 1.1:运行按钮(可以 ...

  6. Zookeeper研究系列之纵观全局

    架构图 用途 ZooKeeper is a centralized service for maintaining configuration information, naming, providi ...

  7. 【Tensorflow入门教程一】纵观全局:tensorflow各函数块解析。

    作为深度学习的最热门工具之一,Tensorflow可以为我们的模型搭建以及数据运算带来极大的便利.作为一门工具,必不可少地是要对它有一个全局的了解.私以为,如果对它的整体的模块架构有一个了解的话,再结 ...

  8. 机房收费系统之纵观全局

    验收项目的时候,师父们从四方面进行了审核:界面.功能.代码.业务.之后师父布置了三项任务:用自己的理解将一般用户.操作员还有管理员的主要职能搞清楚:将本系统的主要功能化成流程图:"谈钱不伤系 ...

  9. 纵观全局,洞察未来物联网转型空间 | 洞见物联网

    迈入虎年,各行各业正在以万分活力投入复工复产之中."虎"寓意着压倒一切.所向无敌的威力,在充满不确定性的时代,更需要我们铆足"虎"力来迎接变局中诸多挑战与机遇. ...

最新文章

  1. 台式计算机无线设置,台式电脑怎么设置无线网络?
  2. 征战蓝桥 —— 2014年第五届 —— C/C++A组第3题——神奇算式
  3. 国内芯片60个细分领域重要代表企业【收藏】
  4. ENVI扩展工具:利用波段运算修改NaN方法总结
  5. Qt使用invokeMethod反射机制实现进程间的通信
  6. arcgis栅格邻域统计_地理工具学习--arcgis篇:单工具学习(14)
  7. RTOS原理与实现05:事件控制块实现
  8. 谁该为马化腾表态这个乌龙尴尬?
  9. 中文问题-Mobile-UrlEncode
  10. 在Win10系统的服务器上离线安装SQL Server 2012中出现“启用windows功能NetFx3时出错”
  11. ADS仿真遇到error如何查找原因
  12. BUUCTF-Misc-No.3
  13. 进程调度之5:系统调用exit与wait4
  14. 怎么检测计算机硬件好坏,鲁大师如何检测硬件好坏?硬件好坏检测方法介绍
  15. html滚动图片代码加文字,HTML代码制作滚动文字
  16. 《见识》吴军——读后感
  17. 基于安卓的毕业设计题目推荐
  18. Matlab中plot画图线型、标记和颜色
  19. arcgis像元大小和分辨率_ArcGIS教程:栅格像元大小和重采样
  20. 25_类和面向对象的概念

热门文章

  1. 搜索引擎百度/360/搜狗关键词搜索提交信息
  2. C语言动态数组(malloc()函数动态分配内存)
  3. 亲密关系沟通-【边界感】-梳理边界感的沟通方法
  4. 数据资产化建设的思考与实践
  5. 冰原服务器维护,12月23日(周四)服务器更新维护公告
  6. curl下载脚本并执行
  7. python 定时自动爬取_python怎么定时爬取数据及将数据以邮件发送
  8. JS中创建、添加、删除节点
  9. jQuery 控制页面
  10. java 判断字符串包含几个字符_java中如何判断一个字符串包含几个指定字符