软路由折腾记

记录一下折腾的踩坑记录,日后防坑用。

软路由

用旧电脑或者工控机运行路由器系统的设备,硬件现在有很多定制的,系统一般是一层虚拟机上运行openwrt的某个定制版本,虚拟机还可以装nas系统,实现家庭影院系统,离线下载等功能。
注意:如果要支持4k UHD解码对硬件有要求,可以参考plex对各大厂Nas的测试结果https://docs.google.com/spreadsheets/d/1MfYoJkiwSqCXg8cm5-Ac4oOLPRtCkgUxU0jdj3tmMPc/edit#gid=1274624273

ESXI是一个虚拟机操作系统,和虚拟机软件比起来它本身就是个虚拟机容器,类似hyperV、 KVM这类东西。
openWRT是个开源的路由器系统。
trueNas是个开源的Nas操作系统,基于freeBSD,文件系统用的ZFS。
NAS是私人云存储设备。

实操

大概前年买了一个工控机,系统用的ESXI虚拟了openwrt和trueNas,本来顺风顺水,谁知道过年期间突然无响应了,重启进系统发现SSD好像坏掉了,任何写操作都会失败。
想到可能是SSD坏了,就用U盘做了exsi的启动盘,准备刷一下系统用。
流程是

  1. 下载ESXI系统镜像。esxi的个人许可证是免费的,需要自己注册账号下载。https://customerconnect.vmware.com/cn/group/vmware/evalcenter?p=free-esxi6
  2. iso烧写到U盘,常规操作。

在安装系统的时候发现,SSD确实坏了,U盘启动之后格式化SSD都会失败,不想深究原因,反正是坏了,狗东上下单了一个新的。然后就和装其他系统一样,u盘启动,安装esxi系统。

最后在ESXI里安装openwrt和trueNAS。

  • trueNas的系统可以直接下载官方给的iso镜像
  • openwrt由于有各种定制版,比如要用某科学功能的话,需要自己拉源码编译,这里需要一个ubuntu的机器,随便找台电脑用virtualBox装个ubuntu即可。

openwrt装好之后为了性能优化需要开启bios的虚拟化,esxi里开启网卡硬件passthrough。

trueNas里面有很多优秀的插件(Plex Server,Kodi,NextCloud,HomeAssistant, Aria2),基于FreeBSD的Jails功能实现, 文件系统是牛叉的ZFS。

坑1:
ESXI里面的vSwitch虚拟交换机设置:

  • Security policy
    • Allow promiscuous mode 混杂模式
  • NIC teaming policy
    • Route based on IP hash 基于IPhash的路由

不然多个虚拟机没法和局域网的其他设备互通网络。

坑2:

  • openwrt编译会直接出一个vmdk文件,这个是vmware用的格式,esxi还不能用。
    • 办法是用一个叫StarWind Converter的软件(还只有win版本)转一下。
    • 就是这步导致没有windows无法搞定

坑3:
不该把所有的系统都放在同一台机器上,出问题之后修复成本太高,已经下单了QNAP乞丐版。^_^

非坑1:
TrueNas的插件是基于FreeBSD的Jails,系统重装之后导入磁盘直接就跑起来了,配置全保留,没任何兼容问题,可真是太棒了。

后记:
经此一坑我已经全面转战Nas硬件,放弃折腾虚拟机组软路由加nas的方案,原因说到底是软路由一般体积比较小,要么配置低,配置高了散热差,不适合做复杂任务,否则一旦发热把ssd或者内存烧坏了整个系统都炸了,网都上不了。
不过TreeNas和FreeBSD还是给我留下了非常非常美好的印象。希望以后有机会再用起来。

C++模板元编程幼儿园中班期中考试篇

背景

https://mp.weixin.qq.com/s/E3-MUoN3LmtL9cp1n14Ydw

本文素材来自于上面这个链接,一个怪人用88万行switch case完成了下面这个题目。

  • 给出一个不多于5位的正整数,要求:
    1 求出它是几位数;
    2 分别输出每一位数;
    3 按逆序输出各位数宇,例如原数为 5631,应输出为 1365。

在原文调侃下,实际上实现了这个题目(不考虑代码体积)的性能理论最佳的实现,不需要任何计算,直接switch case出结果。

看了大佬的实现之后,我发现其实这个代码完全可以用c++ 的metaprogramming魔法来写,就是一个预计算的代码生成。所以以我现在c++元编程的幼儿园中班水平,花了亿点点时间写了这个实现。

实现

最终代码。https://github.com/mOnkD404/testcode/blob/master/variadic.cc

核心逻辑总共不到100行,下面开始实现。

  1. 首先需要做到类似switch case 的代码逻辑,不能有连续的if else,要能通过偏移直接找到代码地址,也就是function dispatch table的实现方式。 然后如果想要和switch case一样没有运行时额外开销,就不能用static const变量实现,因为static是第一次运行时跑初始化逻辑。在这里使用constexpr 构造函数的特性实现 (constexpr constructor)。这部分都是标准 c++ 写法,基本没啥新鲜的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <size_t N>
struct PrintTable<N> {
std::array<void (*)(), N> table_{};

constexpr PrintTable() {}
void PrintAt(int index) const { table_[index](); }
};

void PrintInt(int c) {
constexpr int size = 1000;
if (c >= size)
return;

using Table = PrintTable<size>;
constexpr Table tb;
tb.PrintAt(c);
}
  1. 接下来需要填充table的初始化逻辑,我们希望能用模版的变参展开特性,让编译器在编译阶段帮我们生成这个从1 到 N 的 table,那么模板的参数就不能是size_t, 这里需要用到 c++ 的 index sequence 这个特性。调整之后代码长这样 。 其中前两行是模板的空实现,目的是为了使用 index sequence提供偏特化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template <typename T>
struct PrintTable;
template <size_t... N>
struct PrintTable<std::index_sequence<N...>> {
std::array<void (*)(), sizeof...(N)> table_{PrintTraits<N>::Print...};

constexpr PrintTable() {}
void PrintAt(int index) const { table_[index](); }
};

void PrintInt(int c) {
constexpr int size = 1000;
if (c >= size)
return;

using Table = PrintTable<std::make_index_sequence<size>>;
constexpr Table tb;
tb.PrintAt(c);
}
  1. 接下来实现 PrintTraits 。PrintTraits 要实现题目的要求,输出几位数,每位数是什么,然后倒序输出。 对每个要求的输出实现一个traits模板。

    1. 首先我们实现一个帮助模板,用于记录一个已经拆分完的数字。 显然,他自然就有了输出序列,和计算序列长度的方法。这里用了模板变参展开的日常生活小技巧。

      1
      2
      3
      4
      5
      6
      7
      template <char... Is>
      struct DigitsVector {
      using Type = DigitsVector<Is...>;
      enum { DigitsCount = sizeof...(Is) };
      static void PrintDigitsString() { ((std::cout << (int)Is << " "), ...); }
      static void PrintDigitsCount() { std::cout << DigitsCount << " "; }
      };

      b. 那么最关键的一步就是要把模板的输入数字拆分。这部分我一开始的实现是比较挫的,在群里跟一些c++魔法爱好者学习之后,才写出了比价符合c++魔法部价值观的实现。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      template <int IntVal, typename = DigitsVector<>>
      struct DigitTraitsHelper;

      template <int IntVal, char... Is>
      struct DigitTraitsHelper<IntVal, DigitsVector<Is...>>
      : DigitTraitsHelper<IntVal / 10, DigitsVector<IntVal % 10, Is...>> {};

      template <int... Is>
      struct DigitTraitsHelper<0, DigitsVector<Is...>> : DigitsVector<Is...> {};

      最重要的需要养成的习惯是,c++ 元编程是面向编译器的。最最常用的技巧是利用编译器对类型的推导和解析能力,来实现常规代码中的函数调用和递归或循环,来实现计算功能,比如这里,通过每次继承就在DigitsVector中塞入一个参数的方式,将一个位数的信息传入DigitsVector模板参数中,最后在第一个参数为0时,停止继续继承自己,类似递归逻辑的结束点。

      c. 现在序列已经生成,接下来需要实现类似“个位数:1,十位数:8”这种输出的逻辑。这部分经过一些思考之后,我们发现可以构造一个静态的prefix table,然后还是用index sequence的方式,配合变参模板输出即可。这里面用了 static_assert 和 std::extent 来断言防止位数超过支持的宽度。并且继续使用了变参展开的生活小技巧。小技巧小技巧,一天不学受不了

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      template <typename T, typename N>
      struct PrintDigitsNameHelper;

      template <char... Is, size_t... N>
      struct PrintDigitsNameHelper<DigitsVector<Is...>, std::index_sequence<N...>> {
      constexpr const static char* NameTable[] = {
      "ones digit", "tens digit", "hundreds digit", "thousands digit",
      "ten thousands digit"};

      constexpr static size_t C = sizeof...(N);
      static_assert(C <= std::extent<decltype(NameTable)>::value, "overflow");
      static void Print() {
      ((std::cout << NameTable[C - N - 1] << " : " << (int)Is << " "), ...);
      }
      };

      d. 最后是一个反序的模板实现,有了上文的铺垫之后,到这里已经十分的straight forward。就是利用类型推倒和继承机制,把一个DigitsVector的模板参数反序。实际就是在利用编译器的type推倒机制实现递归,最后递归结束点是原DigitsVector 的参数为空。注意这里很容易想到将变参模板的参数用普通函数的方式递归之后反序输出,不够魔幻,会被魔法部警告。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      template <typename T, char... Rs>
      struct DigitVectorReverseHelper;

      template <int IntVal, char... Is, char... Rs>
      struct DigitVectorReverseHelper<DigitsVector<IntVal, Is...>, Rs...>
      : DigitVectorReverseHelper<DigitsVector<Is...>, IntVal, Rs...> {};

      template <char... Rs>
      struct DigitVectorReverseHelper<DigitsVector<>, Rs...> : DigitsVector<Rs...> {};

      e. 最后来实现打印逻辑,就是把上面几个输出放一起。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      template <int N>
      struct PrintTraits {
      using Helper = typename DigitTraitsHelper<N>::Type;
      using ReverseHelper = typename DigitVectorReverseHelper<
      typename DigitTraitsHelper<N>::Type>::Type;
      using PrintDigitsName =
      PrintDigitsNameHelper<Helper,
      std::make_index_sequence<Helper::DigitsCount>>;

      static void Print() {
      std::cout << " total: ";
      Helper::PrintDigitsCount();
      PrintDigitsName::Print();
      std::cout << " in order: ";
      Helper::PrintDigitsString();
      std::cout << " reverse: ";
      ReverseHelper::PrintDigitsString();
      std::cout << std::endl;
      }
      };

最后的最后补全一些判断逻辑,是见证魔法的时刻。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <array>
#include <cmath>
#include <iostream>
#include <type_traits>

template <char... Is>
struct DigitsVector {
using Type = DigitsVector<Is...>;
enum { DigitsCount = sizeof...(Is) };
static void PrintDigitsString() { ((std::cout << (int)Is << " "), ...); }
static void PrintDigitsCount() { std::cout << DigitsCount << " "; }
};

template <typename T, typename N>
struct PrintDigitsNameHelper;

template <char... Is, size_t... N>
struct PrintDigitsNameHelper<DigitsVector<Is...>, std::index_sequence<N...>> {
constexpr const static char* NameTable[] = {
"ones digit", "tens digit", "hundreds digit", "thousands digit",
"ten thousands digit"};

constexpr static size_t C = sizeof...(N);
static_assert(C <= std::extent<decltype(NameTable)>::value, "overflow");
static void Print() {
((std::cout << NameTable[C - N - 1] << " : " << (int)Is << " "), ...);
}
};

template <int IntVal, typename = DigitsVector<>>
struct DigitTraitsHelper;

template <int IntVal, char... Is>
struct DigitTraitsHelper<IntVal, DigitsVector<Is...>>
: DigitTraitsHelper<IntVal / 10, DigitsVector<IntVal % 10, Is...>> {};

template <int... Is>
struct DigitTraitsHelper<0, DigitsVector<Is...>> : DigitsVector<Is...> {};

template <typename T, char... Rs>
struct DigitVectorReverseHelper;

template <int IntVal, char... Is, char... Rs>
struct DigitVectorReverseHelper<DigitsVector<IntVal, Is...>, Rs...>
: DigitVectorReverseHelper<DigitsVector<Is...>, IntVal, Rs...> {};

template <char... Rs>
struct DigitVectorReverseHelper<DigitsVector<>, Rs...> : DigitsVector<Rs...> {};

template <int N>
struct PrintTraits {
using Helper = typename DigitTraitsHelper<N>::Type;
using ReverseHelper = typename DigitVectorReverseHelper<
typename DigitTraitsHelper<N>::Type>::Type;
using PrintDigitsName =
PrintDigitsNameHelper<Helper,
std::make_index_sequence<Helper::DigitsCount>>;

static void Print() {
std::cout << " total: ";
Helper::PrintDigitsCount();
PrintDigitsName::Print();
std::cout << " in order: ";
Helper::PrintDigitsString();
std::cout << " reverse: ";
ReverseHelper::PrintDigitsString();
std::cout << std::endl;
}
};

template <>
struct PrintTraits<0> {
static void Print() {
std::cout << " total: 1 ones digit: 0 in order: 0 reverse: 0 " << std::endl;
}
};

template <typename T>
struct PrintTable;
template <size_t... N>
struct PrintTable<std::index_sequence<N...>> {
std::array<void (*)(), sizeof...(N)> table_{PrintTraits<N>::Print...};

constexpr PrintTable() {}
void PrintAt(int index) const { table_[index](); }
};

void PrintInt(int c) {
constexpr int size = 100000;
if (c >= size)
return;

using Table = PrintTable<std::make_index_sequence<size>>;
constexpr Table tb;
tb.PrintAt(c);
}

int main(int argc, char* argv[]) {
for (std::string line; std::getline(std::cin, line);) {
PrintInt(atoi(line.c_str()));
}
return 0;
}

这文件编译出来有亿点大,135MB,十分感人。

1
2
3
4
5
6
7
8
9
10
11
12
13
testdir % ls -lah variadic
-rwxr-xr-x 1 swp staff 135M Oct 24 23:12 variadic
testdir % ./variadic
45632
total: 5 ten thousands digit : 4 thousands digit : 5 hundreds digit : 6 tens digit : 3 ones digit : 2 in order: 4 5 6 3 2 reverse: 2 3 6 5 4
0
total: 1 ones digit: 0 in order: 0 reverse: 0
1
total: 1 ones digit : 1 in order: 1 reverse: 1
99999
total: 5 ten thousands digit : 9 thousands digit : 9 hundreds digit : 9 tens digit : 9 ones digit : 9 in order: 9 9 9 9 9 reverse: 9 9 9 9 9
123
total: 3 hundreds digit : 1 tens digit : 2 ones digit : 3 in order: 1 2 3 reverse: 3 2 1

如何调教一台完美的测试机:AOSP刷入GMS记录

背景

最近做开发时很多体验需要完整的gms服务框架,官方镜像可以体验,但是官方是release系统。aosp正常编译是不带gms的,而且webview的开发经常需要和系统webview作对比,因此需要一个能任意替换系统webview的userdebug系统并且带上gms。
需求如下:

  1. userdebug系统
  2. 支持随意替换系统webview
  3. 支持adb root,可以查看所有进程,跑chromium测试
  4. 刷入gms,带google服务框架,体验完整原生安卓

解决方案

最简单的方法是,使用第三方rom(最好修改较小,接近原生),例如魔趣、lineageOS、Omni等热门第三方rom,在recovery中依次刷入rom和opengapps的包即可。
不过我这次用的pixel4 其他第三方系统都不支持,只有lineageOS可以刷,但是刷入之后发现虽然是userdebug的系统,但是却换不了系统webview,怀疑他的编译选项有问题。
因此选择了下面的方法,自己编译aosp,编译时打入opengapps。


正文开始。 pixel 4 编译aosp+opengapps ,步骤+踩坑汇总:

  1. 拉取android 对应分支源码
    例如pixel4

    1
    repo init -u https://android.googlesource.com/platform/manifest -b android-10.0.0_r41
  2. 下载厂商驱动

  3. 例如pixel4 下载https://developers.google.com/android/drivers#flameqq3a.200805.001

  4. 解压后在源码目录下执行对应脚本,中间需要输入I ACCEPT

  5. 拉取opengapps 源码 https://github.com/opengapps/aosp_build

  6. 参照opengapps说明操作,其中最后一步拉代码 repo forall -c git lfs pull 非常容易失败要多来几次,失败的话编译会出错

  7. 小tips 建议选择小包,很多Google全家桶apk可以在playstore下载,而且有些和aosp兼容有问题,比如pixel4刷stock包刷完全屏手势失灵,刷nano/super包正常。

  8. non-stock 包想要能自己随意替换系统webview的话需要开启GAPPS_FORCE_WEBVIEW_OVERRIDES := true

  9. 实际就是在配置 frameworks/base/core/res/res/xml/config_webview_packages.xml 这个文件

  10. 修改一处代码,否则pixellauncher起不来, 参考 https://c55jeremy-tech.blogspot.com/2019/04/aosppixel-2-romrom.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    --- a/services/core/java/com/android/server/wm/WindowManagerService.java
    +++ b/services/core/java/com/android/server/wm/WindowManagerService.java
    @@ -6001,8 +6001,8 @@ public class WindowManagerService extends IWindowManager.Stub

    @Override
    public void setShelfHeight(boolean visible, int shelfHeight) {
    - mAmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR,
    - "setShelfHeight()");
    + //mAmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR,
    + // "setShelfHeight()");
    synchronized (mWindowMap) {
    getDefaultDisplayContentLocked().getPinnedStackController().setAdjustedForShelf(visible,
    shelfHeight)
  11. 常规编译源码
    lunch aosp_flame-userdebug
    make -j8
    如果这步编译有错误,就是上面repo拉apk没拉全,要删了对应目录重来

  12. 刷入 fastboot flashall -w

  13. 启动之后报设备未获得play保护机制认证,在https://www.google.com/android/uncertified/ 注册设备的id,注册之后过一会就能正常用了。获取设备id的方法 :

    1
    2
    3
    adb root
    adb shell
    sqlite3 /data/data/com.google.android.gsf/databases/gservices.db 'select * from main where name = "android_id";'
  14. android 10.0 开启手势

    1
    adb shell cmd overlay enable com.android.internal.systemui.navbar.gestural
  15. 系统webview 替换姿势

  16. 卸载系统webview 用chromium下脚本 android_webview/tools/remove_preinstalled_webview.py

  17. 安装新webview adb install 即可

  18. 如果需要让gapps刷入之后可以安装自编译版本的webview,需要在xml配置文件中加上

    <webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true">
    </webviewprovider>
  19. 参考文档https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/aosp-system-integration.md

  20. 验证结果

  21. 使用系统webview 访问 https://wutong-apk.cdn.bcebos.com/,出现红色风险提示页面,证明系统wbeview+gms工作正常。

  22. 安装chromium源码编译出的自编译包,在设置/开发者选项中,能同时看到:

    1. 官方的系统webview包,com.google.android.webview可以在play store升级
    2. 自编译webview包,com.android.webview

规则匹配引擎

备选本地过滤引擎

AdBlock

AdBlock 目前主流支持easylist规则,基本格式是 filter$options 这种语法。
规则匹配引擎,要解决的问题主要是在海量规则中判断是否命中的问题。如果用正则或者遍历,消耗过大,一般采取的都是先把规则依据某种判据先分成小类别,匹配时先找到对应的小类别,然后在小类别中遍历规则完成匹配。
下面从分类方法、存储方法、匹配方法简述几种匹配引擎的实现。

Brave AdBlock c++ 实现

Brave AdBlock c++ 使用的分类方法是:

  • 计算阶段,用规则的filter部分,去掉特殊字符之后, 用指定长度算出一个key,插入到布隆过滤器中,插入前会先过一个坏key的大表(坏key可以认为是人工过了线上的top站点得出的冲突率最高的key)
    • 如果不是坏key则插入布隆过滤器,如果是坏key,则插入人工分类的几个集合中(例如根据规则是否限制域名,是否限制域名取反等特性分类),并通过hashset查询,hashset中使用规则的host或者filter部分计算key
  • 匹配阶段,先计算目标url所在的domain是否存在于几个hashset中,如果存在则在对应的规则集合中遍历;如果都不存在,则通过url算出所有可能的key,例如固定长度是7,就用url中的连续字符每7个字符算一个key,在布隆过滤器中匹配,如果不命中,则说明命中不了规则,如果命中则在剩余规则中遍历。
  • 规则的序列化和反序列化使用brave实现的格式,加载时需要简单解析一下内容,然后用指针指向对应内存,反序列化文件mmap之后不能释放。

    Brave Adblock Rust实现

  • 计算阶段,首先规则的filter 部分,用规则包含的特殊字符(除了子母和数字之外的字符)将规则切分成多个token,这里需要注意的是,如果一个规则中间有通配符,则包含通配符的部分不能作为token,如www.ba*du.com,计算出来的token是 {www,com},ba和du因为包含通配符,如果作为token,在这个引擎的实现中,匹配时是无法处理的。
    • 准备将token作为当前规则的索引插入hashmap中,首先计算现存所有规则的token对应的map中,当前规则的token中出现次数最少的那个token,即最能独立代表当前规则的token,然后用这个token作为当前规则的key,插入hashmap
  • 匹配阶段,用上文计算过程中相同的分割规则,将目标url切分成对等的token,找到对应规则所在的所有小集合,遍历集合中的规则进行过滤。
  • 存储,还没看

    Chromium Subresource Filter实现

    Subresource Filter是chromium 7x版本开始自己实现的规则引擎,目前还在测试阶段未正式上线,可以为浏览器插件提供支持easylist语法的引擎(官方逼死同人系列)。
  • 计算阶段,处理规则的filter,chromium的实现是把规则中除了通配符()和分隔符(^)之外的字符,用固定长度计算key,如果不到固定长度则忽略。例如 www.badu.com 这个规则中,用chromium的方法计算key用的原始字符(假设长度是5),就是{www.b , ww.ba, du.co, u.com},这种集合
    • 计算key之后,插入hashmap时,寻找所有的key中,桶中元素最少的,类似brave的rust实现
  • 匹配阶段,首先对url也用固定长度算key,能算出很多个,然后每个key在hashmap中寻找对应规则所在的集合,遍历集合中的规则进行过滤。
  • 存储阶段,chromium使用了自家的FlatBuffer,可以不经过反序列化,mmap之后直接使用,效率极高。

看起来brave c++的实现在三者中最差,chromium的有可能略好于brave rust的实现,因为可以在算key时利用上规则里,通配符两边的字符,感觉上找到规则的准确率会提高。

性能对比

过滤引擎性能对比测试结论,brave rust略优于chromium实现,都远好于brave c++实现。

Android WebView DrawFn 相关

在 chromium 的较高版本 webview 中,适配了android Q 的 vulkan 渲染。
在 webview 的历史实现中,由于和 chrome 架构差异,需要使用 DrawGL 相关方法在 android view 中绘制内容。

chrome 浏览器是完全独立的app,因此完全实现了自己的渲染,没有用android的 view 框架;webview 由于要作为一个 view 嵌入 app,所以必须依托于 android 的 view 对象,webview 通过反射调用 android.view.DisplayListCanvas 的 drawGLFunctor 方法实现绘制。
在最新的代码中,为了使用 android Q 的 vulkan 框架,webview 使用了新的实现方法用于调用vulkan。

plat_support

plat_support 是个webview依赖的系统库,实现了webview的创建functor的方法,由于是平台相关,所以实在framework中提供。
https://cs.android.com/android/platform/superproject/+/master:frameworks/base/native/webview/plat_support/
在plat_support创建时会向一个webview的类中注册几个native方法,webview通过使用这些方法,创建系统版本对应的functor,如创建DrawGLFunctor的

1
2
3
4
5
6
7
8
9
const char kClassName[] = "com/android/webview/chromium/DrawGLFunctor";
const JNINativeMethod kJniMethods[] = {
{ "nativeCreateGLFunctor", "(J)J",
reinterpret_cast<void*>(CreateGLFunctor) },
{ "nativeDestroyGLFunctor", "(J)V",
reinterpret_cast<void*>(DestroyGLFunctor) },
{ "nativeSetChromiumAwDrawGLFunction", "(J)V",
reinterpret_cast<void*>(SetChromiumAwDrawGLFunction) },
};

以及创建能使用vulkan的DrawFunctor的

1
2
3
4
5
char kClassName[]
const JNINativeMethod kJniMethods[] = {
{"nativeGetFunctionTable", "()J",
reinterpret_cast<void*>(GetDrawFnFunctionTable)},
};

在创建DrawFunctor的table中,看指向create_functor的函数指针,指向了真正的创建函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
static bool callbacks_initialized = false;
static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
.onSync = &onSync,
.onContextDestroyed = &onContextDestroyed,
.onDestroyed = &onDestroyed,
};
if (!callbacks_initialized) {
switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
case uirenderer::RenderMode::OpenGL_ES:
webview_functor_callbacks.gles.draw = &draw_gl;
break;
case uirenderer::RenderMode::Vulkan:
webview_functor_callbacks.vk.initialize = &initializeVk;
webview_functor_callbacks.vk.draw = &drawVk;
webview_functor_callbacks.vk.postDraw = &postDrawVk;
break;
}
callbacks_initialized = true;
}
SupportData* support = new SupportData{
.data = data,
.callbacks = *functor_callbacks,
};
int functor = uirenderer::WebViewFunctor_create(
support, webview_functor_callbacks,
uirenderer::WebViewFunctor_queryPlatformRenderMode());
if (functor <= 0) delete support;
return functor;
}

首次初始化时会根据平台相关特性,选择使用opengl还是vulkan。

WebView 调用DrawGLFunctor过程

这部分网上分析很多,不详细记录了,大概就是AwContents.onDraw的时候反射调用canvas里一个私有的方法。webview 通过周期地触发InProcessCommandBuffer::Flush方法,触发renderThread的合成。

需要注意的是,chrome和 webview 在渲染上最大的区别就是,command buffer service线程,在chrome上生产者和消费者都在同一个service线程,在webview上,生产者和消费者在不同的线程,因为webview的渲染不是chromium自己管理的,他只输出EGLImage,交给android系统的RenderThread处理 ConsumeTexture。于是,webview使用MailboxManagerSync,而chrome使用MailboxManagerImpl,webview使用的是加锁多线程共享的方式实现。
附生产和消费texture的调用栈:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(gdb) bt
#0 gpu::gles2::MailboxManagerSync::ConsumeTexture () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/mailbox_manager_sync.cc:194
#1 0xcbaa0f80 in gpu::gles2::GLES2DecoderImpl::DoCreateAndConsumeTextureINTERNAL () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/gles2_cmd_decoder.cc:18454
#2 0xcba85898 in gpu::gles2::GLES2DecoderImpl::HandleCreateAndConsumeTextureINTERNALImmediate () at ../../gpu/command_buffer/service/gles2_cmd_decoder_autogen.h:4946
#3 0xcba8f6a0 in gpu::gles2::GLES2DecoderImpl::DoCommandsImpl<false> () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/gles2_cmd_decoder.cc:5932
#4 0xcb9bdc54 in gpu::CommandBufferService::Flush () at ./../../gpu/command_buffer/service/command_buffer_service.cc:69
#5 0xcbb2163a in gpu::InProcessCommandBuffer::FlushOnGpuThread () at ../../gpu/ipc/in_process_command_buffer.cc:913
#6 0xca515508 in base::OnceCallback<void ()>::Run() && () at ../../base/callback.h:97
#7 0xca52ffde in base::internal::FunctorTraits<void (android_webview::AwCookieStoreWrapper::*)(base::OnceCallback<void ()>), void>::Invoke<void (android_webview::AwCookieStoreWrapper::*)(base::OnceCallback<void ()>), base::WeakPtr<android_webview::AwCookieStoreWrapper>, base::OnceCallback<void ()> >(void (android_webview::AwCookieStoreWrapper::*)(base::OnceCallback<void ()>), base::WeakPtr<android_webview::AwCookieStoreWrapper>&&, base::OnceCallback<void ()>&&) () at ../../base/bind_internal.h:499
#8 base::internal::InvokeHelper<true, void>::MakeItSo<void (android_webview::AwCookieStoreWrapper::*)(base::OnceCallback<void ()>), base::WeakPtr<android_webview::AwCookieStoreWrapper>, base::OnceCallback<void ()> >(void (android_webview::AwCookieStoreWrapper::*&&)(base::OnceCallback<void ()>), base::WeakPtr<android_webview::AwCookieStoreWrapper>&&, base::OnceCallback<void ()>&&) ()
at ../../base/bind_internal.h:619
#9 base::internal::Invoker<base::internal::BindState<void (android_webview::AwCookieStoreWrapper::*)(base::OnceCallback<void ()>), base::WeakPtr<android_webview::AwCookieStoreWrapper>, base::OnceCallback<void ()> >, void ()>::RunImpl<void (android_webview::AwCookieStoreWrapper::*)(base::OnceCallback<void ()>), std::__1::tuple<base::WeakPtr<android_webview::AwCookieStoreWrapper>, base::OnceCallback<void ()> >, 0u, 1u>(void (android_webview::AwCookieStoreWrapper::*&&)(base::OnceCallback<void ()>), std::__1::tuple<base::WeakPtr<android_webview::AwCookieStoreWrapper>, base::OnceCallback<void ()> >&&, std::__1::integer_sequence<unsigned int, 0u, 1u>) () at ../../base/bind_internal.h:672
#10 base::internal::Invoker<base::internal::BindState<void (android_webview::AwCookieStoreWrapper::*)(base::OnceCallback<void ()>), base::WeakPtr<android_webview::AwCookieStoreWrapper>, base::OnceCallback<void ()> >, void ()>::RunOnce(base::internal::BindStateBase*) () at ../../base/bind_internal.h:641
#11 0xca515508 in base::OnceCallback<void ()>::Run() && () at ../../base/callback.h:97
#12 0xca5484bc in android_webview::TaskForwardingSequence::RunTask(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int) ()
at ../../android_webview/browser/gfx/deferred_gpu_command_service.cc:108
#13 0xca548544 in base::internal::FunctorTraits<void (android_webview::TaskForwardingSequence::*)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), void>::Invoke<void (android_webview::TaskForwardingSequence::*)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), base::WeakPtr<android_webview::TaskForwardingSequence>, base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int>(void (android_webview::TaskForwardingSequence::*)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), base::WeakPtr<android_webview::TaskForwardingSequence>&&, base::OnceCallback<void ()>&&, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >&&, unsigned int&&) () at ../../base/bind_internal.h:499
#14 base::internal::InvokeHelper<true, void>::MakeItSo<void (android_webview::TaskForwardingSequence::*)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), base::WeakPtr<android_webview::TaskForwardingSequence>, base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int>(void (android_webview::TaskForwardingSequence::*&&)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), base::WeakPtr<android_webview::TaskForwardingSequence>&&, base::OnceCallback<void ()>&&, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >&&, unsigned int&&) () at ../../base/bind_internal.h:619
#15 base::internal::Invoker<base::internal::BindState<void (android_webview::TaskForwardingSequence::*)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), base::WeakPtr<android_webview::TaskForwardingSequence>, base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int>, void ()>::RunImpl<void (android_webview::TaskForwardingSequence::*)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), std::__1::tuple<base::WeakPtr<android_webview::TaskForwardingSequence>, base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int>, 0u, 1u, 2u, 3u>(void (android_webview::TaskForwardingSequence::*&&)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), std::__1::tuple<base::WeakPtr<android_webview::TaskForwardingSequence>, base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int>&&, std::__1::integer_sequence<unsigned int, 0u, 1u, 2u, 3u>) () at ../../base/bind_internal.h:672
#16 base::internal::Invoker<base::internal::BindState<void (android_webview::TaskForwardingSequence::*)(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int), base::WeakPtr<android_webview::TaskForwardingSequence>, base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >, unsigned int>, void ()>::RunOnce(base::internal::BindStateBase*) () at ../../base/bind_internal.h:641
#17 0xca515508 in base::OnceCallback<void ()>::Run() && () at ../../base/callback.h:97
#18 0xca547f16 in android_webview::DeferredGpuCommandService::RunTasks () at ../../android_webview/browser/gfx/deferred_gpu_command_service.cc:243
#19 0xca547ec8 in android_webview::DeferredGpuCommandService::ScheduleTask(base::OnceCallback<void ()>, bool) () at ../../android_webview/browser/gfx/deferred_gpu_command_service.cc:188
#20 0xca5483ac in android_webview::TaskForwardingSequence::ScheduleTask(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >) ()
at ../../android_webview/browser/gfx/deferred_gpu_command_service.cc:77
#21 0xcbb2156e in gpu::InProcessCommandBuffer::ScheduleGpuTask(base::OnceCallback<void ()>, std::__1::vector<gpu::SyncToken, std::__1::allocator<gpu::SyncToken> >) ()
at ../../gpu/ipc/in_process_command_buffer.cc:849
#22 0xcbb219a6 in gpu::InProcessCommandBuffer::Flush () at ../../gpu/ipc/in_process_command_buffer.cc:977
#23 0xca7a9b84 in gpu::CommandBufferHelper::Flush () at ./../../gpu/command_buffer/client/cmd_buffer_helper.cc:182
#24 0xcb8b2800 in gpu::gles2::GLES2Implementation::FlushHelper () at ./../../gpu/command_buffer/client/gles2_implementation.cc:1388
#25 0xcb8b2a7c in gpu::gles2::GLES2Implementation::IssueShallowFlush () at ./../../gpu/command_buffer/client/gles2_implementation.cc:1378
#26 0xca549968 in android_webview::ParentOutputSurface::SwapBuffers () at ../../android_webview/browser/gfx/parent_output_surface.cc:52
#27 0xcba317dc in viz::GLRenderer::SwapBuffers () at ./../../components/viz/service/display/gl_renderer.cc:2901
#28 0xcba25d3a in viz::Display::DrawAndSwap () at ./../../components/viz/service/display/display.cc:523
#29 0xca54bba6 in android_webview::SurfacesInstance::DrawAndSwap () at ../../android_webview/browser/gfx/surfaces_instance.cc:239
#30 0xca548fc8 in android_webview::HardwareRenderer::Draw () at ../../android_webview/browser/gfx/hardware_renderer.cc:182
#31 0xca54a00c in android_webview::RenderThreadManager::DrawOnRT () at ../../android_webview/browser/gfx/render_thread_manager.cc:195
#32 0xca544be2 in android_webview::AwGLFunctor::DrawGL () at ../../android_webview/browser/gfx/aw_gl_functor.cc:119
---Type <return> to continue, or q <return> to quit---
#33 DrawGLFunction () at ../../android_webview/browser/gfx/aw_gl_functor.cc:27
#34 0xec21d328 in android::(anonymous namespace)::DrawGLFunctor::operator()(int, void*) () from /tmp/adb-gdb-libs-803fd342/system/lib/libwebviewchromium_plat_support.so
#35 0xf26fc6de in android::uirenderer::skiapipeline::GLFunctorDrawable::onDraw(SkCanvas*) () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#36 0xf29b84b6 in SkDrawable::draw(SkCanvas*, SkMatrix const*) () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#37 0xf29b8ac2 in SkLiteDL::draw(SkCanvas*) const () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#38 0xf29a07e0 in android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#39 0xf29a0af6 in android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#40 0xf2703d3e in android::uirenderer::skiapipeline::SkiaPipeline::renderLayersImpl(android::uirenderer::LayerUpdateQueue const&, bool, bool) ()
from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#41 0xf29d3d1a in android::uirenderer::skiapipeline::SkiaPipeline::renderFrame(android::uirenderer::LayerUpdateQueue const&, SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, bool, bool, android::uirenderer::Rect const&, sk_sp<SkSurface>) ()
from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#42 0xf29d33de in android::uirenderer::skiapipeline::SkiaOpenGLPipeline::draw(android::uirenderer::renderthread::Frame const&, SkRect const&, SkRect const&, android::uirenderer::FrameBuilder::LightGeometry const&, android::uirenderer::LayerUpdateQueue*, android::uirenderer::Rect const&, bool, bool, android::uirenderer::BakedOpRenderer::LightInfo const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, android::uirenderer::FrameInfoVisualizer*) ()
from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#43 0xf270c42c in android::uirenderer::renderthread::CanvasContext::draw() () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#44 0xf29d6b08 in std::__1::__function::__func<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0, std::__1::allocator<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0>, void ()>::operator() () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#45 0xf299fb30 in android::uirenderer::WorkQueue::process() () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#46 0xf271519e in android::uirenderer::renderthread::RenderThread::threadLoop() () from /tmp/adb-gdb-libs-803fd342/system/lib/libhwui.so
#47 0xf132f088 in android::Thread::_threadLoop(void*) () from /tmp/adb-gdb-libs-803fd342/system/lib/libutils.so
#48 0xf1ea940a in __pthread_start(void*) () from /tmp/adb-gdb-libs-803fd342/system/lib/libc.so
#49 0xf1e630ce in __start_thread () from /tmp/adb-gdb-libs-803fd342/system/lib/libc.so
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
(gdb) bt
#0 gpu::gles2::MailboxManagerSync::ProduceTexture () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/mailbox_manager_sync.cc:226
#1 0xcbae0318 in gpu::SharedImageBackingPassthroughGLTexture::ProduceLegacyMailbox ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:593
#2 0xcbad10b6 in gpu::SharedImageRepresentationFactoryRef::ProduceLegacyMailbox () at ../../gpu/command_buffer/service/shared_image_representation.h:73
#3 gpu::SharedImageFactory::RegisterBacking () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:287
#4 0xcbad0f96 in gpu::SharedImageFactory::CreateSharedImage () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:117
#5 0xcbb2bdf4 in gpu::SharedImageStub::OnCreateSharedImage () at ./../../gpu/ipc/service/shared_image_stub.cc:99
#6 0xcbb2baf4 in base::DispatchToMethodImpl<gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>, 0u>(gpu::SharedImageStub* const&, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&, std::__1::integer_sequence<unsigned int, 0u>) () at ../../base/tuple.h:52
#7 base::DispatchToMethod<gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params> >(gpu::SharedImageStub* const&, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&) () at ../../base/tuple.h:60
#8 IPC::DispatchToMethod<gpu::SharedImageStub, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), void, std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params> >(gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), void*, std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&) ()
at ../../ipc/ipc_message_templates.h:51
#9 IPC::MessageT<GpuChannelMsg_CreateSharedImage_Meta, std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>, void>::Dispatch<gpu::SharedImageStub, gpu::SharedImageStub, void, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&)> () at ../../ipc/ipc_message_templates.h:146
#10 gpu::SharedImageStub::OnMessageReceived () at ./../../gpu/ipc/service/shared_image_stub.cc:69
#11 0xcbb280b8 in gpu::GpuChannel::HandleMessageHelper () at ./../../gpu/ipc/service/gpu_channel.cc:597
#12 0xcbb273b0 in gpu::GpuChannel::HandleMessage () at ./../../gpu/ipc/service/gpu_channel.cc:560
#13 0xcb9bf9b6 in base::OnceCallback<void ()>::Run() && () at ../../base/callback.h:97
#14 gpu::Scheduler::RunNextTask () at ./../../gpu/command_buffer/service/scheduler.cc:527
#15 0xcb1088c8 in base::OnceCallback<void ()>::Run() && () at ../../base/callback.h:97
#16 base::TaskAnnotator::RunTask () at ./../../base/task/common/task_annotator.cc:114
#17 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl () at ./../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:363
#18 0xcb10855c in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoSomeWork () at ./../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:214
#19 0xcb108d9c in non-virtual thunk to base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoSomeWork() () at ./../../base/time/time_now_posix.cc:52
#20 0xcb0e6e9c in base::MessagePumpDefault::Run () at ./../../base/message_loop/message_pump_default.cc:39
#21 0xcb1090fe in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run () at ./../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:448
#22 0xcb0f36de in base::RunLoop::RunWithTimeout () at ./../../base/run_loop.cc:161
#23 0xcb119ab2 in base::Thread::ThreadMain () at ./../../base/threading/thread.cc:312
#24 0xcb13b010 in base::(anonymous namespace)::ThreadFunc () at ./../../base/threading/platform_thread_posix.cc:81
#25 0xf1ea940a in __pthread_start(void*) () from /tmp/adb-gdb-libs-803fd342/system/lib/libc.so
#26 0xf1e630ce in __start_thread () from /tmp/adb-gdb-libs-803fd342/system/lib/libc.so

RasterTileWorker

1
2
3
4
5
6
7
8
9
10
11
12
#0  gpu::SharedImageInterfaceProxy::CreateSharedImage () at ../../gpu/ipc/client/shared_image_interface_proxy.cc:63
#1 0xc2ae3952 in cc::(anonymous namespace)::RasterizeSourceOOP () at ./../../cc/raster/gpu_raster_buffer_provider.cc:142
#2 cc::GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal () at ./../../cc/raster/gpu_raster_buffer_provider.cc:546
#3 cc::GpuRasterBufferProvider::PlaybackOnWorkerThread () at ./../../cc/raster/gpu_raster_buffer_provider.cc:470
#4 cc::GpuRasterBufferProvider::RasterBufferImpl::Playback () at ./../../cc/raster/gpu_raster_buffer_provider.cc:325
#5 0xc2b4b6c8 in cc::(anonymous namespace)::RasterTaskImpl::RunOnWorkerThread () at ./../../cc/tiles/tile_manager.cc:160
#6 0xc365e4d2 in content::CategorizedWorkerPool::RunTaskInCategoryWithLockAcquired () at ./../../content/renderer/categorized_worker_pool.cc:400
#7 content::CategorizedWorkerPool::RunTaskWithLockAcquired () at ./../../content/renderer/categorized_worker_pool.cc:378
#8 content::CategorizedWorkerPool::Run () at ./../../content/renderer/categorized_worker_pool.cc:260
#9 content::(anonymous namespace)::CategorizedWorkerPoolThread::Run () at ./../../content/renderer/categorized_worker_pool.cc:55
#10 0xc21896a6 in base::SimpleThread::ThreadMain () at ./../../base/threading/simple_thread.cc:80
#11 0xc21ad234 in base::(anonymous namespace)::ThreadFunc () at ./../../base/threading/platform_thread_posix.cc:81

InProcGPUThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

#0 gpu::SharedImageBackingFactoryGLTexture::MakeBacking ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:1222
#1 0xc2d72960 in gpu::SharedImageBackingFactoryGLTexture::CreateSharedImage ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:1052
#2 0xc2d72442 in gpu::SharedImageBackingFactoryGLTexture::CreateSharedImage ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:857
#3 0xc2d74fe6 in gpu::SharedImageFactory::CreateSharedImage ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:115
#4 0xc2dd1540 in gpu::SharedImageStub::OnCreateSharedImage () at ./../../gpu/ipc/service/shared_image_stub.cc:99
#5 0xc2dd1250 in base::DispatchToMethodImpl<gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>, 0u>(gpu::SharedImageStub* const&, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&, std::__1::integer_sequence<unsigned int, 0u>) ()
at ../../base/tuple.h:52
#6 base::DispatchToMethod<gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params> >(gpu::SharedImageStub* const&, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&) () at ../../base/tuple.h:60
#7 IPC::DispatchToMethod<gpu::SharedImageStub, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), void, std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params> >(gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), void*, std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&) () at ../../ipc/ipc_message_templates.h:51
#8 IPC::MessageT<GpuChannelMsg_CreateSharedImage_Meta, std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>, void>::Dispatch<gpu::SharedImageStub, gpu::SharedImageStub, void, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&)> ()
at ../../ipc/ipc_message_templates.h:146
#9 gpu::SharedImageStub::OnMessageReceived () at ./../../gpu/ipc/service/shared_image_stub.cc:69
#10 0xc2dcd8b0 in gpu::GpuChannel::HandleMessageHelper () at ./../../gpu/ipc/service/gpu_channel.cc:614
#11 0xc2dccbbc in gpu::GpuChannel::HandleMessage () at ./../../gpu/ipc/service/gpu_channel.cc:570
#12 0xc2c337ce in base::OnceCallback<void ()>::Run() && () at ../../base/callback.h:97
#13 gpu::Scheduler::RunNextTask () at ./../../gpu/command_buffer/service/scheduler.cc:527
#14 0xc2245d46 in base::OnceCallback<void ()>::Run() && () at ../../base/callback.h:97
#15 base::TaskAnnotator::RunTask () at ./../../base/task/common/task_annotator.cc:114
#16 0xc22501f0 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl ()
at ./../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:363
#17 0xc224ff5a in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoSomeWork ()

RenderThread 中 InProcessCommandBuffer建立

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Thread 28 "RenderThread" hit Breakpoint 1, gpu::InProcessCommandBuffer::InProcessCommandBuffer ()
at ../../gpu/ipc/in_process_command_buffer.cc:285
285 }
(gdb) bt
#0 gpu::InProcessCommandBuffer::InProcessCommandBuffer () at ../../gpu/ipc/in_process_command_buffer.cc:285
#1 0xc09722f2 in std::__1::make_unique<gpu::InProcessCommandBuffer, gpu::CommandBufferTaskExecutor*&, GURL>(gpu::CommandBufferTaskExecutor*&, GURL&&) () at ../../buildtools/third_party/libc++/trunk/include/memory:3131
#2 gpu::GLInProcessContext::Initialize () at ../../gpu/ipc/gl_in_process_context.cc:75
#3 0xbf09bf00 in android_webview::AwRenderThreadContextProvider::AwRenderThreadContextProvider ()
at ../../android_webview/browser/gfx/aw_render_thread_context_provider.cc:69
#4 android_webview::AwRenderThreadContextProvider::Create () at ../../android_webview/browser/gfx/aw_render_thread_context_provider.cc:32
#5 0xbf0a25f4 in android_webview::SurfacesInstance::SurfacesInstance () at ../../android_webview/browser/gfx/surfaces_instance.cc:129
#6 android_webview::SurfacesInstance::GetOrCreateInstance () at ../../android_webview/browser/gfx/surfaces_instance.cc:55
#7 0xbf09f3e4 in android_webview::HardwareRenderer::HardwareRenderer () at ../../android_webview/browser/gfx/hardware_renderer.cc:33
#8 0xbf0a0f4c in android_webview::RenderThreadManager::DrawOnRT () at ../../android_webview/browser/gfx/render_thread_manager.cc:203
#9 0xbf09a31a in android_webview::AwDrawFnImpl::DrawInternal<AwDrawFn_DrawGLParams> ()
at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:624
#10 android_webview::AwDrawFnImpl::DrawGL () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:275
#11 android_webview::(anonymous namespace)::DrawGLWrapper () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:133
#12 0xe0d68262 in android::(anonymous namespace)::draw_gl(int, void*, android::uirenderer::DrawGlInfo const&) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libwebviewchromium_plat_support.so
#13 0xebb53e20 in android::uirenderer::WebViewFunctor::drawGl(android::uirenderer::DrawGlInfo const&) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#14 0xebb5356e in android::uirenderer::skiapipeline::GLFunctorDrawable::onDraw(SkCanvas*) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#15 0xeba7a024 in SkCanvas::onDrawDrawable(SkDrawable*, SkMatrix const*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#16 0xeba725f4 in android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#17 0xeba98a42 in android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#18 0xeba9dcc8 in android::uirenderer::skiapipeline::SkiaPipeline::renderLayersImpl(android::uirenderer::LayerUpdateQueue const&, bool) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#19 0xeba9be44 in android::uirenderer::skiapipeline::SkiaPipeline::renderFrame(android::uirenderer::LayerUpdateQueue const&, SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, bool, android::uirenderer::Rect const&, sk_sp<SkSurface>, SkMatrix const&) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so

GPU线程 创建 SharedImageFactory

1
2
3
4
5
6
7
8
9
10
11
12
#0  gpu::SharedImageFactory::SharedImageFactory ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:96
#1 0xc0993164 in std::__1::make_unique<gpu::SharedImageFactory, gpu::GpuPreferences const&, gpu::GpuDriverBugWorkarounds const&, gpu::GpuFeatureInfo const&, gpu::SharedContextState*, gpu::MailboxManager*, gpu::SharedImageManager*, gpu::ImageFactory*, gpu::SharedImageStub*, bool>(gpu::GpuPreferences const&, gpu::GpuDriverBugWorkarounds const&, gpu::GpuFeatureInfo const&, gpu::SharedContextState*&&, gpu::MailboxManager*&&, gpu::SharedImageManager*&&, gpu::ImageFactory*&&, gpu::SharedImageStub*&&, bool&&) ()
at ../../buildtools/third_party/libc++/trunk/include/memory:3131
#2 gpu::SharedImageStub::MakeContextCurrentAndCreateFactory () at ./../../gpu/ipc/service/shared_image_stub.cc:310
#3 0xc0990360 in gpu::SharedImageStub::Create () at ./../../gpu/ipc/service/shared_image_stub.cc:51
#4 gpu::GpuChannel::CreateSharedImageStub () at ./../../gpu/ipc/service/gpu_channel.cc:598
#5 gpu::GpuChannel::Create () at ./../../gpu/ipc/service/gpu_channel.cc:432
#6 gpu::GpuChannelManager::EstablishChannel () at ./../../gpu/ipc/service/gpu_channel_manager.cc:171
#7 0xbf485426 in viz::GpuServiceImpl::EstablishGpuChannel(int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>) () at ./../../components/viz/service/gl/gpu_service_impl.cc:648
#8 0xbf4887a4 in base::internal::FunctorTraits<void (viz::GpuServiceImpl::*)(int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>), void>::Invoke<void (viz::GpuServiceImpl::*)(int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>), base::WeakPtr<viz::GpuServiceImpl>, int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)> >(void (viz::GpuServiceImpl::*)(int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>), base::WeakPtr<viz::GpuServiceImpl>&&, int&&, unsigned long long&&, bool&&, bool&&, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>&&) () at ../../base/bind_internal.h:499
#9 base::internal::InvokeHelper<true, void>::MakeItSo<void (viz::GpuServiceImpl::*)(int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>), base::WeakPtr<viz::GpuServiceImpl>, int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)> >(void (viz::GpuServiceImpl::*&&)(int, unsigned long long, bool, bool, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>), base::WeakPtr<viz::GpuServiceImpl>&&, int&&, unsigned long long&&, bool&&, bool&&, base::OnceCallback<void (mojo::ScopedHandleBase<mojo::MessagePipeHandle>)>&&) () at ../../base/bind_internal.h:619

UI线程创建GPUchannel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#0  viz::GpuClient::PreEstablishGpuChannel () at ./../../components/viz/host/gpu_client.cc:66
#1 0xbf5d79dc in content::RenderProcessHostImpl::Init () at ./../../content/browser/renderer_host/render_process_host_impl.cc:1822
#2 0xbf53f5cc in content::RenderFrameHostManager::InitRenderView () at ./../../content/browser/frame_host/render_frame_host_manager.cc:2087
#3 0xbf53e7a4 in content::RenderFrameHostManager::ReinitializeRenderFrame ()
at ./../../content/browser/frame_host/render_frame_host_manager.cc:2253
#4 0xbf53dc44 in content::RenderFrameHostManager::GetFrameHostForNavigation ()
at ./../../content/browser/frame_host/render_frame_host_manager.cc:740
#5 0xbf53d9fc in content::RenderFrameHostManager::DidCreateNavigationRequest ()
at ./../../content/browser/frame_host/render_frame_host_manager.cc:574
#6 0xbf5102b6 in content::FrameTreeNode::CreatedNavigationRequest () at ./../../content/browser/frame_host/frame_tree_node.cc:430
#7 0xbf5299d0 in content::NavigatorImpl::Navigate () at ./../../content/browser/frame_host/navigator_impl.cc:346
#8 0xbf51da24 in content::NavigationControllerImpl::NavigateWithoutEntry ()
at ./../../content/browser/frame_host/navigation_controller_impl.cc:2878
#9 content::NavigationControllerImpl::LoadURLWithParams () at ./../../content/browser/frame_host/navigation_controller_impl.cc:973
#10 0xbf512bac in content::NavigationControllerAndroid::LoadUrl () at ./../../content/browser/frame_host/navigation_controller_android.cc:294
#11 Java_com_bytedance_org_chromium_content_browser_framehost_NavigationControllerImpl_nativeLoadUrl ()
at gen/content/public/android/content_jni_headers/content/jni/NavigationControllerImpl_jni.h:241

GPU线程创建MailboxManagerSync

1
2
3
4
5
6
7
8
9
10
11
#0  gpu::gles2::CreateMailboxManager () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/mailbox_manager_factory.cc:17
#1 0xbf04696c in android_webview::DeferredGpuCommandService::CreateDeferredGpuCommandService ()
at ../../android_webview/browser/gfx/deferred_gpu_command_service.cc:135
#2 android_webview::DeferredGpuCommandService::GetInstance () at ../../android_webview/browser/gfx/deferred_gpu_command_service.cc:148
#3 0xbf03abe6 in android_webview::(anonymous namespace)::GetSyncPointManager () at ../../android_webview/lib/aw_main_delegate.cc:379
#4 0xc130f834 in content::(anonymous namespace)::CreateVizMainDependencies () at ./../../content/gpu/gpu_child_thread.cc:172
#5 content::GpuChildThread::GpuChildThread(base::RepeatingCallback<void ()>, content::ChildThreadImpl::Options const&, std::__1::unique_ptr<gpu::GpuInit, std::__1::default_delete<gpu::GpuInit> >) () at ./../../content/gpu/gpu_child_thread.cc:209
#6 0xc1310abc in content::GpuChildThread::GpuChildThread () at ./../../content/gpu/gpu_child_thread.cc:196
#7 content::InProcessGpuThread::Init () at ./../../content/gpu/in_process_gpu_thread.cc:59
#8 0xbfdb7a52 in base::Thread::ThreadMain () at ./../../base/threading/thread.cc:301
#9 0xbfddb234 in base::(anonymous namespace)::ThreadFunc () at ./../../base/threading/platform_thread_posix.cc:81

RenderThread创建AwGLSurface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#0  gpu::InProcessCommandBuffer::Initialize () at ../../gpu/ipc/in_process_command_buffer.cc:347
#1 0xbe42f34c in gpu::GLInProcessContext::Initialize () at ../../gpu/ipc/gl_in_process_context.cc:78
#2 0xbcb58f00 in android_webview::AwRenderThreadContextProvider::AwRenderThreadContextProvider ()
at ../../android_webview/browser/gfx/aw_render_thread_context_provider.cc:69
#3 android_webview::AwRenderThreadContextProvider::Create () at ../../android_webview/browser/gfx/aw_render_thread_context_provider.cc:32
#4 0xbcb5f5f4 in android_webview::SurfacesInstance::SurfacesInstance () at ../../android_webview/browser/gfx/surfaces_instance.cc:129
#5 android_webview::SurfacesInstance::GetOrCreateInstance () at ../../android_webview/browser/gfx/surfaces_instance.cc:55
#6 0xbcb5c3e4 in android_webview::HardwareRenderer::HardwareRenderer () at ../../android_webview/browser/gfx/hardware_renderer.cc:33
#7 0xbcb5df4c in android_webview::RenderThreadManager::DrawOnRT () at ../../android_webview/browser/gfx/render_thread_manager.cc:203
#8 0xbcb5731a in android_webview::AwDrawFnImpl::DrawInternal<AwDrawFn_DrawGLParams> () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:624
#9 android_webview::AwDrawFnImpl::DrawGL () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:275
#10 android_webview::(anonymous namespace)::DrawGLWrapper () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:133
#11 0xde1b6262 in android::(anonymous namespace)::draw_gl(int, void*, android::uirenderer::DrawGlInfo const&) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libwebviewchromium_plat_support.so
#12 0xe79f2e20 in android::uirenderer::WebViewFunctor::drawGl(android::uirenderer::DrawGlInfo const&) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#13 0xe79f256e in android::uirenderer::skiapipeline::GLFunctorDrawable::onDraw(SkCanvas*) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#14 0xe7919024 in SkCanvas::onDrawDrawable(SkDrawable*, SkMatrix const*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#15 0xe79115f4 in android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#16 0xe7937a42 in android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#17 0xe793ccc8 in android::uirenderer::skiapipeline::SkiaPipeline::renderLayersImpl(android::uirenderer::LayerUpdateQueue const&, bool) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#18 0xe793ae44 in android::uirenderer::skiapipeline::SkiaPipeline::renderFrame(android::uirenderer::LayerUpdateQueue const&, SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, bool, android::uirenderer::Rect const&, sk_sp<SkSurface>, SkMatrix const&) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#19 0xe793abc0 in android::uirenderer::skiapipeline::SkiaOpenGLPipeline::draw(android::uirenderer::renderthread::Frame const&, SkRect const&, SkRect const&, android::uirenderer::LightGeometry const&, android::uirenderer::LayerUpdateQueue*, android::uirenderer::Rect const&, bool, android::uirenderer::LightInfo const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, android::uirenderer::FrameInfoVisualizer*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#20 0xe7979df6 in android::uirenderer::renderthread::CanvasContext::draw() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#21 0xe79793de in std::__1::__function::__func<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0, std::__1::allocator<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0>, void ()>::operator() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#22 0xe7986cd0 in android::uirenderer::WorkQueue::process() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#23 0xe7986b2a in android::uirenderer::renderthread::RenderThread::threadLoop() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#24 0xe6d2689a in android::Thread::_threadLoop(void*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libutils.so

RenderThread 回放DrawQuad

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#0  gpu::gles2::GLES2Implementation::CreateAndConsumeTextureCHROMIUM () at ./../../gpu/command_buffer/client/gles2_implementation.cc:6433
#1 0xbd3a8ade in viz::DisplayResourceProvider::LockForRead () at ./../../components/viz/service/display/display_resource_provider.cc:478
#2 0xbd3b0d54 in viz::DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL () at ./../../components/viz/service/display/display_resource_provider.cc:843
#3 viz::DisplayResourceProvider::ScopedSamplerGL::ScopedSamplerGL () at ./../../components/viz/service/display/display_resource_provider.cc:864
#4 viz::GLRenderer::DrawContentQuadNoAA () at ./../../components/viz/service/display/gl_renderer.cc:2105
#5 viz::GLRenderer::DrawContentQuad () at ./../../components/viz/service/display/gl_renderer.cc:1971
#6 viz::GLRenderer::DrawTileQuad () at ./../../components/viz/service/display/gl_renderer.cc:1938
#7 viz::GLRenderer::DoDrawQuad () at ./../../components/viz/service/display/gl_renderer.cc:533
#8 0xbd3a0886 in viz::DirectRenderer::DrawRenderPass () at ./../../components/viz/service/display/direct_renderer.cc:714
#9 viz::DirectRenderer::DrawRenderPassAndExecuteCopyRequests () at ./../../components/viz/service/display/direct_renderer.cc:573
#10 0xbd3a6ea0 in viz::DirectRenderer::DrawFrame () at ./../../components/viz/service/display/direct_renderer.cc:429
#11 viz::Display::DrawAndSwap () at ./../../components/viz/service/display/display.cc:492
#12 0xbbc04b6e in android_webview::SurfacesInstance::DrawAndSwap () at ../../android_webview/browser/gfx/surfaces_instance.cc:239
#13 0xbbc01e48 in android_webview::HardwareRenderer::Draw () at ../../android_webview/browser/gfx/hardware_renderer.cc:197
#14 0xbbc0301a in android_webview::RenderThreadManager::DrawOnRT () at ../../android_webview/browser/gfx/render_thread_manager.cc:208
#15 0xbbbfc3ca in android_webview::AwDrawFnImpl::DrawInternal<AwDrawFn_DrawGLParams> () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:624
#16 android_webview::AwDrawFnImpl::DrawGL () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:275
#17 android_webview::(anonymous namespace)::DrawGLWrapper () at ../../android_webview/browser/gfx/aw_draw_fn_impl.cc:133
#18 0xdd5e5262 in android::(anonymous namespace)::draw_gl(int, void*, android::uirenderer::DrawGlInfo const&) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libwebviewchromium_plat_support.so
#19 0xe8712e20 in android::uirenderer::WebViewFunctor::drawGl(android::uirenderer::DrawGlInfo const&) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#20 0xe871256e in android::uirenderer::skiapipeline::GLFunctorDrawable::onDraw(SkCanvas*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#21 0xe8639024 in SkCanvas::onDrawDrawable(SkDrawable*, SkMatrix const*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#22 0xe86315f4 in android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#23 0xe8657a42 in android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#24 0xe865ccc8 in android::uirenderer::skiapipeline::SkiaPipeline::renderLayersImpl(android::uirenderer::LayerUpdateQueue const&, bool) ()
from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#25 0xe865ae44 in android::uirenderer::skiapipeline::SkiaPipeline::renderFrame(android::uirenderer::LayerUpdateQueue const&, SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, bool, android::uirenderer::Rect const&, sk_sp<SkSurface>, SkMatrix const&) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#26 0xe865abc0 in android::uirenderer::skiapipeline::SkiaOpenGLPipeline::draw(android::uirenderer::renderthread::Frame const&, SkRect const&, SkRect const&, android::uirenderer::LightGeometry const&, android::uirenderer::LayerUpdateQueue*, android::uirenderer::Rect const&, bool, android::uirenderer::LightInfo const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, android::uirenderer::FrameInfoVisualizer*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#27 0xe8699df6 in android::uirenderer::renderthread::CanvasContext::draw() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#28 0xe86993de in std::__1::__function::__func<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0, std::__1::allocator<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0>, void ()>::operator() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#29 0xe86a6cd0 in android::uirenderer::WorkQueue::process() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#30 0xe86a6b2a in android::uirenderer::renderthread::RenderThread::threadLoop() () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libhwui.so
#31 0xe8ca889a in android::Thread::_threadLoop(void*) () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libutils.so

GPU thread 用skia 绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#0  0xe6692354 in glDrawElements () from /tmp/adb-gdb-libs-99121FFAZ00A7P/system/lib/libGLESv2.so
#1 0xbcefdbcc in GrGLGpu::sendIndexedMeshToGpu () at ../../third_party/skia/include/gpu/gl/GrGLFunctions.h:303
#2 0xbcefdc2e in non-virtual thunk to GrGLGpu::sendIndexedMeshToGpu(GrPrimitiveType, GrBuffer const*, int, int, unsigned short, unsigned short, GrBuffer const*, int, GrPrimitiveRestart) () at ../../third_party/skia/include/gpu/gl/GrGLFunctions.h:303
#3 0xbcefda84 in GrMesh::sendToGpu () at ../../third_party/skia/src/gpu/GrMesh.h:246
#4 0xbcefd92e in GrGLGpu::draw () at ../../third_party/skia/src/gpu/gl/GrGLGpu.cpp:2624
#5 0xbcf015ac in GrGLGpuRTCommandBuffer::onDraw () at ../../third_party/skia/src/gpu/gl/GrGLGpuCommandBuffer.h:88
#6 0xbce88cda in GrGpuRTCommandBuffer::draw () at ../../third_party/skia/src/gpu/GrGpuCommandBuffer.cpp:101
#7 0xbce8a232 in GrOpFlushState::executeDrawsAndUploadsForMeshDrawOp(GrOp const*, SkRect const&, GrProcessorSet&&, GrPipeline::InputFlags, GrUserStencilSettings const*) () at ../../third_party/skia/src/gpu/GrOpFlushState.cpp:56
#8 0xbced1f7a in GrSimpleMeshDrawOpHelper::executeDrawsAndUploads () at ../../third_party/skia/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp:109
#9 0xbce9c79c in GrOp::execute () at ../../third_party/skia/src/gpu/ops/GrOp.h:181
#10 0xbce9c6a0 in GrRenderTargetOpList::onExecute () at ../../third_party/skia/src/gpu/GrRenderTargetOpList.cpp:512
#11 0xbce8308a in GrOpList::execute () at ../../third_party/skia/include/private/GrOpList.h:41
#12 GrDrawingManager::executeOpLists () at ../../third_party/skia/src/gpu/GrDrawingManager.cpp:496
#13 GrDrawingManager::flush () at ../../third_party/skia/src/gpu/GrDrawingManager.cpp:357
#14 0xbce83464 in GrDrawingManager::flushSurfaces () at ../../third_party/skia/src/gpu/GrDrawingManager.cpp:575
#15 0xbce9b1dc in GrDrawingManager::flushSurface () at ../../third_party/skia/src/gpu/GrDrawingManager.h:89
#16 GrRenderTargetContext::flush () at ../../third_party/skia/src/gpu/GrRenderTargetContext.cpp:1757
#17 0xbbdb209a in SkSurface::flush () at ../../third_party/skia/src/image/SkSurface.cpp:247
---Type <return> to continue, or q <return> to quit---
#18 SkSurface::flush () at ../../third_party/skia/src/image/SkSurface.cpp:243
#19 0xbd4dc312 in gpu::raster::RasterDecoderImpl::DoEndRasterCHROMIUM ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/raster_decoder.cc:2193
#20 gpu::raster::RasterDecoderImpl::HandleEndRasterCHROMIUM () at ../../gpu/command_buffer/service/raster_decoder_autogen.h:157
#21 0xbd4df1a6 in gpu::raster::RasterDecoderImpl::DoCommandsImpl<false> ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/raster_decoder.cc:1184
#22 gpu::raster::RasterDecoderImpl::DoCommands () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/raster_decoder.cc:1243
#23 0xbd3a25a0 in gpu::CommandBufferService::Flush () at ./../../gpu/command_buffer/service/command_buffer_service.cc:69
#24 0xbd53d160 in gpu::CommandBufferStub::OnAsyncFlush () at ./../../gpu/ipc/service/command_buffer_stub.cc:522

gpu线程创建skia surface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#0  gpu::SharedImageRepresentationSkiaImpl::SharedImageRepresentationSkiaImpl ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:359
#1 0xbd5d91ea in base::RefCounted<gpu::SharedContextState, base::DefaultRefCountedTraits<gpu::SharedContextState> >::DeleteInternal<gpu::SharedContextState> () at ../../base/memory/ref_counted.h:352
#2 base::DefaultRefCountedTraits<gpu::SharedContextState>::Destruct () at ../../base/memory/ref_counted.h:318
#3 base::RefCounted<gpu::SharedContextState, base::DefaultRefCountedTraits<gpu::SharedContextState> >::Release ()
at ../../base/memory/ref_counted.h:341
#4 scoped_refptr<gpu::SharedContextState>::Release () at ../../base/memory/scoped_refptr.h:297
#5 scoped_refptr<gpu::SharedContextState>::~scoped_refptr () at ../../base/memory/scoped_refptr.h:209
#6 std::__1::make_unique<gpu::SharedImageRepresentationSkiaImpl, gpu::SharedImageManager*&, gpu::SharedImageBackingGLTexture*, scoped_refptr<gpu::SharedContextState>, sk_sp<SkPromiseImageTexture>&, gpu::MemoryTypeTracker*&, unsigned int, unsigned int>(gpu::SharedImageManager*&, gpu::SharedImageBackingGLTexture*&&, scoped_refptr<gpu::SharedContextState>&&, sk_sp<SkPromiseImageTexture>&, gpu::MemoryTypeTracker*&, unsigned int&&, unsigned int&&) () at ../../buildtools/third_party/libc++/trunk/include/memory:3131
#7 gpu::SharedImageBackingGLTexture::ProduceSkia ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:615
#8 0xbd5c925e in base::RefCounted<gpu::SharedContextState, base::DefaultRefCountedTraits<gpu::SharedContextState> >::DeleteInternal<gpu::SharedContextState> () at ../../base/memory/ref_counted.h:352
#9 base::DefaultRefCountedTraits<gpu::SharedContextState>::Destruct () at ../../base/memory/ref_counted.h:318
#10 base::RefCounted<gpu::SharedContextState, base::DefaultRefCountedTraits<gpu::SharedContextState> >::Release ()
at ../../base/memory/ref_counted.h:341
#11 scoped_refptr<gpu::SharedContextState>::Release () at ../../base/memory/scoped_refptr.h:297
#12 scoped_refptr<gpu::SharedContextState>::~scoped_refptr () at ../../base/memory/scoped_refptr.h:209
#13 gpu::SharedImageManager::ProduceSkia () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_manager.cc:192
#14 0xbd5bb6a2 in base::RefCounted<gpu::SharedContextState, base::DefaultRefCountedTraits<gpu::SharedContextState> >::DeleteInternal<gpu::SharedContextState> () at ../../base/memory/ref_counted.h:352
#15 base::DefaultRefCountedTraits<gpu::SharedContextState>::Destruct () at ../../base/memory/ref_counted.h:318
#16 base::RefCounted<gpu::SharedContextState, base::DefaultRefCountedTraits<gpu::SharedContextState> >::Release ()
at ../../base/memory/ref_counted.h:341
#17 scoped_refptr<gpu::SharedContextState>::Release () at ../../base/memory/scoped_refptr.h:297
#18 scoped_refptr<gpu::SharedContextState>::~scoped_refptr () at ../../base/memory/scoped_refptr.h:209
#19 gpu::SharedImageRepresentationFactory::ProduceSkia ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:337
#20 gpu::raster::RasterDecoderImpl::DoBeginRasterCHROMIUM ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/raster_decoder.cc:2026
#21 gpu::raster::RasterDecoderImpl::HandleBeginRasterCHROMIUMImmediate () at ../../gpu/command_buffer/service/raster_decoder_autogen.h:130
#22 0xbd5bf1b6 in gpu::raster::RasterDecoderImpl::DoCommandsImpl<false> ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/raster_decoder.cc:1205
#23 gpu::raster::RasterDecoderImpl::DoCommands () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/raster_decoder.cc:1243
#24 0xbd4825b0 in gpu::CommandBufferService::Flush () at ./../../gpu/command_buffer/service/command_buffer_service.cc:75
#25 0xbd61d170 in gpu::CommandBufferStub::OnAsyncFlush () at ./../../gpu/ipc/service/command_buffer_stub.cc:525
#26 0xbd61cace in trace_event_internal::ScopedTracer::ScopedTracer () at ../../base/trace_event/trace_event.h:983
#27 IPC::MessageT<GpuCommandBufferMsg_RegisterTransferBuffer_Meta, std::__1::tuple<int, base::UnsafeSharedMemoryRegion>, void>::Dispatch<gpu::CommandBufferStub, gpu::CommandBufferStub, void, void (gpu::CommandBufferStub::*)(int, base::UnsafeSharedMemoryRegion)> ()
at ../../ipc/ipc_message_templates.h:143

gpu线程创建shared image backing 实际就是GL_TEXTURE_2D

1
2
3
4
5
6
7
8
9
10
11
#0  gpu::SharedImageBackingFactoryGLTexture::MakeBacking ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:1241
#1 0xbd480cb0 in gpu::SharedImageBackingFactoryGLTexture::CreateSharedImage ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:1052
#2 0xbd480792 in gpu::SharedImageBackingFactoryGLTexture::CreateSharedImage ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:857
#3 0xbd483336 in gpu::SharedImageFactory::CreateSharedImage ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:115
#4 0xbd4df890 in gpu::SharedImageStub::OnCreateSharedImage () at ./../../gpu/ipc/service/shared_image_stub.cc:99
#5 0xbd4df5a0 in base::DispatchToMethodImpl<gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>, 0u>(gpu::SharedImageStub* const&, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&, std::__1::integer_sequence<unsigned int, 0u>) ()
at ../../base/tuple.h:52

gpu线程创建 EglImage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#0  gpu::gles2::TextureDefinition::TextureDefinition ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/texture_definition.cc:361
#1 0xbd3ad1b0 in gpu::gles2::MailboxManagerSync::ProduceTexture ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/mailbox_manager_sync.cc:250
#2 0xbd3da506 in gpu::SharedImageBackingPassthroughGLTexture::ProduceLegacyMailbox ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc:680
#3 0xbd3ca5bc in gpu::SharedImageRepresentationFactoryRef::ProduceLegacyMailbox ()
at ../../gpu/command_buffer/service/shared_image_representation.h:73
#4 gpu::SharedImageFactory::RegisterBacking () at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:296
#5 0xbd3ca36e in gpu::SharedImageFactory::CreateSharedImage ()
at ../../third_party/mesa_headers/../../gpu/command_buffer/service/shared_image_factory.cc:120
#6 0xbd426890 in gpu::SharedImageStub::OnCreateSharedImage () at ./../../gpu/ipc/service/shared_image_stub.cc:99
#7 0xbd4265a0 in base::DispatchToMethodImpl<gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>, 0u>(gpu::SharedImageStub* const&, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&, std::__1::integer_sequence<unsigned int, 0u>) ()
at ../../base/tuple.h:52
#8 base::DispatchToMethod<gpu::SharedImageStub*, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params> >(gpu::SharedImageStub* const&, void (gpu::SharedImageStub::*)(GpuChannelMsg_CreateSharedImage_Params const&), std::__1::tuple<GpuChannelMsg_CreateSharedImage_Params>&&) () at ../../base/tuple.h:60

eglImage被放入MailboxManagerSync的texture_to_group_里面

然后在RenderThread DrawQuad的时候通过resource id 拿到resource,通过resource的mailbox name,调用CreateAndConsumeTextureCHROMIUM,先序列化,再回放,取到gpu线程绘制的eglImage。

Media 相关 Tips

Fragment MP4

简称fmp4,一种特殊的MP4封装。
常规的mp4文件将metadata放在文件结尾,ffmpeg可以用 -movflags faststart将metadata放在开头以支持更好的播放。
分片的mp4会将每个片段的metadata和片段一起存放,并在头部有一个moov。
moov [moof mdat]+
在fmp4中,moov只保存基本信息,如track的数量,codec信息等。
Sample的位置和大小信息都保存在moof中。紧跟着moof的就是moof中记录了信息的sample块(mdat)。

MP4的一些box:
ftyp File Type Box
moov Movie Header Box
sidx Segment Index
moof movie fragment

分片的mp4结构:头部moov+sidx
每个分片moof+mdat

MP4的交织、分段、分片

以下操作基于MP4Box。

简单说:如果要支持边下边播,交织;如果需要流畅跳转,分段;如果需要自适应切换分辨率,分片。

Interleaving (-inter) is when (groups of ) samples of different tracks are stored alternatively in the file: e.g. N milliseconds of video samples, followed by N milliseconds of audio samples, followed by N milliseconds of video samples … Typically, interleaved samples are grouped within an interleaving window. Interleaving reduces disk accesses, playback buffer requirements and enables progressive download and playback.
交织(-inter)是指不同轨道的(一组)样本交替存储在文件中:例如
N毫秒的视频样本,接着是N毫秒的音频样本,接着是N毫秒的视频样本……通常,交错的样本在交错窗口内分组。
交错可减少磁盘访问,回放缓冲要求并支持渐进式下载和回放。

Fragmentation (-frag) is an optional process applicable to the MP4 file format. By default, MP4 files generated with MP4Box are not fragmented. This process consists in using Movie Fragments (moof). Movie Fragments is a tool introduced in the ISO spec to improve recording of long-running sequences and that is now used for HTTP streaming. Even if it is possible, according to the ISO spec, to do interleaving on fragments, MP4Box currently does not support it, because we don’t see important use cases for it. For instance, all audio samples within a fragment are contiguously stored and similarly for the video samples. The only way to ‘interleave’ tracks is to have small fragments. There may be some overhead for big files, we welcome comments on this.

分段(-frag)是适用于MP4文件格式的可选过程。
默认情况下,使用MP4Box生成的MP4文件不会碎片化。
此过程包括使用电影片段(moof)。
Movie Fragments是ISO规范中引入的工具,用于改进长时间运行序列的记录,现在用于HTTP流式传输。
即使有可能,根据ISO规范,对片段进行交错,MP4Box目前也不支持它,因为我们没有看到重要的用例。
例如,片段内的所有音频样本被连续存储,并且类似地用于视频样本。
“交错”轨道的唯一方法是使用小片段。
大文件可能有一些开销,我们欢迎对此发表评论。

Segmentation (-dash) is the process of creating segments, parts of an original file meant for individual/separate HTTP download (not necessarily for individual playback). A segment can be a part of a big file or a separate file. It is not specific to the MP4 file format (in particular it may apply to MPEG-2 TS) but a segment may imply specific ISO signaling (styp and sidx boxes, for instance). A segment is what is refered to by the XML file used to drive the HTTP Streaming and segment boundaries can be convenient places for bitstream switching. Segmentation often implies fragmentation but not necessarily.

分段(-dash)是创建段的过程,原始文件的一部分用于单独/单独的HTTP下载(不一定用于单独回放)。
段可以是大文件的一部分或单独的文件。
它不是特定于MP4文件格式(特别是它可以应用于MPEG-2TS),但是段可以暗示特定的ISO信令(例如styp和sidx框)。
段是用于驱动HTTP流的XML文件所指的段,段边界可以是用于比特流切换的便利位置。
细分通常意味着碎片,但不一定。

DASH的构成

Danymic Adaptive Streaming over HTTP。类似苹果的HLS。

MPD: an XML document describing where the various media resources present in the content are located. The media resources can be single-media (for example, a video-only MP4 file) or a multiplexed set of streams (for example an AV MPEG-2 Transort Stream). Streams can be scalable (such as SVC) but we won’t go into such details as GPAC doesn’t support advanced description of scalable streams in DASH. Some media resources may exist in different versions, for example different bitrate or language or resolutions. In DASH, such a “version” of the stream is called a representation, and all representations are grouped together in an AdaptationSet.
segment: a continuous part of a media resource. The segment is the smallest part of the media that can be located in the MPD. What a segment exactly contains depends on the underlying media format of the content.
subsegment: a continuous part of a segment, or of a subsegment.
sidx: short name for SegmentIndexBox, this is an ISOBMF (MP4/3GP container) structure describing a segment by giving its earliest presentation time, how the segment is further divided into subsegments, random access points locations (byte offset) and timing in the segment payload. The goal of the SIDX is to build an index of the segment at a given granularity to simplify trick modes (seeking, fast-forward, fast-rewind, …).
Google翻译:
MPD:描述内容中存在的各种媒体资源的位置的XML文档。
媒体资源可以是单媒体(例如,仅视频MP4文件)或多路复用的流集(例如AV MPEG-2 Transort流)。
流可以是可扩展的(例如SVC),但我们不会详细介绍GPAC不支持DASH中可伸缩流的高级描述。
某些媒体资源可能存在于不同版本中,例如不同的比特率或语言或分辨率。
在DASH中,流的这种“版本”被称为表示,并且所有表示在AdaptationSet中被组合在一起。
segment:媒体资源的连续部分。
该段是可以位于MPD中的媒体的最小部分。
段确切包含的内容取决于内容的基础媒体格式。
子段:段或子段的连续部分。
sidx:SegmentIndexBox的短名称,这是一个ISOBMF(MP4 / 3GP容器)结构,通过给出其最早的呈现时间,段如何进一步划分为子段,随机访问点位置(字节偏移)和段中的时序来描述段
有效载荷。
SIDX的目标是以给定的粒度构建段的索引,以简化特技模式(搜索,快进,快退,……)。

MKV MIME type

Mkv没有官方的mime type,一般用video/x-matroska

获取服务器返回的http header中的mime type
Curl -I http://xxx

流媒体协议

RTMP 基于tcp的低延时协议,flash支持
HLS 基于http的协议,中高延时
DASH 类似HLS,中高延时
WebRTC 低延时协议,但是支持的设备有限

YUV颜色模式

YUV分为打包格式和平面格式。
Packed format vs. planar format
在打包格式中,YUV存储在一个序列中,在平面格式中,YUV被存储为三个单独的平面,平面格式需要多个纹理,每个平面需要一个纹理。

## Linux进程获取本进程是否正在被debug
Chromium中 base::debug::WaitForDebugger(time, silent);
原理:
/proc/self/status中有一条记录: TracerPid: 0
被调试时有值。
1.可以用此方法让进程等待debug
while( ! isdebug() ) {
sleep(1);
}
isdebug中读取TracerPid的值看是否为0。

2.还有一种比较粗暴的方法
volitale int test=1;
while(test) {
sleep(1);
}
GDB attach之后,set var test=0

用这个方法可以在一些不方便打断点的地方(如浏览器启动时)等待gdb连接。

视频码率控制

CBR VBR
CBR constant bitrate 恒定比特率
VBR variable bitrate 可变比特率
VBV Video Buffering Verifier 视频缓冲区验证

几种控制模式:

Constant QP/CQP
QP quantization parameter 控制Mcroblock的质量,QP越高压缩率越高质量越差。
CQP会导致比特率根据场景复杂度变化很大,并且编码效率降低。一般只作为研究用。

Average Bitrate ABR
ffmpeg -i input -c:v libx264 -b:v 1M output
因为编码器无法准确知道未来的帧分布情况,因此只能估计,
ABR模式会导致质量波动严重,不建议使用.

Constant Bitrate
ffmpeg -i input -c:v libx264 -x264-params “nal-hrd=cbr:fore-cfr=1” -b:v 1M -minrate 1M -maxrate 1M -bufsize 2M output
ffmpeg -i input -c:v libvpx-vp9 -b:v 1M -maxrate 1M -minrate 1M output
固定比特率,使用libx264时需要输出格式为ts,因为mp4不支持NAL。
如果输入源易于编码,此模式会浪费带宽。

2-Pass ABR
编码器通过两次编码生成码流,第一次计算编码帧的编码成本,第二次更有效的使用bit,确保输出质量最佳。
x264
ffmpeg -i input -c:v libx264 -b:v 1M -pass 1 -f mp4 /dev/null
ffmpeg -i input -c:v libx264 -b:v 1M -pass 2 .mp4
x265
ffmpeg -i input -c:v libx264 -b:v 1M -x265-params pass=1 -f mp4 /dev/null
ffmpeg -i input -c:v libx264 -b:v 1M -x265-params pass=2 .mp4
vp9
ffmpeg -i input -c:v libvpx-vp9 -b:v 1M -pass 1 -f webm /dev/null
ffmpeg -i input -c:v libvpx-vp9 -b:v 1M -pass 2 .webm

Constant Quality (CQ) / Constant Rate Factor (CRF)
CRF是x264和x265的默认质量设置参数,可选值0-51,越小质量越好。
CRF模式在编码过程中保持恒定的质量,和2passABR相比,CRF模式只需设置质量,2passABR可以控制文件大小,
CRF在1pass编码中提供最佳的压缩率,但是无法限制文件大小和比特率,因此不建议流式传输使用。

ffmpeg -i input -c:v libx264 -crf 23
ffmpeg -i input -c:v libx265 -crf 28
ffmpeg -i input -c:v libvpx-vp9 -crf 30 -b:v 0

Constrained Encoding (VBV)
确保最大最小的比特率,可以和2passABR、CRF同时使用。
ffmpeg -i input -c:v libx264 -crf 23 -maxrate 1M -bufsize 2M
ffmpeg -i input -c:v libx265 -crf 28 -x265-params vbv-maxrate=1000:vbv-bufsize=2000
ffmpeg -i input -c:v libvpx-vp9 -crf 30 -b:v 2M

对于x264 x265,可以用-tune zerolatency和 -preset ultrafast提高编码速度,降低质量。
对于VP9,可以用-quality realtime和-speed 5。

2passABR+VBV
ffmpeg -i input -c:v libx264 -b:v 1M -maxrate 1M -bufsize 2M -pass 1 -f mp4 /dev/null
ffmpeg -i input -c:v libx264 -b:v 1M -maxrate 1M -bufsize 2M -pass 2
ffmpeg -i input -c:v libx265 -b:v 1M -x265-params pass=1:vbv-maxrate=1000:vbv-bufsize=2000 -f mp4 /dev/null
ffmpeg -i input -c:v libx265 -b:v 1M -x265-params pass=2:vbv-maxrate=1000:vbv-bufsize=2000

ffmpeg -i input -c:v libvpx-vp9 -b:v 1M -maxrate 1M -bufsize 2M -pass 1 -f webm /dev/null
ffmpeg -i input -c:v libvpx-vp9 -b:v 1M -maxrate 1M -bufsize 2M -pass 2

bufsize如果不确定,可以设置成maxrate的两倍大小。如果客户端内存很少,可以与maxrate相同。如果限制比特率,可以设置为maxrate的一半或更低。

总结,根据使用场景:
存档:CRF
流:2passCRF或ABR+VBV
直播:1passCRF或ABR+VBV
为设备编码:2passABR
Shaka player
Google的js播放器,支持MSE 、EME、DASH等播放格式。
不支持SegmentList中的SegmentURL@indexRange属性,
仅支持SegmentList@duration或SegmentTimeline

ffmpeg添加分辨率水印(用于测试DASH自适应切换分辨率)

ffmpeg -y -i frag_aac.flv -c:a libfdk_aac -ac 2 -ab 128k -c:v libx264 -x264opts ‘keyint=24:min-keyint=24:no-scenecut’ -b:v 800k -maxrate 800k -bufsize 500k -vf “scale=-1:540, drawtext=fontfile=/usr/share/fonts/truetype/msttcorefonts/arial.ttf: text=’540:%{frame_num}’: start_number=1: x=(w-tw)/2: y=h-(2*lh): fontcolor=black: fontsize=20: box=1: boxcolor=white: boxborderw=5” ./dash_800k.mp4

检查关键帧位置

两种方法:
ffprobe -loglevel error -skip_frame nokey -select_streams v:0 -show_entries frame=pkt_pts_time -of csv=print_section=0 frag_dash.mp4

ffprobe frag_dash.mp4 -show_frames -select_streams v:0 | grep key_frame

检查关键帧对齐

Check key frame alignment
https://gpac.wp.imt.fr/2015/11/02/check-key-frame-alignment-with-mp4box/

平均GOP长度

Get average GOP length:
MP4Box -info TRACK_ID source1.mp4 2>&1 | grep GOP

MP4Box -std -diso source1.mp4 2>&1 | grep SyncSampleEntry > 1.txt

打印关键帧时间

print key frame time:
ffprobe -loglevel error -skip_frame nokey -select_streams v:0 -show_entries frame=pkt_pts_time -of csv=print_section=0 input.mp4

如果MP4Box生成的video 和audio切片数量不同
Different number of segments for video and audio when use mp4box:

https://github.com/gpac/gpac/issues/774
https://github.com/gpac/gpac/issues/771

DASH 和 HLS

DASH 使用.mpd 文件索引,切片格式为fragment mp4
HLS使用.m3u8 文件索引,切片格式为ts

ffmpeg和mp4box为dash格式转码

ffmpeg encode for dash :
must has I-frames on same timestamp

重新编码视频,在相同位置插入I帧:

ffmpeg -y -i inputfile -c:a libfdk_aac -ac 2 -ab 128k -c:v libx264 -x264opts ‘keyint=24:min-keyint=24:no-scenecut’ -b:v 1500k -maxrate 1500k -bufsize 1000k -vf “scale=-1:720” outputfile720.mp4

ffmpeg -y -i inputfile -c:a libfdk_aac -ac 2 -ab 128k -c:v libx264 -x264opts ‘keyint=24:min-keyint=24:no-scenecut’ -b:v 800k -maxrate 800k -bufsize 500k -vf “scale=-1:540” outputfile540.mp4

ffmpeg -y -i inputfile -c:a libfdk_aac -ac 2 -ab 128k -c:v libx264 -x264opts ‘keyint=24:min-keyint=24:no-scenecut’ -b:v 400k -maxrate 400k -bufsize 400k -vf “scale=-1:360” outputfile360.mp4

keyint:GOP长度
min-keyint:最小GOP长度
Dash自适应切换清晰度要求不同分辨率的视频流必须在相同位置有关键帧。

用MP4Box添加track:

MP4Box -add outputfile720.mp4#video -fps 24 output.mp4

用MP4Box制作dash:

MP4Box -dash 2000 -rap -bs-switching no output.mp4#trackID=1:dur=60 output.mp4#trackID=2:dur=60 output.mp4#trackID=3:dur=60 -out mpds/output_dash.mpd

ffmpeg转码时设置GOP的参数

libx264:
-g sets the keyframe interval.
-keyint_min sets the minimum keyframe interval.
-x264-params “keyint=x:min-keyint=y” is the same as -g x -keyint_min y.
Note: When setting both to the same value, the minimum is internally set to half the maximum interval plus one, as seen in the x264 code:
h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
libx265:
-g is not implemented.
-x265-params “keyint=x:min-keyint=y” works.
libvpx-vp9:
-g sets the keyframe interval.
-keyint_min sets the minimum keyframe interval
Note: Due to how FFmpeg works, -keyint_min is only forwarded to the encoder when it is the same as -g. In the code from libvpxenc.c in FFmpeg we can find:
if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size) enccfg.kf_min_dist = avctx->keyint_min; if (avctx->gop_size >= 0) enccfg.kf_max_dist = avctx->gop_size;
This might be a bug (or lack of feature?), since libvpx definitely supports setting a different value for kf_min_dist.

libx264为DASH转码

x264 –output intermediate_2400k.264 –fps 24 –preset slow –bitrate 2400 –vbv-maxrate 4800 –vbv-bufsize 9600 –min-keyint 48 –keyint 48 –scenecut 0 –no-scenecut –pass 1 –video-filter “resize:width=1280,height=720” inputvideo.mkv

MP4Box -add intermediate.264 -fps 24 output_2400k.mp4

MP4Box -dash 4000 -frag 4000 -rap -segment-name segment_ output_2400k.mp4

MP4Box -dash 4000 -frag 4000 -rap -segment-name segment_ video.mp4#audio

I帧和IDR帧的区别

Instantaneous Decoder Refresh (IDR) frames: These allow independent decoding of the following frames, without access to frames previous to the IDR frame.
Non-IDR-frames: These require a previous IDR frame for the decoding to work. Non-IDR frames can be used for scene cuts in the middle of a GOP (group of pictures).

An IDR frame is a special type of I-frame in H.264. An IDR frame specifies that no frame after the IDR frame can reference any frame before it. This makes seeking the H.264 file easier and more responsive in the player.

GOP boundary: between two IDR frames

IDR帧是一类特殊的I帧,IDR帧之后的帧都不能参考IDR帧之前的内容

两个IDR帧之间的区域称为GOP,group of pictures

开启scene cut后,GOP内有可能被插入新的非IDR帧的I帧

scenecut 场景切换
x264有一指标,用于衡量每一帧与前一帧的差异程度。
若该值小于scenecut,则检测到’场景切换’(‘scenecut’)条件,
并放置一个I帧 (前提:该帧与上一个IDR帧的间隔小于min-keyint,否则就放置一个IDR帧)。
提高scenecut值将增加检测到的’场景切换’数量。
ffmpeg中使用-sc_threshold设置此项。
将scenecut设为0,相当于设定 no-scenecut

转码DASH时为了I帧的稳定,需要关闭场景切换。

ffmpeg提取音频

ffmpeg -i input.mkv # show stream numbers and formats
ffmpeg -i input.mkv -c copy audio.m4a # AAC
ffmpeg -i input.mkv -c copy audio.mp3 # MP3
ffmpeg -i input.mkv -c copy audio.ac3 # AC3
ffmpeg -i input.mkv -an -c copy video.mkv
ffmpeg -i input.mkv -map 0:1 -c copy audio.m4a # stream 1

ffmpeg制作hls切片

ffmpeg -i input.mp4 -c:v libx264 -c:a aac -strict -2 -f hls output.m3u8

media source中切换track

SourceBuffer.videoTracks[I].selected = true/false

用MediaSource播放MP4的要求

MSE(Media Source Extensions)需要mp4中将moov放在文件开始,并有moof(movie fragment box )在mdat(media data box)前面