Visual LabINTERACTIVE LEARNING
阶段 9 · 原生实践进阶28 分钟

原生视频渲染:YUV 帧怎样抵达屏幕

Stride、Color Conversion、GPU Texture 与 Zero-copy Surface

理解软件解码帧的 YUV Plane、Stride 与色彩转换,以及硬件解码 Surface 通过零拷贝进入 GPU 合成器的路径。

LEARNING GOALS

先明确本课目标

1

正确读取 Plane 与 stride

2

理解 YUV → RGB 色彩转换

3

解释硬件 Surface 和零拷贝价值

MENTAL MODEL · 再建立心智模型

软件路径把 Y、U、V 平面上传成纹理再由 Shader 转 RGB;硬件路径让解码器直接写可被合成器消费的表面,尽量不搬像素。

MINIMAL EXAMPLE

为什么复制 Y 平面不能只 memcpy(width × height)?

Plane 的每行有效像素宽度可能小于 linesize,行尾包含对齐 padding。正确复制要逐行从 y×linesize 读取 width 个有效字节。

最小例子cpp
for (int y = 0; y < height; ++y) {
  const uint8_t* src = frame->data[0] + y * frame->linesize[0];
  uint8_t* dst = tightlyPackedY + y * width;
  std::memcpy(dst, src, width);
}
  1. 用 linesize 定位源行 解码器每行跨度可能大于可见宽度。
  2. 目标按紧密宽度推进 上传缓冲只保存每行有效像素。
  3. 复制有效区域 不要把 padding 当成下一行画面数据。

任意对齐方式的 Y 平面都能被正确整理,不会出现错行、斜裂和越界读取。

本课概念
OPTIONAL · 按需查阅完整术语表与概念边界

遇到陌生术语时再展开,不打断主线实验。

展开⌄
LIVE EXPERIMENT · 先获得反馈

边改边运行

浏览器加载后会激活代码编辑器、独立运行环境与实时输出。

本课挑战

写一个支持 I420 与 NV12 的 GPU Shader 上传布局和色彩转换方案。

DEEP DIVE · 实验之后

回到原理,解释刚才发生了什么

先用结果建立反馈,再按运行流程、核心原理和知识关系逐层深入。

CORE IDEA

核心讲解

01

Stride 可能大于可见宽度

解码器为对齐和 SIMD 会让每行带 padding。逐行上传必须使用 linesize,不能假设平面是 width×height 紧密连续。

02

零拷贝减少内存带宽

硬件解码器输出的 Surface/PixelBuffer 可直接被 Metal、Vulkan、OpenGL 或系统合成器引用,避免 GPU→CPU→GPU 往返。

OPTIONAL · 迁移时查阅Web 与原生实现对照

主线实验完成后,再用完整映射处理跨平台或跨 API 迁移。

展开⌄
API COMPARISON

Canvas/WebGPU 与 Metal/Vulkan 最终都消费纹理,原生更常直接握住解码 Surface。

WebGL

CVPixelBuffer、AHardwareBuffer、D3D11 Texture 等可跨解码器与渲染器共享。

WebGPU

VideoFrame 可作为 CanvasImageSource,也可通过 importExternalTexture 等路径交给 GPU。

视频渲染性能优先检查是否发生像素读回和重复色彩转换。