原文出处:WebRTC视频渲染

导读:WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音对话或视频对话的 API。W3C 和 IETF 在2021年1月26日共同宣布 WebRTC 1.0 定稿,促使 WebRTC 从事实上的互联网通信标准成为了官方标准,其在不同场景的应用将得到更为广泛的普及。WebRTC 提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:Windows,Mac,iOS,Android。本文主要介绍各个平台的视频渲染技术。

背景

目前业界还没有关于 WebRTC 各个平台视频渲染技术的总结,同时本人最近主要从事视频后处理超分在移动端落地的相关工作,会涉及到视频渲染模块的联动,因此刚好趁这个机会把相关的知识点进行总结一下,希望能够帮助大家更容易的理解 WebRTC 的视频渲染技术。

内容

视频 Pipline 流程

视频渲染需要支持视频采集、视频前处理、视频后处理、视频解码输出的视频格式。

视频渲染流程

视频渲染技术

1. 平台视频渲染技术介绍

主要介绍 Apple、Google、Microsoft 三大平台在视频渲染方面的支持。

Apple 主要使用早期的 OpenGL 和 最新的 Metal 2种渲染技术,目前 WebRTC 中 iOS 和 Mac 这2个平台都实现了 OpenGL 和 Metal 2种渲染方式。

WWDC 2014 发布了 Metal,仅支持 iOS 8 以及 A7 以上的设备;

WWDC 2015 Metal 支持在 OS X 上运行,2012 之后生产的,系统版本在 El Capitan(10.11)之上的 Mac 设备 ;

WWDC 2016 Metal 性能优化,一些新技术,比如Tessellation(曲面细分)可用于实现细节层次,高效调整以适应不同材质等。最重要的应该是引入了 Metal Performance Shaders,内置了一系列常用的图像处理 kernel,方便进行图像效果处理 ;

WWDC 2017 发布了 Metal 2。名字上是图形 API 更新,实际上更多是内部实现的优化,以及加入一系列调试工具,API 层面并没有多大改变。硬件方面要求一致,系统版本支持 iOS 11,macOS High Sierra,tvOS 11 ;

WWDC 2018 iOS 12、macOS 10.14 之后弃用 OpenGL ES,系统的一些框架全面改成默认 Metal 支持 ;

WWDC 2019、2020、2021 都有发布关于 Metal 的更新,包括机器学习、计算机视觉、AR/VR 与 Metal 的交互。

在 Android 平台上,GPU 渲染的 API 有两套,一套是 OpenGL-ES,另一套是7.0后推出的 Vulkan。目前 WebRTC 中 Android 平台实现了 OpenGL 的渲染方式,网易云信后期也将考虑支持 Vulkan。

Vulkan 是一个用于图形和计算设备的编程接口,Vulkan 是一个跨平台的 2D 和 3D 绘图应用程序接口(API),最早由科纳斯组织在2015年游戏开发者大会(GDC)上发表。

Vulkan 是用于高性能 3D 图形的低开销、跨平台 API。Vulkan 是 Khronos Group(OpenGL 标准的维护组织)开发的一个新 API,它提供了对现代显卡的一个更好的抽象,与 OpenGL 和 Direct3D 等现有 API 相比,Vulkan 可以更详细的向显卡描述你的应用程序打算做什么,从而可以获得更好的性能和更小的驱动开销。Vulkan 的设计理念与 Direct3D 12 和 Metal 基本类似,但 Vulkan 作为 OpenGL 的替代者,它设计之初就是为了跨平台实现的,可以同时在 Windows、Linux 和 Android 开发。甚至在 Mac OS 系统上,Khronos 也提供了 Vulkan 的 SDK,虽然这个 SDK 底层其实是使用 MoltenVK 实现的。

在 Windows 平台下的视频播放技术主要有以下三种:GDI、Direct3D 和 OpenGL;包括上面提到的 Vulkan 也支持 Windows 平台。以及早期的 DirectDraw,目前微软已放弃支持。

Direct3D 是微软公司在 Microsoft Windows 系统上开发的一套 3D 绘图 API,是 DirectX 的一部份,目前广为各家显示卡所支持。1995年2月,微软收购了英国的 Rendermorphics 公司,将 RealityLab 2.0 技术发展成 Direct3D 标准,并整合到 Microsoft Windows 中,Direct3D 在 DirectX 3.0 版本中开始出现。后来在 DirectX 8.0 发表时与 DirectDraw 编程介面合并并改名为 DirectX Graphics。Direct3D 与 Windows GDI 是同层级组件。它可以直接调用底层显卡的功能。与 OpenGL 同为电脑绘图软件和电脑游戏最常使用的两套绘图 API。

Simple DirectMedia Layer(SDL)是一个跨平台开发库,主要提供对音频,键盘,鼠标,操纵杆的操作,通过 OpenGL 和 Direct3D 来实现直接访问图像硬件。主要应用在视频播放软件,模拟器和游戏开发。SDL 官方支持 Windows,Mac OS X,Linux,iOS 和 Android。

由于微软想主推 Direct3D,因此微软对于 OpenGL 的支持并不积极。目前 WebRTC 中并没有实现 Windows 平台的渲染,目前网易云信使用的是开源的SDL框架,但由于其太重,因此后期会考虑直接实现 Direct3D。

由以上的介绍可知,目前在终端实现的渲染技术有跨平台的 OpenGL、Vulkan,以及 Apple 平台特有的 Metal、Windows 平台特有的 Direct3D,总共4种渲染方式。

2. 详细介绍视频渲染技术

OpenGL 介绍

OpenGL(Open Graphics Library)是一个跨语言、跨平台的编程图形程序接口,它可用于二维、三维图像的渲染,是一个功能强大,调用方便的底层图形库。OpenGL ES(OpenGL for Embedded Systems)是 OpenGL 三维图形 API 的子集,针对手机、Pad 和游戏而设计,去除了很多不必要和性能较低的API。因此在 iPhone 和 Android 手机上使用的都是 OpenGL ES。

1. 什么是 EGL

EGL 是 OpenGL ES 和本地窗口系统(Native Window System)之间的通信接口,它的主要作用:

OpenGL ES 的平台无关性正是借助 EGL 实现的,EGL 屏蔽了不同平台的差异。

2. 创建 OpenGL 上下文

3. 创建 OpenGL View

4. 具体运用

目前网易云信第二代实时音视频 iOS 和 Mac 的整体渲染框架,如下图:

目前网易云信第二代实时音视频 iOS 和 Mac 的 OpenGL 渲染架构,如下图:

Metal介绍

Metal 框架支持 GPU 加速的先进的 3D 图形渲染和并行数据计算。Metal 提供了一系列现代化且高效的 API,用于在细粒度和低层次上组织、处理、提交图形绘制指令和并行计算指令,并管理和这些指令相关联的数据和资源。Metal 的一个主要目标是最小化 GPU 执行这些计算时必要的 CPU 开销。

1. Metal 框架提供以下内容:
2. MTLCommandBuffer 提供的 Encoder 类型:
3. 多线程 Metal Command Buffers

4. 具体运用

目前网易云信第二代实时音视频 iOS 和 Mac 的 Metal 渲染架构,拓展了纹理输入渲染,如下图:

Vulkan 介绍

Vulkan 是一个用于图形和计算设备的编程接口,Vulkan 是一个跨平台的 2D 和 3D 绘图应用程序接口(API)。同 OpenGL® 一样,Vulkan™ 也由 Khronos 集团开发。它是 AMD Mantle 的后续版本,继承了前者强大的低开销架构,使软件开发人员能够全面获取 Radeon™ GPU 与多核 CPU 的性能、效率和功能。相对于 OpenGL,Vulkan™ 大幅降低了 CPU 在提供重要特性、性能和影像质量时的“API 开销” (CPU 在分析游戏的硬件需求时所执行的后台工作),而且可以使用通常通过 OpenGL 无法访问的 GPU 硬件特性。
独特的跨 OS 支持:Vulkan™ 能够支持深入硬件底层的控制,为 Windows® 7、Windows® 8.1、Windows® 10 和 Linux® 带来更快的性能和更高的影像质量。Vulkan™API 还提供超高的 OS 兼容性、渲染特性和硬件效率。
自动兼容 GCN 架构:目前只有基于 GCN 架构 的 Radeon™ 显卡拥有强大的“异步计算”功能,使显卡得以并行处理 3D 几何图形与计算工作量。

1. Vulkan 中主要的组件以及它们之间的关系

2. 基本的 Vulkan 编程流程

这个流程和 OpenGL 的使用流程很像,就是找到设备——创建上下文——创建命令队列——准备任务——发送执行。

3. Vulkan 的窗口系统

注意到,在移动设备上使用 OpenGL 时,我们必须通过 EGL 的 API 先准备好 Surface 和 Context,而在 Vulkan 标准里面,WSI 只是为Command Buffer 提供了 VkFrameBuffer,这个是图形渲染的输出。

Direct3D 介绍

Direct3D 是一种低级别的 API,用于通过呈现管道绘制基元,或用于通过计算着色器执行并行操作。

Direct3D 9.0 使用 HLSL(全称 High Level Shading Language)编写 Vertex Shader 和 Pixel Shader,有助于着色器的编写和所产生代码的效率,并且大幅地缩短设计时间。Direct3D 10 着眼在高级绘图程序,全新的 graphics pipeline;新的 resource type: constant buffer、texture array。Texture array 可容许最多 512 个 Texture;resource 引进 view 的概念;guaranteed feature set;GPU 呈现多任务(multitasking)。

Direct3D 11 新增以下的功能:镶嵌(Tessellation, 即曲面细分);多线程渲染(Multithread Render);

计算着色器(Compute Shader),支持 GPGPU,提供新版 HLSL 语言,与 nVidia 的 CUDA 或 OpenCL 功能类似。其他还有面向对象化的 Shader Model 5 等功能。之前 DirectX 10 还是单线程,文件访问与绘图指令共用同一个线程,容易造成画面迟缓的现象,与 DirectX 10 相比,Direct3D 11 有了更好的解决方案。DirectX 11 的 pipeline 新增 Hull Shader、Tessellator、Domain Shader 来实现 tessellation, 可以快速让成像 3D 的小三角型快速增加。至于 Computer ShadeWindows U 的实现,以 GPU 的平行处理能力与浮点运算能力来实现 CPU 的运算,能够同时支持 ATI 以及 Nvidia 的显卡,不受绘图流程的限制。DirectX11 还支持 Intel 的支持 Ray Tracing(光线跟踪)与 Rasterization(光栅化)技术,使 3D 效果更真实,更加逼真。

1. D3D11.1 图形流水线

from《Direct3D 11.3 Functional Specification》

2. D3D11.1 计算流水线

from 《Direct3D 11.3 Functional Specification》

总结

随着 AR/VR 的发展,对高效的视频渲染技术提出了更高的要求。Apple 在 WWDC 2018 上宣称 iOS 12、macOS 10.14 之后弃用 OpenGL ES,系统的一些框架全面改成默认 Metal 支持;以及多家硬件厂商(高通、英伟达等)都致力于打造新一代渲染技术 Vulkan,包括谷歌也已经明确 Android 会支持 Vulkan;而微软一直努力开发 Direct3D。Vulkan、Metal、Direct3D 其三者背后设计的理念都是一致的,都是朝着高性能的图形渲染技术发展。并行计算架构、可扩展的渲染管线、GPU 驱动的渲染管线都将是发展的重要方向。因此我认为此后的发展必将形成一个三足鼎立的态势。

参考文献


原文出处:GPU方案的探索与落地

背景

现阶段为了完成 G2 SDK(网易云信第二代实时音视频SDK)接入视频矫正、美颜、超分等 GPU 算法,鉴于 G2 目前尚未支持整个 GPU 方案,因此需要改造 G2 现有的视频数据链路走向,形成统一的 G2 前处理模块,包含视频矫正、美颜、视频降噪、视频增强等算法。考虑到整体性能的最佳状态,整体方案会涉及到 Camera 采集、基础前处理(裁剪、缩放、旋转、编码镜像、编码方向)、算法前处理(transform层、算法层)、渲染、编码等模块的整体调整。

关键点

方案介绍

目前整体方案采取单路数据流,支持 CPU 方案和 GPU 方案并行。中高端机型实现 GPU 方案,低端机型实现 CPU 方案,CPU 方案可以作为 GPU 方案的灾备。

CPU 方案

Camera 输出 I420+CPU 基础前处理

GPU 方案

Camera 输出纹理+ GPU 基础前处理

方案选型

这个是之前讨论的双路数据的方案,那么我们为什么不考虑呢?

  1. 根据 Camera1/Camera2 单双流数据采集性能对比报告显示,光一个2路数据采集,在测试的大部分手机上,归一化的 CPU 百分比就多出2个点,8核的手机总的 CPU 消耗就是多出16%。

  2. 2路数据对于人脸检测的数据,必须保证是同一张画面,且大小都一致,否则人脸检测的坐标点就无法统一起来。在 RTC 的框架里面,存在 Adapter 的操作,会有丢帧帧率,因此很难控制2路数据的一致性。其次纹理数据做 GPU 基础前处理,那么另外一路 I420 数据也需要做同样的 CPU 基础前处理,这部分的开销也是会增长的。

  3. 对于人脸检测的这一路 I420 数据肯定需要单独再开线程来同步人脸检测的结果坐标点到原始纹理数据上。如果都是在前处理线程上,必然会引起前处理线程的阻塞。这2路数据必须要做到互相等的情况,纹理处理快了,需要等人脸检测的数据,人脸检测快了,需要等纹理,因此多线程操作会相当复杂。

  4. 对于这种2路数据方案的提出,本来就是为了人脸检测这个模块考虑的。为了满足该需求,我们使用上面的 CPU 方案,只需要使 Camera 输出 I420 数据,同时基础前处理选CPU操作就可以满足需求;而且这种方案的性能消耗和复杂度都比双路有优势。

综上所述,我们将淘汰双路的方案,采取单路方案,支持 CPU 方案和 GPU 方案并行。中高端机型的 GPU 性能较好,对于 GPU 方案有较为明显的优势;低端机型的 GPU 性能较差,对于 CPU 方案有较为明显的优势;因此中高端机型实现 GPU 方案,低端机型实现 CPU 方案,CPU 方案可以作为 GPU 方案的灾备,整体使用下发控制来做到兼容性的适配。

框架设计

框架介绍

一个满足整个视频前后处理的框架,整体由 ProcessManager 管理 GPU 的上下文环境,同时负责前处理 PreProcess 和后处理 PostProcess 的创建和销毁。 第一层为 Process Control:内部包含具体的前处理 PreProcess 和后处理 PostProcess,它们各自管理一个线程,进行耗时操作。 第二层为 Process Unit:它们负责不同类型的操作管理,正如上面方案里面具体的处理单元,包括 CPU 算法处理单元、RGB 纹理处理单元、YUV 纹理处理单元、基础前处理的预览处理单元、基础前处理的编码处理单元、编码格式要求的处理单元等。 第三层为 Transform:主要负责 RTC 中各个平台的数据类型的转换,包括 CPU 数据和 GPU 数据的互转,以及 GPU 数据不同格式之间的转换;Apple 平台使用 Metal 实现、Android 平台使用 OpenGL ES 实现。 第四层为算法层:主要包含 AI 算法和传统算法,目前主要包含的算法有:超分、屏幕增强、视频降噪、人脸检测、美颜、人脸画质增强、视频矫正等。有的使用 CPU 实现,有的使用 GPU 实现。 第五层为平台层:主要负责各自平台算子的实现,会有 NPU、CPU、GPU 等方案,像 GPU 内部又会分为 Vulkan、Metal、OpenCL、Cuda 等。针对 AI 的 GPU 加速,我们有好几种 GPU API Backend,这样做的目的主要也是为了在不同平台不同系统上可以让 GPU 有更好的加速,例如:在 IOS 平台上当前比较优的 GPU 方案就是采用 Metal 去加速,而在 Android 平台上比较通用的方法是 OpenCL 去加速,所以我们的框架需要去对这不同的 GPU API 做兼容和适配。

模型设计

每个 Process Unit 处理单元内部包含一个 Transfrom 层负责数据格式转换和同类型的多个算法,它们犹如管线一样,依次串联,从而达到视频数据的流动。譬如 RGBTexProcessUnit 内部包含一个 rgb 纹理的 transfrom,多个需要 rgb 纹理输入的算法,包括视频矫正、人脸画质增强、美颜以及美颜内部串联美白、磨皮、贴纸、特效等。

Transfrom 层实现

Transform 层主要分为三步:输入数据、格式转换、输出数据。输入部分需要关注各种数据类型的输入,做到各种数据输入的兼容;格式转换部分需要满足各种数据类型格式的转换,并且是高效的;输出部分需要关注外部指定的格式要求。

1. 颜色空间的转换

YUV 是一种颜色编码方法,主要用在视频、图形处理流水线中。相对于 RGB 颜色空间,设计 YUV 的目的就是为了编码、传输的方便,减少带宽占用和信息出错。因为人眼的视觉特点是对亮度更敏感,对位置、色彩相对来说不敏感。在视频编码系统中为了降低带宽,可以保存更多的亮度信息,保存较少的色差信息。

对于图像显示器来说,它是通过 RGB 模型来显示图像的,而在传输图像数据时又是使用 YUV 模型。因此就需要采集图像时将 RGB 模型转换到 YUV 模型,显示时再将 YUV 模型转换为 RGB 模型。

在介绍 YUV 和 RGB 的颜色空间转换前,请先阅读一文读懂 YUV 的采样与格式,能够帮助你更好的理解下面的过程。

对于标清电视应用 (SDTV),我们往往使用 ITU-R BT.601;对于高清电视 (HDTV),我们往往使用 ITU-R BT.709。

对于数字分量视频,使用颜色格式 YCbCr。对于标清电视应用 (SDTV),以下等式描述了从 RGB 到 YCbCr 的颜色转换(根据 ITU-RBT.601):

为了从 YCbCr 颜色恢复 RGB 颜色,使用以下逆矩阵:

亮度和色度的取值范围做了一些保留,亮度范围是 16~235,色度范围是 16~240。对于使用 RGB 和 YCbCr 颜色格式的计算机应用程序,在许多情况下,使用 8 位的完整范围,而不保留多余范围。通常这种全范围颜色格式用于 JPEG 图像。

RGB 颜色到全范围 YCbCr 颜色的转换由以下等式描述:

反过来,将全范围 YCbCr 颜色转换为 RGB 由以下等式描述:

对于高清电视 (HDTV),需要使用不同的系数。亮度和色度的取值范围与 SDTV 相同,以提供必要的动态余量。以下等式描述了 HDTV 从 RGB 到 YCbCr 的颜色转换(根据 ITU-R BT.709):

这是从 YCbCr 颜色中获取 RGB 颜色分量的相应逆矩阵:

Apple 平台下,存在2种常用的 I420 格式:

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 【Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240])】

kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 【Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255])】

在 iOS 和 Mac 平台下获取的 CMSampleBuffer 基本都是 BT601

formatDescription = <CMVideoFormatDescription 0x281dfc450 [0x1e8c95860]> {
        mediaType:'vide' 
        mediaSubType:'BGRA' 
        mediaSpecific: {
                codecType: 'BGRA'                dimensions: 1080 x 1920 
        } 
        extensions: {{
  CVBytesPerRow = 4352;
  CVImageBufferColorPrimaries = "ITU_R_709_2";
  CVImageBufferTransferFunction = "ITU_R_709_2";
  CVImageBufferYCbCrMatrix = "ITU_R_601_4";
  Version = 2;
}

Metal Performance Shaders 框架包含一系列高度优化的计算和图形着色器,旨在轻松高效地集成到您的 Metal应用程序中。这些数据并行经过专门调整,利用每个 GPU 系列的独特硬件特性来确保最佳性能。同时它也是 Apple 上实现深度学习的工具,它主要封装了 MPSImage 来存储数据管理内存,相当于 Caffe 中的 Blob、MXNet 中的 NDArray,实现了Convolution、Pooling、Fullconnetcion、ReLU 等常用的卷积神经网络中的 Layer。我们的 GPU 传统超分就是通过 Metal Performance Shaders 实现的。我们的AI 超分中也用到了 MTLComputeCommandEncoder 并行计算任务。

在 Apple 平台下,不同纹理格式之间的转换都是通过 Metal Performance Shaders 和 MTLComputeCommandEncoder 并行数据计算任务编码来完成的。

Android 平台使用 OpenGL ES 的 Shader 实现,目前主要实现了这些转换,后期看需求再扩充。

iOS 平台使用 Metal 的 Shader 实现,目前主要实现了这些转换,后期看需求再扩充。

2. CPU 与 GPU 的高效方式

在 RTC 场景中 CPU 数据主要指 I420 数据,GPU 数据主要指 RGB 纹理。

因为 CPU 和 GPU 是两个不同的处理器,它们可以并行地执行各自的指令。GPU 侧会存在一个命令队列用于暂存还未发送到 GPU 的命令,实际上我们调用的绝大多数 OpenGL ES 或者 Metal 方法,只是往命令队列时送入命令而已,并不会在 CPU 同步等命令执行完。因此绝大部分情况,从 CPU 往 GPU 异步提交任务是非常高效的,但部分接口涉及到同步等待,因此会比较耗时,例如显示器显示图像时,需要交换前后缓冲区。

由于移动端设备算力的有限,越来越多的传统算法和 AI 算法计算量又比较高,如果需要把性能做到极致,总避不开使用 GPU 的算力。因此如果 Camera 输出的是 CPU 数据,那就无法避免将 CPU 数据上传到 GPU 数据。

同时由于部分算法如人脸检测算法又必须使用 CPU,以及软件编码器需要的输入数据格式是 I420,因此无法避免从 GPU 往 CPU 的数据格式转换。而提供一种高效的方法能够帮助全链路实现性能最佳。

Android 平台的方法:输出的纹理不仅要包含所有的 YUV 信息,还要方便我们一次性读取 I420 格式数据(glReadPixels)。同时考虑到 YUV 数据的排列情况,因此提出了3种方案。

方案一:

U 和 V 存在虚线部分的内存重叠,因此在计算 I420 时,需要注意 U 和 V 步长 stride 为 w,建议转为标准的 I420 格式。同时按这个内存排列方式,内存占用为:w*h*3/2, 是一种比较节省内存的方式。

方案二:

标准的 I420 排列方式,但是由于需要作为绘制目标的纹理时,必然是一个连续的内存块,因此实际的内存大小为:wh2, 同时 U 和 V 步长 stride 为 w。

方案三:

该方案的内存排列方式,内存占用为:wh3/2。但是由于类似于 4:1:1 的模式,因此将该部分数据上传 GPU 时,而非标准的 I420 格式,存在 uv 分量显示异常的问题。

综上所述考虑,基于内存占用和 I420 排列的特性,因此我们选取方案一作为 RGB 纹理按 YUV 数据排列转 YUV 的方式。

下图主要表现的是 toI420 接口单帧耗时的测试数据:

3. 输入输出类型

Transform 层的输入输出数据类型涉及多个模块的联动,包括 Camera、SDK 外部处理、算法模块、渲染模块、编码模块等,因此是一个复杂的模块。

Android 平台:Camera1 支持 OES 纹理和 NV21 数据;Camera2 支持 OES 纹理和 I420 数据

Apple 平台:支持 RGB 数据和 NV12 数据的 CVPixelBuffer,NV12 包括 420v 和 420f 两种

Android 平台(OpenGL ES):主要支持 I420 数据、YUV 纹理、OES 纹理、RGB 纹理

Apple 平台(Metal+OpenGL ES):主要支持 I420 数据、NV12 数据、RGB 数据、YUV 纹理、YCbCr 纹理、RGB 纹理

Android 平台:硬件编码 MediaCodc(H264、H265)支持纹理和 I420 数据,RTC 场景中软件编码(NE264、NE265、NEVC)支持 I420 数据

Apple 平台:硬件编码 VideoToolBox(H264、H265)支持 NV12 数据的 CVPixelBuffer,RTC 场景中软件编码(NE264、NE265、NEVC)支持 I420 数据

C++ 的数据封装类和渲染各平台的数据封装类之间的关系和转换。渲染是各平台系统 API 强相关的。

Mac 平台和 iOS 平台类似,渲染部分实现是 Metal 和 OpenGL,OpenGL ES 是专门为移动平台设计的,Mac 平台的 Metal 内存存储管理方面和 iOS 不同,其他部分基本相同,因此 Metal 基本可以做到2个平台的共用。Windows 平台则相对简单,目前在 RTC 场景基本主要使用 I420 数据格式。

GPU 基础前处理

RTC 场景的基础前处理主要包括裁剪、缩放、旋转、编码镜像、编码方向等功能,而这些对于图像的操作都可以直接通过纹理坐标和绘制视图来实现。

1.OpenGL的纹理坐标和Metal的纹理坐标区别

DirectX、Metal、Vulkan 三者的纹理坐标相同

2. 以 Metal 为例,顶点坐标和纹理坐标的理解

3. 那怎么理解裁剪、缩放、旋转、镜像映射到纹理坐标和绘制视图的操作呢?

纹理坐标的排列:{(左下),(右下),(左上),(右上)}

裁剪:可以理解为由蓝色 ABCD 4个点组成的新画面,相对于由红色 ABCD 4个点组成的原始画面,在宽和高上都做了相应的裁剪。裁剪是从坐标 (x,y) 开始,裁剪为宽为 w,高为 h 的画面。体现到纹理坐标为 {(L,B),(R,B),(L,T),(R,T)}。

镜像:可以分为水平镜像和垂直镜像,通常画面镜像都是指水平镜像。那么镜像就是指将红色 A 点和红色 B 点位置互换,红色 D 点和红色 C 点位置互换。体现到纹理坐标为 {(1,1),(0,1),(1,0),(0,0)}。

旋转:图像的旋转操作就是红色 ABCD 4个点的旋转操作。顺时针旋转90度体现到纹理坐标为 {(1,1),(1,0),(0,1),(0,0)}。

缩放:主要是指图像的放大和缩小,如果借助于 FBO,那就是绘制到FBO绑定的纹理大小。OpenGL ES 通过 glViewport 体现,Metal 通过setViewport 体现。

4. 题外话:那怎么做到把三维空间中所展示的内容显示到一个二维空间上呢?

那就需要使用到视图变换和投影变换,视频矫正算法就是基于此实现的,涉及多个坐标系的转换。

总结

随着 RTC 业务场景的不断丰富,对于不同场景的算法落地要求也越来越高,即需要实时性,又需要低功耗。与此同时随着硬件的不断发展,硬件的低功耗存在得天独厚的优势,但是由于硬件的兼容性问题,因此在全平台实现 CPU 和 GPU 并行的方案将是当下大趋势。而一个简单合理、高效稳定、可拓展的前后处理框架是算法快速落地的基础。因此我们也在探索一辆 CPU 和 GPU 并驾齐驱的马车,不管是架构设计上还是算法实现上。