ubuntu18.04 编译Firefox以及HTML5多媒体框架简要分析

准备环境

安装python3,curl

sudo apt-get install python3 python3-dev curl

安装版本管理工具:

firefox使用Mercurial进行版本管理代码,所以下载代码前,必须先安装Mercurial

sudo python3 -m pip install --user mercurial

安装curl,下载准备文件bootstrap.py

curl https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py -O

执行python安装脚本

选择编译模式1.

这里有四个选择项,其中3,4项是以android为后端,编译运行于安卓平台的firefox用的,这里不选择。

那问题是1,2有什么区别,实际上,如果选择1,是基于社区预编译的很多pre-build库的基础上进行的增量编译,所以编译会很快就会完成,如果选择2,则会编译完整的源代码,会比较慢一些。

感谢万能的mozilla开发社区,助我解决了这个问题:

快速模式编译:

进入firefox/mozilla-unified目录,打开mozconfig文件

当ac_add_options --enable-artifact-builds打开时,使用的是快速编译模式,会使用pre-build的库。

执行./mach build 编译

运行:

执行 ./mach run

本地模式编译:

如果想完整编译Firefox所有代码,可以将ac_add_options --enable-artifact-build注释,重新执行相同的命令编译。

在我的PC(I7 8核),用时不到43分钟编译完成,比编译chromium节省不少时间,以我的PC为例,编译chromium至少要三个小时了,最郁闷的是还需要和谐上网.

再次运行测试

有些同学可能觉得奇怪,怎么Help显示的是Nightly不是Firefox, 而且图标也不对。这不是一个正经的Firefox,尤其是和下图正经的版本相比,看起来有很大差异:

实际上,nightly是firefox的测试版本 每天更新的 所以叫nightly,翻译过来就是每夜版,上图中显示的是今天的时间,也说明了它是每天更新的.

题外话:

Firefox分为四个通道,Nightly,Aurora,Beta和Release,Nightly是其中更新最快、新功能最多,也是最不稳定的一个版本。不建议日常用户使用,想要尝鲜可以尝试Beta或Aurora。

注意:如果执行python3 bootstrap.py过程中,在快结束的时候中断,可以执行 

sudo ./mach bootstrap

恢复配置过程.

在执行python3 bootstrap.py的过程中,会调用apt install安装很多的工具,无法一一列出,印象比较深刻的是rust编译器rustc,由于greatwall的原因,安装rustc颇费周折.

这中间还遇到一个_bz2的问题,原因和python3.6,python3.7版本有关,执行sudo cp /usr/lib/python3.6/lib-dynload/_bz2.cpython-36m-x86_64-linux-gnu.so /usr/local/lib/python3.7/lib-dynload/_bz2.cpython-37m-x86_64-linux-gnu.so解决.

也可以执行:

sudo make clean

sudo make

来进行编译,实际上是对./mach clobber和./mach build的封装.

测试HTML5 Video标签播放器:

FireFox上的多媒体框架

1.打开mozilla-unified/media/ffvpx/libavutil/hwcontext.c文件,可以看到const HWContextType类型的hw_table数组的定义,在这个数组里面,定义了硬解加速API的种类,他们分别是:

经过追踪,在hw_table数组中,只定义了一个成员,它是CONFIG_VAAPI配置定义的ff_hwcontext_type_vaapi.

为什么使用VAAPI呢? VAAPI的定义者是intel,由于Intel在桌面PC处理器的领袖地位,大部分的Intel处理器使用了内置的GPU。VAAPI就是对Intel集成GPU的一次封装。如果使用的是外置Nvida卡,可能这里就变成VDPAU了,VDAPU是Nvidia定义的。

修改vaapi_transfer_data_to和vaapi_transfer_data_from,加入调试打印,观察H5播放器是否会走这里。

重新编译验证,video tag解码MP4和OGG视频,发现打印并没有出现,MP4封装的应该是H264视频,莫非解码并没有使用VAAPI硬解?继续验证

一个重要的类出现了,class FFmpegDataDecoder是一个模板类,模板类型为LIBAV_VER,看起来像是和FFMPEG版本有关。

       如上图,在解码的必经之路Decode成员函数中加入打印,观察会不会被调用,编译后运行HTML5测试用例,可以看到Decode函数被调用了,这就是Firefox使用FFMPEG实现的HTML5 Video特性的最直接证明。

在完整视频解码路径上添加打印:

编译,测试:

一开始,我根据 mLib->avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet);这一行调用找到了mozilla-unified/media/ffvpx/libavcodec/decode.c文件中的同名解码函数并加入了调试打印,测试后发现并没有进来。

后来经过分析代码,才发现实际上的解码器是基于动态加载的方式导入的,通过dlopen,dlclose,dlfind函数寻找到对应的符号,由于使用的是pre-build库,所以当然找不到调用路径了。通过将name打印出来,可以看到实际调用函数所在的动态库文件。

从上图还可以看出,调用dlopen过程中会进行某种启发式尝试,例如,很显然libavcodec-ffmpeg.so.*表示的几个库打不开,dlopen返回的句柄为空,成功打开的解码动态库libmozavcodec.so.很可能就是解码器decoder,我们一会儿验证下,首先看一下启动的firefox进程地址空间是否包含我们关心的几个库。

都知道chromium是多进程模式,实际上最新的Firefox也支持这种模式,Firefox浏览器57版本之后默认开启多进程,刚刚编译出的Nightly就支持多进程,如下图 pidof的结果。

第一个和第二个命令输出是./mach run启动Firefox后Blank页面状态的进程列表。第三个命令是在播放HTML5视频的时候抓取的济南城列表,可以看到多出来5345和5293两个进程,我们看一下他们俩的MAP:

可以看到进程5293的地址空间中出现了两个库的映射,分别是ffmpeg的decoder和parser.

都走到这一步了,索性就走到底,我们查找一下libmozavcodec.so的符号表,看是否有avcodec_decode_video2这个函数:

证据链条都已经连接起来,可以说是铁证如山,Firefox坏的很,它不但包养了FFMPEG,还不断用生娃的方式(创建新的播放子进程)要求她播放小电影!简直坏透了。

经过分析,可以抽象出的Firefox浏览器播放框架如下图示:

感谢万能的社区,让我了解了Firefox对FFMPEG使用的一些细节,Firefox仅仅使用了FFMPEG框架中的核心部分,比如parser和avcodec部分,并不是全部ffmpeg代码都有用,如下图对话说明:

由于H264版权原因,Firefox并未ship H264的codec源码,而是用pre-build的libmozavcodec.so实现这类版权格式的解码的。但是对于vp8/vp9这类没有版权限制的格式则没有这些限制,所以如果需要debug解码路径,最好选择用vp8/vp9格式的视频.

接下来我们验证一下是否如他所说,VP9格式使用Firefox Native源码解码的:VP9的码源比较少,我们按照这篇文章介绍的方法先将测试的H264视频进行转码成VP9格式。

之后,编写HTML文档:

<!DOCTYPE html>
<html>
<head> 
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title> 
</head>
<body>

<video width="320" height="240" controls>
  <source src="vp9movie_libvpx.mp4" type="video/mp4">
  <source src="movie.ogg" type="video/ogg">
  您的浏览器不支持 HTML5 video 标签。
</video>

</body>
</html>

在VP9解码的必经之路上加入打印信息:

貌似走的还是原来的路径,原因未知,后面再查。

总结:

最后做一下总结,Firefox的多媒体框架使用的是FFMPEG,另外主流的chromium用的也是ffmpeg作为多媒体框架.webitkitgtk不同,webkit基于gstreamer搭建多媒体框架,gstreamer下面可以加OMX IL层作解码加速,当然也可以使用gst-libav插件将ffmpeg封装为gst-plugin的形式加以使用.

所以可以看出,三大主流的浏览器引擎的多媒体组件都和ffmpeg有关,ffmpeg的重要性不言而喻.


参考资源:

https://firefox-source-docs.mozilla.org/contributing/build/artifact_builds.html#understanding-artifact-builds

https://firefox-source-docs.mozilla.org/setup/linux_build.html

https://firefox-source-docs.mozilla.org/contributing/debugging/debugging_firefox_with_gdb.html

https://firefox-source-docs.mozilla.org/contributing/contribution_quickref.html

和padenot沟通发给我的两个链接,看了一下,是关于多媒体codec硬件加速的,有时间看一下:

https://bugzilla.mozilla.org/show_bug.cgi?id=1572697

https://bugzilla.mozilla.org/show_bug.cgi?id=1610199

WebKitGtk:

https://www.xitongjiaocheng.com/ubuntu/2018/64679.html

https://trac.webkit.org/wiki/BuildingGtk


结束!

猜你喜欢

转载自blog.csdn.net/tugouxp/article/details/116097011