编译与运行#
参考文档:
macOS 上需要 Xcode SDK,可以先检查:
ls -l `xcode-select -p`/Platforms/MacOSX.platform/Developer/SDKssh安装 depot_tools:
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.gitsh将 depot_tools 加入环境变量。这里用 $HOME,避免把机器用户名写死:
echo 'export PATH="$HOME/zen/depot_tools:$PATH"' >> ~/.zshrc
source ~/.zshrcsh获取 Chromium 源码:
caffeinate fetch chromiumsh当前本地工作区结构是:
/Users/zhyw/zen/chromium # gclient 工作区
/Users/zhyw/zen/chromium/src # 真正的 Chromium 源码根目录text生成构建文件和编译:
cd /Users/zhyw/zen/chromium/src
gn gen out/Default
autoninja -C out/Default chromesh运行:
out/Default/Chromium.app/Contents/MacOS/Chromiumsh源码目录#
Chromium 源码根目录是 chromium/src。外层 chromium/ 主要是 gclient 工作区,包含 .gclient、.cipd 等依赖同步文件。
产品层
chrome/
android_webview/
headless/
ash/
浏览器核心嵌入层
content/
Web 平台和渲染引擎
third_party/blink/
v8/
gin/
渲染后半段
cc/
components/viz/
gpu/
skia/
基础服务和 IPC
services/
mojo/
通用能力
base/
net/
media/
storage/
ui/
components/
构建、测试、工具、依赖
build/
tools/
testing/
third_party/text最容易混淆的是这三个目录:
| 目录 | 定位 |
|---|---|
chrome/ | Chrome 产品层,包含 UI、浏览器功能、产品集成 |
content/ | 多进程浏览器核心,负责导航、frame、进程、安全、WebContents |
third_party/blink/ | Blink 渲染引擎和 Web Platform 实现 |
可以先记成一句话:
chrome 是产品,
content 是页面运行的多进程外壳,
Blink 是 DOM / CSS / Layout / Paint 的引擎。textchrome:Chrome 产品层#
chrome/ 包含 Chrome 这个产品的应用层代码。它不是浏览器内核本身,而是把 content/、components/、ui/、各种服务整合成用户可见的浏览器。
常见子目录:
| 目录 | 作用 |
|---|---|
chrome/app/ | Chrome 进程启动入口、资源、delegate |
chrome/browser/ | Browser Process 中的 Chrome 产品逻辑 |
chrome/browser/ui/ | 浏览器窗口、标签页、地址栏、菜单、WebUI |
chrome/common/ | 多进程共享的 Chrome 常量、开关、数据结构 |
chrome/renderer/ | Chrome 产品在 Renderer Process 中的扩展逻辑 |
chrome/test/ | Chrome 层测试 |
用户在地址栏输入 URL 时,最前面的入口属于 chrome/:
地址栏 / omnibox
→ chrome/browser/ui
→ Chrome tab / browser window
→ content/public/browser
→ content/browser 接管导航textchrome/ 的边界意识很重要。Chrome 产品层不应该直接操作 Blink 的 DOM 或 Layout,而是通过 content/public 提供的 API 使用网页内容容器,比如 WebContents。
content:多进程浏览器核心#
content/ 是渲染一个页面所需要的核心基础设施。它实现多进程、沙盒化、导航、frame 管理、Renderer 管理、GPU 加速接入等能力,但不包含 Chrome 产品功能。
content/ 和 chrome/ 的分工:
| 层级 | 负责 | 不负责 |
|---|---|---|
content/ | Web Platform 所需的页面运行基础,多进程、导航、frame、sandbox、WebContents | Chrome 产品 UI、同步、翻译、Safe Browsing 等产品能力 |
chrome/ | 产品功能、浏览器 UI、Profile 集成、厂商服务集成 | Blink 内核实现细节 |
content/ 的目录通常按进程划分:
| 目录 | 对应角色 | 说明 |
|---|---|---|
content/browser/ | Browser Process | 导航、WebContents、FrameTree、RenderFrameHost、权限、安全、进程管理 |
content/renderer/ | Renderer Process | Renderer 入口、RenderFrameImpl、和 Blink 的连接 |
content/gpu/ | GPU Process 相关 | content 对 GPU 进程的嵌入和启动逻辑 |
content/utility/ | Utility Process | 辅助进程相关代码 |
content/common/ | 多进程共享 | browser/renderer 共用的数据结构、mojom、常量 |
content/public/ | 对 embedder 暴露 API | Chrome、WebView、headless 通过这里使用 content |
content/shell/ | 最小浏览器壳 | 不带完整 Chrome 产品层,用于测试 content / Blink |
阅读导航主线时,几个类值得先建立印象:
| 概念 | 代码位置 | 说明 |
|---|---|---|
| 标签页网页内容容器 | content/browser/web_contents/web_contents_impl.* | WebContentsImpl 是 tab 内容的核心容器 |
| 导航请求 | content/browser/renderer_host/navigation_request.* | NavigationRequest 表示一次正在进行的导航 |
| Browser 侧 frame | content/browser/renderer_host/render_frame_host_impl.* | RenderFrameHostImpl 代表 Renderer 中的一个 frame |
| Renderer 主线程入口 | content/renderer/render_thread_impl.* | Renderer Process 和 browser 侧通信的核心连接点 |
content/public:embedder 边界#
content/public 是 content 暴露给上层 embedder 的 API。Chrome、Android WebView、headless 都应该通过这里使用 content,而不是直接 include content/browser 或 content/renderer 的内部实现。
这层 API 的作用:
chrome/ 可以使用 content/public
content/ 不依赖 chrome/
content 内部实现不随便暴露给上层产品text常见边界类:
| 类 / 目录 | 作用 |
|---|---|
content/public/browser/WebContents | 上层看到的网页内容容器接口 |
content/public/browser/WebContentsObserver | 观察导航、加载、frame 等事件 |
content/public/browser/ContentBrowserClient | content 回调 embedder 的 Browser 侧接口 |
content/public/renderer/ContentRendererClient | content 回调 embedder 的 Renderer 侧接口 |
content/public/common/ | 跨进程、跨 embedder 的公共数据结构 |
components:可复用功能层#
components/ 用来放多个产品或多个 embedder 复用的功能。它不是随便拆模块的地方,而是给确实有复用需求的功能提供稳定边界。
典型使用场景:
| 场景 | 说明 |
|---|---|
| Chrome 和 iOS Chrome 共用 | //ios 不依赖 //chrome,共享逻辑需要抽出 |
| Chrome 和 Android WebView 共用 | 多个 content embedder 共享同一套功能 |
| Browser Process 和 Blink 共用 | 如果不是 Blink 自己拥有的代码,可以放在 components |
一次网页打开时,权限、历史记录、下载、favicon、内容设置等功能可能会通过 components/ 参与,但页面生命周期本身仍由 content/ 管理。
services 与 mojo#
services/ 里是基础服务,mojo/ 是服务和模块之间通信的 IPC 基础设施。
可以这样区分:
services/ 定义服务集合
mojo/ 提供服务之间的接口定义和通信方式text常见服务:
| 目录 | 服务 |
|---|---|
services/network/ | Network Service |
services/audio/ | Audio Service |
services/device/ | Device Service |
services/data_decoder/ | 数据解码服务 |
services/tracing/ | tracing / perfetto |
services/viz/ | Viz service 接口和运行 glue |
mojo 里的几个关键词:
| 概念 | 含义 |
|---|---|
mojom | Mojo 接口定义文件 |
| message pipe | 双端消息管道 |
| data pipe | 适合传输大量数据 |
| shared buffer | 跨进程共享内存 |
Remote / Receiver | C++ bindings 中常见的调用端和接收端 |
普通页面加载时,Network Service 的位置大致是:
content/browser
→ services/network
→ net/textnet/ 是网络协议栈和底层实现,services/network/ 是网络能力的服务化边界。
Blink:Web 平台和渲染引擎#
Blink 主要在:
third_party/blink/
public/
common/
renderer/
core/
modules/
platform/
bindings/
web_tests/
tools/text关键层次:
| 目录 | 作用 |
|---|---|
third_party/blink/public/ | Blink 对外公开接口 |
third_party/blink/common/ | Blink browser/renderer 共用数据 |
third_party/blink/renderer/core/ | DOM、CSS、Layout、Paint、Frame、Loader 等核心 Web 平台 |
third_party/blink/renderer/modules/ | Web API 模块,如 WebAudio、WebGPU、ServiceWorker、WebRTC、MediaSource |
third_party/blink/renderer/platform/ | 图形、字体、网络抽象、scheduler、heap、media 等平台层 |
third_party/blink/renderer/bindings/ | Web IDL 到 V8 / Blink C++ 的绑定 |
third_party/blink/web_tests/ | Web 平台和 Blink 行为测试 |
渲染流水线主要落在 renderer/core/:
| 阶段 | 典型目录 |
|---|---|
| HTML parsing | renderer/core/html/parser/ |
| DOM | renderer/core/dom/ |
| Frame / Document | renderer/core/frame/、renderer/core/dom/ |
| Loading | renderer/core/loader/ |
| CSS / Style | renderer/core/css/、renderer/core/style/ |
| Layout | renderer/core/layout/ |
| Pre-paint / Paint | renderer/core/paint/ |
| Events / Input | renderer/core/events/、renderer/core/input/ |
| Workers | renderer/core/workers/ |
cc、Viz、GPU:渲染后半段#
Blink 完成 Style、Layout、Paint 之后,后半段由 cc、Viz、GPU 接住。
cc/ 是 layer compositor,负责 compositor tree、commit、raster 调度、activate、draw。关键类包括:
| 类 | 说明 |
|---|---|
cc::LayerTreeHost | main thread 侧 layer tree host |
cc::LayerTreeHostImpl | compositor / impl side host |
cc::Layer | main thread 侧 layer 抽象 |
cc::LayerImpl | impl side layer 抽象 |
components/viz/ 负责 Surface、DrawQuad、RenderPass、CompositorFrame、Surface Aggregation、Display Compositor 等。gpu/ 更靠近 GPU command buffer、图形 API 和平台后端。
后半段可以先记成:
Blink PaintArtifact
→ layerization
→ cc LayerTreeHost
→ commit 到 impl side
→ raster tile
→ activate active tree
→ DrawQuad / RenderPass
→ viz::CompositorFrame
→ Viz Surface Aggregation
→ GPU Displaytext一次网页打开:从 URL 到首帧#
把源码目录和前面的理论流程合起来,一次普通网页打开可以分成这些阶段:
1. Chrome 产品 UI
chrome/browser/ui
2. 发起导航
chrome/browser
content/public/browser
content/browser/web_contents
3. 创建导航状态
content/browser/renderer_host/NavigationRequest
content/browser/renderer_host/RenderFrameHostImpl
4. 发起网络请求
content/browser/loader 或 network 相关 glue
services/network
net
5. 选择或创建 Renderer Process
content/browser/renderer_host
RenderProcessHost
SiteInstance
BrowsingInstance
6. 提交导航到 Renderer
Mojo / IPC
content/renderer
7. Blink 加载主文档
third_party/blink/renderer/core/loader
DocumentLoader
8. HTML 解析和子资源发现
third_party/blink/renderer/core/html/parser
preload scanner
子资源继续通过 services/network 加载
9. JS 执行
third_party/blink/renderer/bindings
v8
gin
10. 渲染流水线
Blink core: Style / Layout / Pre-paint / Paint
cc: Commit / Raster / Activate / Draw
Viz: Aggregate / Display
11. Browser UI 和页面一起合成
chrome/browser/ui
ui/
cc/
components/viz/
gpu/text| 层 | 负责 | 不负责 |
|---|---|---|
chrome/ | 产品 UI、浏览器功能、用户入口 | DOM / Layout / Paint 内核实现 |
content/ | 导航、frame、进程、安全、WebContents | Chrome 特有产品功能 |
services/network | 网络服务边界 | DOM 解析 |
net/ | 网络协议栈实现 | 页面生命周期 |
blink/ | Web 平台、DOM、CSS、Layout、Paint | Browser UI |
cc/ | compositor tree、raster 调度、DrawQuad | HTML parser |
viz/ | Surface 聚合、Display Compositor | 页面业务逻辑 |
gpu/ | GPU 命令、图形后端 | 导航策略 |
对应渲染流水线#
RenderingNG 的阶段可以直接映射到源码目录:
| 阶段 | 主要源码目录 | 关键产物 / 概念 |
|---|---|---|
| Navigation commit | content/browser/renderer_host、content/renderer | NavigationRequest、RenderFrameHostImpl、RenderFrameImpl |
| Loading | third_party/blink/renderer/core/loader | DocumentLoader、resource load |
| Parsing | third_party/blink/renderer/core/html/parser | token、DOM nodes |
| DOM | third_party/blink/renderer/core/dom | Document、Node、Element |
| JS bindings | third_party/blink/renderer/bindings、v8/、gin/ | Web IDL binding、V8 objects |
| Style | third_party/blink/renderer/core/css、core/style | Computed Style |
| Layout | third_party/blink/renderer/core/layout | Layout objects / fragments |
| Pre-paint | third_party/blink/renderer/core/paint | Property Trees、paint invalidation |
| Paint | third_party/blink/renderer/core/paint | Display items、PaintArtifact |
| Layerization | Blink paint + cc/ | compositing reasons、cc layer data |
| Commit | cc/trees | LayerTreeHost 到 LayerTreeHostImpl |
| Tiling / Raster | cc/tiles、cc/raster、skia/ | Tile、Raster task、texture |
| Activate | cc/trees | Pending tree → Active tree |
| Draw | cc/、components/viz/common/quads | DrawQuad、RenderPass、CompositorFrame |
| Aggregate | components/viz/service/display | Surface Aggregation |
| Display | components/viz/service/display、gpu/ | GPU output、pixels |
几个概念需要持续区分:
| 概念 | 说明 |
|---|---|
| Paint | Blink 生成绘制记录,不直接生成最终屏幕像素 |
| Raster | cc / Skia 把绘制记录转换为 tile texture 或 bitmap |
| Draw | cc 遍历 active tree,把已有资源组织成 DrawQuad / RenderPass |
| Display | Viz / GPU 把聚合后的结果输出到屏幕 |
视频子系统#
media/ 不是主渲染流水线的一部分,但它和 <video>、<audio>、MSE、EME、WebRTC、硬件解码、Audio Output、VideoFrame 合成都强相关。
常见目录:
| 目录 | 作用 |
|---|---|
media/base/ | 媒体通用数据结构,如 VideoFrame、AudioBus、codec enum |
media/audio/ | 平台音频输入输出实现 |
media/capture/ | 屏幕、标签页、摄像头采集 |
media/ffmpeg/ | FFmpeg 绑定 |
media/filters/ | demuxer、decoder、data source、pipeline controller |
media/formats/ | container / MSE 格式解析 |
media/gpu/ | 平台硬件编解码实现 |
media/mojo/ | 媒体服务化、跨进程媒体能力 |
media/renderers/ | 音频/视频渲染器 |
media/video/ | 抽象硬件视频解码接口和工具 |
视频相关代码不只在 media/,还会跨越 Blink 和 content:
| 层 | 典型路径 | 作用 |
|---|---|---|
| Blink DOM | third_party/blink/renderer/core/html/media/ | HTMLMediaElement、HTMLVideoElement |
| Blink platform media | third_party/blink/renderer/platform/media/ | WebMediaPlayerImpl、VideoFrameCompositor |
| content glue | content/renderer/media/ | MediaFactory,连接 Blink 和 media |
| media pipeline | media/filters/、media/base/、media/renderers/ | 加载、解复用、解码、渲染 |
| hardware decode | media/gpu/ | 平台硬解 |
| compositor / viz | cc/、components/viz/ | 视频帧参与最终合成 |
H5 视频相关概念#
普通 <video> 只是入口,背后还有几类重要 Web 媒体能力:
| 概念 | 说明 | 典型路径 |
|---|---|---|
| HTMLMediaElement | <audio> 和 <video> 的公共基础行为,如 load、play、pause、seek | third_party/blink/renderer/core/html/media/html_media_element.* |
| HTMLVideoElement | <video> 元素本身,包含视频尺寸、poster、画面相关能力 | third_party/blink/renderer/core/html/media/html_video_element.* |
| MSE | Media Source Extensions,JS 手动 append 媒体分片,常用于 DASH / HLS 类播放器 | third_party/blink/renderer/modules/mediasource/、media/filters/chunk_demuxer.* |
| EME | Encrypted Media Extensions,DRM / CDM 相关 | third_party/blink/renderer/modules/encryptedmedia/、media/cdm/ |
| MediaStream | 摄像头、麦克风、屏幕共享、WebRTC 等实时媒体流 | third_party/blink/renderer/modules/mediastream/、media/capture/ |
| WebCodecs | 让 JS 直接访问编码/解码能力 | third_party/blink/renderer/modules/webcodecs/ |
| WebAudio | Web 音频图处理 | third_party/blink/renderer/modules/webaudio/ |
第一轮阅读先选择普通 src= 播放,不一开始展开 WebRTC、MSE、EME、WebCodecs。普通路径足够把 Blink、content、media、cc、Viz 串起来。
普通 video src 播放链路#
一个普通视频:
<video src="bear.mp4" controls></video>html粗略链路:
HTMLVideoElement / HTMLMediaElement
→ WebMediaPlayerImpl
→ PipelineController
→ PipelineImpl
→ FFmpegDemuxer
→ DecoderStream
→ AudioRenderer / VideoRenderer
→ VideoFrame
→ VideoFrameCompositor
→ cc / Viz
→ Displaytext更贴近源码的调用关系:
HTMLMediaElement::load()
HTMLMediaElement::play()
→ StartPlayerLoad()
→ CreateWebMediaPlayer()
→ content::MediaFactory::CreateMediaPlayer()
→ WebMediaPlayerBuilder::Build()
→ WebMediaPlayerImpl
WebMediaPlayerImpl::Load()
→ WebMediaPlayerImpl::DoLoad()
→ DemuxerManager::CreateDemuxer()
→ FFmpegDemuxer 或 ChunkDemuxer
→ PipelineController::Start()
→ PipelineImpl::Start()
→ RendererImpl
→ AudioRendererImpl / VideoRendererImpl
→ DecoderStream
→ VideoFrameCompositortext关键文件:
| 文件 | 作用 |
|---|---|
third_party/blink/renderer/core/html/media/html_media_element.cc | DOM 层媒体元素,处理 load/play/pause/seek 等状态 |
third_party/blink/renderer/core/html/media/html_video_element.cc | video 元素特有行为 |
content/renderer/media/media_factory.cc | Renderer 侧创建 media player 的 glue |
third_party/blink/renderer/platform/media/web_media_player_builder.cc | 构建 WebMediaPlayerImpl |
third_party/blink/renderer/platform/media/web_media_player_impl.cc | Blink 和 media pipeline 之间的核心播放器 |
media/filters/pipeline_controller.cc | 控制 pipeline 的 start/seek/suspend/resume |
media/base/pipeline_impl.cc | media pipeline 核心编排 |
media/filters/ffmpeg_demuxer.cc | 普通 src 播放的解复用 |
media/filters/chunk_demuxer.cc | MSE 播放的解复用 |
media/filters/decoder_stream.cc | 串联 demuxer stream 和 decoder |
media/renderers/renderer_impl.cc | 协调 audio/video renderer |
media/renderers/video_renderer_impl.cc | 视频渲染调度 |
third_party/blink/renderer/platform/media/video_frame_compositor.cc | 视频帧进入 compositor 的关键点 |
普通 src= 和 MSE 的分叉:
| 场景 | Demuxer | 数据来源 |
|---|---|---|
<video src="xxx.mp4"> | FFmpegDemuxer | WebMediaPlayerImpl 负责从网络/文件加载 bytes |
| MSE | ChunkDemuxer | JS 通过 SourceBuffer append muxed bytes |
视频和普通渲染流水线的关系#
普通 DOM/CSS 内容:
DOM / CSS
→ Style
→ Layout
→ Paint
→ Raster
→ Tile texture
→ DrawQuad
→ CompositorFrametext视频内容:
media bytes
→ Demux
→ Decode
→ VideoFrame
→ VideoFrameCompositor
→ video quad / surface / overlay
→ Viz
→ Displaytext<video> 元素本身仍然参与 DOM、Layout、Paint。它有位置、尺寸、裁剪、透明度、transform,也可能影响 compositing。但是视频每一帧的像素数据不会像普通 DOM 内容那样每次都重新 Paint / Raster。
可以这样理解:
主渲染流水线决定 video 元素这个盒子的位置、裁剪和合成属性;
media pipeline 决定盒子里面此刻应该显示哪一帧;
Viz / GPU 负责把页面内容、视频帧、Browser UI 聚合到最终画面。text这也是 VideoNG 里“video 像一个洞”的含义。洞的几何属性由 Blink / cc 管,洞里的动态画面由 media pipeline 管,最后在 Viz 层统一合成。
播控流程#
播控从 DOM API 或用户操作开始,先进入 Blink 的媒体元素状态机,再传给 WebMediaPlayerImpl 和 media pipeline。
play#
HTMLMediaElement::play()
→ 更新 pending play promise / autoplay / user gesture 等状态
→ 调用 WebMediaPlayerImpl::Play()
→ pipeline resume / start rendering
→ audio/video renderer 开始按时钟拉取和输出数据textplay() 不只是“开始解码”。它还要处理:
| 状态 | 说明 |
|---|---|
| autoplay policy | 是否允许自动播放 |
| pending play promise | JS video.play() 返回的 Promise |
| readyState | 当前是否有足够数据播放 |
| networkState | 是否需要继续加载 |
| media session | 页面媒体会话状态 |
| pipeline state | pipeline 是否已经初始化、是否需要 resume |
pause#
HTMLMediaElement::pause()
→ 更新 paused 状态
→ WebMediaPlayerImpl::Pause()
→ pipeline / renderer 暂停输出
→ 保留当前播放位置和缓冲状态text暂停一般不会释放所有资源。它更像把输出停住,并保留当前状态,方便继续播放。
seek#
HTMLMediaElement 设置 currentTime
→ 进入 seeking 状态
→ WebMediaPlayerImpl::Seek()
→ PipelineController::Seek()
→ demuxer / decoder flush 或重新定位
→ renderer 在新时间点重新输出textseek 要处理的事情比 play/pause 更复杂:
| 阶段 | 说明 |
|---|---|
| 更新目标时间 | DOM 层记录新的 currentTime |
| 进入 seeking | 触发 seeking 事件 |
| flush | 清理旧时间点附近的 buffer / decoder 状态 |
| demuxer seek | 找到新时间点附近的关键帧或媒体数据 |
| decoder restart | 重新解码目标时间附近数据 |
| ready | 有新帧后触发 seeked,继续播放或停在目标帧 |
关键数据和流转#
视频播放中有几类重要数据:
| 数据 | 所在阶段 | 说明 |
|---|---|---|
| URL / ResourceRequest | 加载阶段 | 视频资源地址和请求信息 |
| encoded bytes | 加载后 | 从网络、文件或 MSE 进入的压缩媒体数据 |
| container packets | demux 阶段 | MP4/WebM 等容器中拆出的音视频 packet |
| stream config | demux 后 | codec、分辨率、采样率、颜色空间等 |
| compressed buffers | decode 前 | 送入 decoder 的压缩音视频 buffer |
| decoded audio | audio decode 后 | 供 AudioRenderer 输出 |
media::VideoFrame | video decode 后 | 解码后的视频帧,可能是 CPU memory 或 GPU-backed resource |
| playback time | 渲染阶段 | 当前播放时间、媒体时间、音视频同步 |
viz::DrawQuad | compositor 阶段 | 最终合成用的绘制单元 |
viz::CompositorFrame | 提交阶段 | Renderer / Browser UI 提交给 Viz 的一帧合成数据 |
几个设计上的重点:
大块媒体数据尽量避免跨进程反复复制。
视频帧可能使用共享内存、GPU texture、mailbox 等方式流转。
音频通常以 audio callback / sink 的节奏拉取数据。
视频通常由 compositor 的节奏驱动,按显示时机取合适帧。text音视频同步通常以 audio time source 为核心。视频渲染器根据当前媒体时间选择合适的 VideoFrame,再通过 VideoFrameCompositor 交给 compositor。
进程和线程分工#
普通视频播放会横跨多个进程和线程:
| 位置 | 负责 |
|---|---|
| Browser Process | tab、权限、网络服务连接、音频输出通道、进程管理 |
| Renderer Process Main Thread | DOM、HTMLMediaElement 状态、JS 播控、Layout/Paint |
| Renderer Process Media Thread / Worker | demux、decode、pipeline task |
| Renderer Compositor Thread | 合成调度、视频帧提交、Draw |
| Utility / Network Service | 网络请求、资源加载 |
| GPU / Viz Process | Surface 聚合、GPU 资源、最终显示 |
一个重要原则:
DOM 状态和媒体 pipeline 状态不是同一层。
DOM 层负责 Web API 语义;
media 层负责字节、解码、音视频同步和输出;
compositor / Viz 负责最终合成。text