源码结构和调用层次

源码结构

从 Github 上拉取最新的源码,目录结构大致如下:

H:\MPV
├─.github
├─audio
│ ├─decode
│ ├─filter
│ └─out
├─ci
├─common
├─demux
├─DOCS
│ └─man
├─etc
├─filters
├─input
├─libmpv
├─misc
├─options
├─osdep
│ ├─android
│ ├─ar
│ ├─macos
│ └─win32
│ └─include
├─player
│ ├─javascript
│ └─lua
├─stream
├─sub
├─ta
├─test
│ └─ref
├─TOOLS
│ ├─lua
│ ├─mpv-osd-symbols.sfdir
│ └─osxbundle
│ └─mpv.app
│ └─Contents
│ ├─MacOS
│ │ └─lib
│ └─Resources
├─video
│ ├─decode
│ ├─filter
│ └─out
│ ├─cocoa
│ ├─cocoa-cb
│ ├─d3d11
│ ├─gpu
│ ├─hwdec
│ ├─opengl
│ ├─placebo
│ ├─vulkan
│ └─win32
└─waftools
├─checks
├─detections
├─fragments
└─generators
  • <libmpv>:这个文件夹内放置了作为 libmpv 链接库所暴露的方法(头文件),具体实现都在别的文件夹里。实际上编译到动态链接库的时候,暴露的方法名都定义在了libmpv/mpv.def里面。但是这个 .def 文件不是标准的导出文件
  • <audio>:顾名思义,音频解码相关的源码。
  • <video>:视频解码、分离、渲染相关的文件,分别在 decode, filter, out 文件夹里。
  • <player>:一个具体的播放器实现,内部调用上面几个部分的模块。
  • wscript:编译脚本。新添加的文件要由此加入到编译流程中。

内部调用层次

初始化核心上下文

如果是启动播放器进行播放,则首先会进行一个内部状态的初始化,主要是初始化了MPContext这个结构体。这个结构体是一个大杂烩,所有播放相关的参数、动态变化的属性都绑定到这上面。然后内核进入 idle 状态,等待播放视频。

初始化渲染驱动

打开第一个媒体文件的时候,会开始进行视频/音频播放链路(video_output_chain)初始化,其中就包括初始化解码和渲染模块。渲染模块由结构体 vo_driver 定义,(mpv 内部使用结构体来定义接口),例如 vo_gpu 的定义如下:

const struct vo_driver video_out_gpu = {
.description = "Shader-based GPU Renderer",
.name = "gpu",
.caps = VO_CAP_ROTATE90,
.preinit = preinit,
.query_format = query_format,
.reconfig = reconfig,
.control = control,
.get_image = get_image,
.draw_frame = draw_frame,
.flip_page = flip_page,
.get_vsync = get_vsync,
.wait_events = wait_events,
.wakeup = wakeup,
.uninit = uninit,
.priv_size = sizeof(struct gpu_priv),
.options = options,
};

接下来我们都以这个 Windows 下最常用的 vo 驱动器——vo_gpu 为例。在 /video/out/vo.c 中,你可以看到所有支持的 vo_driver:

const struct vo_driver *const video_out_drivers[] =
{
&video_out_libmpv,
#if HAVE_ANDROID
&video_out_mediacodec_embed,
#endif
&video_out_gpu,
#if HAVE_VDPAU
&video_out_vdpau,
#endif
...省略多个driver

Mpv 会根据系统、编译情况、传入参数决定使用哪个具体的视频输出驱动。之后,调用该驱动的preinit方法。对于 vo_gpu 来说,它的下层还依赖于不同的 render_context,对应了在不同系统环境上的渲染接口。这也是 Mpv 跨平台兼容的关键。所有 gpu 支持的渲染接口定义在 video/out/gpu/context.c

static const struct ra_ctx_fns *contexts[] = {
#if HAVE_D3D11
&ra_ctx_d3d11,
#endif // OpenGL contexts:
#if HAVE_EGL_ANDROID
&ra_ctx_android,
#endif
#if HAVE_RPI
&ra_ctx_rpi,
#endif
#if HAVE_GL_COCOA
&ra_ctx_cocoa,
#endif
#if HAVE_EGL_ANGLE_WIN32
&ra_ctx_angle,
#endif
#if HAVE_GL_WIN32
&ra_ctx_wgl,
#endif
...省略大量接口
};

每个底层接口都由结构体 ra_ctx_fns 定义。这个结构体暴露了一组用于配置的具体方法:

const struct ra_ctx_fns ra_ctx_d3d11 = {
.type = "d3d11",
.name = "d3d11",
.reconfig = d3d11_reconfig,
.control = d3d11_control,
.init = d3d11_init,
.uninit = d3d11_uninit,
};

因此在 gpu 渲染驱动的 preinit 函数中一大任务就是调用具体渲染接口的 init 方法。

视频播放循环

视频、音频播放驱动初始化完毕后,就开始视频播放。整个播放的流程(render loop)如下伪代码:

for video in Videos {
while(1) {
render_frame(video);
wait for next frame;
}
}

对的,就是这么简单粗暴。这里有意忽略了时间同步、音视频同步等具体细节,实际上 Mpv 内部大量依赖于锁和信号量进行线程间同步。

TL;DR

总结一下,一个初始化的流程涉及如下接口的调用:

  • MPContext 初始化
  • vo_driver 初始化
  • render_backend 初始化(即特定的、与系统环境相关的底层接口)

下一篇文章,我们顺着官方播放器的具体代码,看看 Mpv 具体初始化了哪些东西,并试图捋清楚 libmpv 又是如何进行初始化的。

MPV源码探究:源码结构和调用层次的更多相关文章

  1. Vue源码探究-源码文件组织

    Vue源码探究-源码文件组织 源码探究基于最新开发分支,当前发布版本为v2.5.17-beta.0 Vue 2.0版本的大整改不仅在于使用功能上的优化和调整,整个代码库也发生了天翻地覆的重组.可见随着 ...

  2. Vue源码探究-状态初始化

    Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...

  3. spring-cloud-sleuth+zipkin源码探究

    1. spring-cloud-sleuth+zipkin源码探究 1.1. 前言   粗略看了下spring cloud sleuth core源码,发现内容真的有点多,它支持了很多类型的链路追踪, ...

  4. Vue源码探究-虚拟DOM的渲染

    Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue ...

  5. ConcurrentHashMap源码探究 (JDK 1.8)

    很早就知道在多线程环境中,HashMap不安全,应该使用ConcurrentHashMap等并发安全的容器代替,对于ConcurrentHashMap也有一定的了解,但是由于没有深入到源码层面,很多理 ...

  6. WebViewJavascriptBridge源码探究--看OC和JS交互过程

    今天把实现OC代码和JS代码交互的第三方库WebViewJavascriptBridge源码看了下,oc调用js方法我们是知道的,系统提供了stringByEvaluatingJavaScriptFr ...

  7. MySQL源码分析以及目录结构 2

    原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...

  8. MySQL源码分析以及目录结构

    原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...

  9. storm源码之storm代码结构【译】【转】

    [原]storm源码之storm代码结构[译]  说明:本文翻译自Storm在GitHub上的官方Wiki中提供的Storm代码结构描述一节Structure of the codebase,希望对正 ...

随机推荐

  1. Spring Data Jpa的四种查询方式

    一.调用接口的方式 1.基本介绍 通过调用接口里的方法查询,需要我们自定义的接口继承Spring Data Jpa规定的接口 public interface UserDao extends JpaR ...

  2. Selenium+Java(九)Selenium键盘与鼠标事件

    一.键盘事件 ctrl+a driver.findElement(By.id("kw")).sendKeys(Keys.CONTROL, "a"); ctrl+ ...

  3. 部署 kube-controller-manager 高可用集群

    目录 前言 创建kube-controller-manager证书和私钥 生成证书和私钥 将生成的证书和私钥分发到所有master节点 创建和分发kubeconfig文件 分发kubeconfig到所 ...

  4. 对python的初步了解

    一,Python简介 Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具 ...

  5. mysql那些事(5)建表存储引擎的选择

    在mysql见表的时候,会遇到选择存储引擎:MyISAM和InnoDB.究竟用哪种存储引擎好呢? 1.MyISAM:表锁:支持全文索引:读并发性能较好. 2.InnoDB:行锁:支持事务,支持外键:写 ...

  6. IDEA的控制台拖拽出来之后,如何恢复?

    大家搜到这个的时候,肯定遇到了如下图展示的尴尬情况,我们的控制台在不小心之间被拖拽出来,然后不知如何再拖回去?放心,我来告诉你怎么办. 点击左下角的  恢复按钮 就可以了.

  7. 通过哪吒动漫豆瓣影评,带你分析python爬虫与BeautifulSoup快速入门【华为云技术分享】

    久旱逢甘霖 西安连着几天温度排行全国三甲,也许是<哪吒之魔童降世>的剧组买通了老天,从踩着风火轮的小朋友首映开始,就全国性的持续高温,还好今天凌晨的一场暴雨,算是将大家从中暑边缘拯救回来了 ...

  8. 学习索引结构的一些案例——Jeff Dean在SystemML会议上发布的论文(下)

    [摘要] 除了范围索引之外,点查找的Hash Map在DBMS中起着类似或更重要的作用. 从概念上讲,Hash Map使用Hash函数来确定性地将键映射到数组内的随机位置(参见图[9 ],只有4位开销 ...

  9. 在Linux中配置jdk,Tomcat,MySQL

    解压缩: tar 命令 : 使用方式 tar [参数] source [target] source - 压缩文件 target - 解压缩后的目标位置, 默认解压到当前目录 常用写法 : 解压缩 : ...

  10. Oracle:row_number()、rank()、dense_rank()

    语法:ROW_NUMBER()  OVER(): row_number的用途非常广泛,排序最好用它,它会为查询出来的每一行记录生成一个序号,依次排序且不会重复,注意使用row_number函数时必须要 ...