- 通信
- 音视频
【免费下载链接】freeswitch
FreeSWITCH is a Software Defined Telecom Stack enabling the digital transformation from proprietary telecom switches to a versatile software implementation that runs on any commodity hardware. From a Raspberry PI to a multi-core server, FreeSWITCH can unlock the telecommunications potential of any device.
本指南以仓库内 libs/libyuv/docs/formats.md 为骨架,结合 libyuv 头文件 与 FreeSWITCH 视频管线(src/switch_core_video.c)展开,系统讲解 libyuv 支持的 FOURCC 像素格式体系、OSX Core Media 像素格式映射、ARGB 内存布局与字节序细节,以及各格式在 FreeSWITCH 图像处理(如 I420↔ARGB 转换、视频缩放)中的实际调用方式。读完本文,你将能准确识别任意 FOURCC 字符串对应的内存布局,理解 I420/ARGB 为何是 libyuv 的“双枢纽”,并能直接在 FreeSWITCH 图像处理代码中调用
I420ToARGB、ARGBToI420、ConvertToI420等 API 完成格式适配。
一、libyuv 像素格式体系概述:两个核心格式
libyuv 是 FreeSWITCH 仓库中随附的 YUV 缩放与转换开源库,主要职责包括:为压缩前的内容准备 YUV 数据(缩放)、从摄像头格式转换到 YUV、转换到 RGB 用于渲染与特效、支持 90/180/270 度旋转,并在 x86(SSSE3/AVX2)、Arm(Neon)、Mips(MSA)上做了 SIMD 优化(见 README.md)。
在像素格式层面,libyuv 的整个转换体系建立在两个核心格式之上:
- I420:YUV 4:2:0 平面(planar)格式,是 YUV 侧的唯一枢纽。
- ARGB:32 位打包(packed)RGB 格式,是 RGB 侧的唯一枢纽。
据此形成两条黄金规则:
- 所有 YUV 格式都可以转换到/自 I420;
- 所有 RGB 格式都可以转换到/自 ARGB。
因此,任意 YUV 与 RGB 之间的互转(例如 NV12→ARGB)在 libyuv 中实际走的是“先到 I420,再到 ARGB”的多步路径。文档中同样指出:缩放(scaling)与平面处理(planar functions)这类滤波类函数,正是工作在 I420 和/或 ARGB 之上。
二、OSX Core Media 像素格式与 libyuv FOURCC 的映射
libyuv 维护了一张 OSX Core Media(CoreVideo)像素格式到自身 FOURCC 的映射表。理解这张表,是在 macOS 上做摄像头采集、视频渲染时正确选型的前提:
| Core Media 常量 | 取值 | libyuv 映射 |
|---|---|---|
kCMPixelFormat_32ARGB | 32 | FOURCC_BGRA |
kCMPixelFormat_32BGRA | 'BGRA' | FOURCC_ARGB |
kCMPixelFormat_24RGB | 24 | FOURCC_RAW |
kCMPixelFormat_16BE555 | 16 | 不支持 |
kCMPixelFormat_16BE565 | 'B565' | 不支持 |
kCMPixelFormat_16LE555 | 'L555' | FOURCC_RGBO |
kCMPixelFormat_16LE565 | 'L565' | FOURCC_RGBP |
kCMPixelFormat_16LE5551 | '5551' | FOURCC_RGBO |
kCMPixelFormat_422YpCbCr8 | '2vuy' | FOURCC_UYVY |
kCMPixelFormat_422YpCbCr8_yuvs | 'yuvs' | FOURCC_YUY2 |
kCMPixelFormat_444YpCbCr8 | 'v308' | FOURCC_I444(文档标注?,表示映射不确定) |
kCMPixelFormat_4444YpCbCrA8 | 'v408' | 不支持 |
kCMPixelFormat_422YpCbCr16 | 'v216' | 不支持 |
kCMPixelFormat_422YpCbCr10 | 'v210' | 曾为FOURCC_V210,现已移除 |
kCMPixelFormat_444YpCbCr10 | 'v410' | 不支持 |
kCMPixelFormat_8IndexedGray_WhiteIsZero | 0x00000028 | 不支持 |
需要特别留意的坑:
- 命名看似颠倒:
kCMPixelFormat_32ARGB实际映射到FOURCC_BGRA,而kCMPixelFormat_32BGRA映射到FOURCC_ARGB。这正是 formats.md 强调的“FOURCC 描述的是寄存器内通道顺序,而非内存顺序”的直接体现(详见第四节)。 'v210'(10 位 4:2:2)曾经有FOURCC_V210支持,现在已被移除。若你的 macOS 采集管线依赖 v210,需要自行做预处理。
从源码看,这张映射表最终落地于 libs/libyuv/source/video_common.cc 的kFourCCAliases别名表,其中:
FOURCC_YUVS → FOURCC_YUY2对应kCMPixelFormat_422YpCbCr8_yuvs;FOURCC_2VUY → FOURCC_UYVY对应kCMPixelFormat_422YpCbCr8;FOURCC_CM32 → FOURCC_BGRA对应kCMPixelFormat_32ARGB;FOURCC_CM24 → FOURCC_RAW对应kCMPixelFormat_24RGB;FOURCC_L555 → FOURCC_RGBO、FOURCC_L565 → FOURCC_RGBP、FOURCC_5551 → FOURCC_RGBO分别对应三种 16 位小端格式。
三、FOURCC 完整清单:libyuv 支持的全部格式
文档明确说明,以下枚举是 video_common.h 中enum FourCC的完整列表。libyuv 按实现效率对格式进行了分组:主格式(Primary)一步高效转换,次级格式(Secondary)需两步,辅助格式(Auxiliary)则调用主格式的转换器。
3.1 9 个主 YUV 格式(5 平面 + 2 双平面 + 2 打包)
FOURCC_I420 = FOURCC('I', '4', '2', '0'), FOURCC_I422 = FOURCC('I', '4', '2', '2'), FOURCC_I444 = FOURCC('I', '4', '4', '4'), FOURCC_I400 = FOURCC('I', '4', '0', '0'), FOURCC_NV21 = FOURCC('N', 'V', '2', '1'), FOURCC_NV12 = FOURCC('N', 'V', '1', '2'), FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'), FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'), FOURCC_H010 = FOURCC('H', '0', '1', '0'), // 非官方 fourcc,10 bit lsb3.2 1 个次级 YUV 格式(行双平面,row biplanar)
FOURCC_M420 = FOURCC('M', '4', '2', '0'),3.3 11 个主 RGB 格式(4 个 32bpp + 2 个 24bpp + 3 个 16bpp + 1 个 10bpc)
FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'), FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'), FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'), FOURCC_AR30 = FOURCC('A', 'R', '3', '0'), // 每通道 10 位,即 2-10-10-10 FOURCC_AB30 = FOURCC('A', 'B', '3', '0'), // ABGR 版的 10 位格式 FOURCC_24BG = FOURCC('2', '4', 'B', 'G'), FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'), FOURCC_RGBP = FOURCC('R', 'G', 'B', 'P'), // rgb565 小端 FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // argb1555 小端 FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444 小端3.4 1 个主压缩 YUV 格式
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),3.5 8 个辅助 YUV 变体(3 个 UV 平面交换 + 1 个别名等)
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'), FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux 版 I420 FOURCC_J420 = FOURCC('J', '4', '2', '0'), FOURCC_J400 = FOURCC('J', '4', '0', '0'), // 非官方 fourcc FOURCC_H420 = FOURCC('H', '4', '2', '0'), // 非官方 fourcc FOURCC_H422 = FOURCC('H', '4', '2', '2'), // 非官方 fourcc3.6 14 个辅助别名(由CanonicalFourCC()归一化)
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // I420 的别名 FOURCC_YU16 = FOURCC('Y', 'U', '1', '6'), // I422 的别名 FOURCC_YU24 = FOURCC('Y', 'U', '2', '4'), // I444 的别名 FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'), // YUY2 的别名 FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Mac 上 YUY2 的别名 FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // UYVY 的别名 FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Mac 上 UYVY 的别名 FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // MJPG 的别名 FOURCC_DMB1 = FOURCC('d', 'm', 'b', '1'), // Mac 上 MJPG 的别名 FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // BGGR 的别名(Bayer) FOURCC_RGB3 = FOURCC('R', 'G', 'B', '3'), // RAW 的别名 FOURCC_BGR3 = FOURCC('B', 'G', 'R', '3'), // 24BG 的别名 FOURCC_CM32 = FOURCC(0, 0, 0, 32), // BGRA 的别名,对应 kCMPixelFormat_32ARGB FOURCC_CM24 = FOURCC(0, 0, 0, 24), // RAW 的别名,对应 kCMPixelFormat_24RGB FOURCC_L555 = FOURCC('L', '5', '5', '5'), // RGBO 的别名 FOURCC_L565 = FOURCC('L', '5', '6', '5'), // RGBP 的别名 FOURCC_5551 = FOURCC('5', '5', '5', '1'), // RGBO 的别名注:文档列举了 14 个别名,但源码枚举中共列出 17 项(含
FOURCC_IYUV…FOURCC_5551),其中FOURCC_BA81/RGB3/BGR3同时服务于已弃用的 Bayer 家族。严格以 video_common.h 为准。
3.7 已弃用格式(保留仅为向后兼容,不支持转换)
FOURCC_I411 = FOURCC('I', '4', '1', '1'), FOURCC_Q420 = FOURCC('Q', '4', '2', '0'), FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'), FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'), FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'), FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'), FOURCC_H264 = FOURCC('H', '2', '6', '4'),以及通配符FOURCC_ANY = -1(匹配任意格式)。
四、ARGB 家族:4 种布局与字节序真相
4.1 四种 ARGB 布局
libyuv 的 ARGB 家族共 4 种布局:ARGB、BGRA、ABGR、RGBA。其中ARGB 最为常见——它被用于屏幕格式以及 Windows 摄像头驱动。其余三种本质上是同一组通道的四种排列。
4.2 FOURCC 描述的是寄存器顺序,而非内存顺序
这是理解 libyuv 格式最容易混淆的一点。文档明确指出:FOURCC 描述的是通道在寄存器(register)中的顺序。一个采集器给出的 fourcc 可以被看作一个字符串,例如"ARGB"。
在小端机器上,当这个字符串被当作int读取时,'A'位于最低字节。而FOURCC宏会反转这个顺序:
#define FOURCC(a, b, c, d) \ (((uint32_t)(a)) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))因此"ARGB"字符串读作uint32时写作:
FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B')如果你把 ARGB 像素当作uint32数组来读,alpha 在高字节,blue 在最低字节。而在内存(小端存储)中,实际字节序是'B' 在前,随后 'G'、'R','A' 最后。
4.3 调用约定与函数命名
- 转换函数的命名与 FOURCC 一一对应:例如 I420 转 ARGB 就是
I420ToARGB(); - 所有格式都可以转换到/自 ARGB;
- 多数
planar_functions(平面处理函数)作用于 ARGB,例如ARGBBlend; - 部分函数与通道顺序无关(channel order agnostic),例如
ARGBScale——因为它只做像素位置变换,不关心各通道是什么; - 部分函数是对称的:例如
ARGBToBGRA与BGRAToARGB效果相同,因此直接以宏实现。
4.4 ARGBBlend 与预乘 alpha
ARGBBlend期望输入是预乘(preattenuated)alpha的 ARGB:即 R、G、B 各分量已按 alpha 预先乘过。其余函数不关心是否预乘。这一点在调用混合/合成类 API 时务必注意,否则会出现边缘发暗等合成伪影。
五、RGB24 与 RAW:两种 24 位 RGB 布局
RGB 侧除 32 位 ARGB 家族外,还有 2 种 24 位布局,仅在于内存中通道顺序不同:
- RGB24(即 24BG):内存顺序为B、G、R;
- RAW:内存顺序为R、G、B。
对应的转换 API 可参考 convert_from_argb.h 中的ARGBToRGB24()、ARGBToRAW(),反向转换见 convert.h 中的RGB24ToI420()、RAWToI420()。
六、AR30 与 XR30:10 位 HDR 格式
AR30是2-10-10-10的 ARGB,按小端序存储:2 位 alpha + 3 个 10 位 RGB 通道。10 位 RGB 的取值范围为0~1023。
2 位 alpha 只有 4 种取值,与之对应的 8 位 alpha 值如下:
| 2 位 alpha | 比例 | 8 位等价 alpha |
|---|---|---|
| 0 | 0% | 00000000b = 0x00 = 0 |
| 1 | 33% | 01010101b = 0x55 = 85 |
| 2 | 66% | 10101010b = 0xaa = 170 |
| 3 | 100% | 11111111b = 0xff = 255 |
XR30与 AR30 相同,只是没有 alpha 通道。libyuv 提供了ARGBToAR30/ABGRToAR30等入口(见 convert_from_argb.h)。
七、NV12 与 NV21:双平面(biplanar)YUV
NV12是双平面格式:一个全尺寸的 Y 平面,后面紧跟一个交织(weaved)的 U、V 平面。NV21相同,只是交织顺序为V、U。
命名中的数字含义与采样规格:
- NV12的 “12” 指12 bits per pixel;其色度通道为半宽半高,属于420 采样;
- NV16为16 bits per pixel,色度半宽全高,即422采样;
- NV24为24 bits per pixel,色度全尺寸,即444采样。
对应转换 API:NV12ToI420()、NV21ToI420()(见 convert.h)。值得一提的是,NV12/NV21 在 FreeSWITCH 中也以SWITCH_IMG_FMT_NV12的形式出现在 src/include/switch_image.h 的图像格式枚举中。
八、平面 YUV 家族:UV 子采样规则
I420、I422、I444、I400、NV21、NV12 等平面格式遵循统一的内存布局:一个全尺寸的 Y 平面,后随 1~2 个 UV 平面。UV 的大小(子采样)因格式而异:
| 格式 | UV 子采样 | 说明 |
|---|---|---|
| I420、NV12、NV21 | 半宽、半高 | 4:2:0 |
| I422、NV16、NV61 | 半宽、全高 | 4:2:2 |
| I444、NV24、NV42 | 全宽、全高 | 4:4:4 |
| I400、J400 | 无色度通道 | 灰度 |
I420 的每像素位数(bits per pixel)在 video_common.h 的enum FourCCBpp中也有对应定义:FOURCC_BPP_I420 = 12、FOURCC_BPP_I422 = 16、FOURCC_BPP_I444 = 24、FOURCC_BPP_I400 = 8、FOURCC_BPP_ARGB = 32等。这套 BPP 数值可用于估算帧缓冲大小(例如 1280×720 的 I420 帧约为1280*720 + 2*(640*360) = 1382400字节)。
九、FreeSWITCH 中的实际应用:I420 ↔ ARGB 转换
libyuv 在 FreeSWITCH 中的典型用途是视频图像格式转换。src/switch_core_video.c在编译开启SWITCH_HAVE_YUV时直接调用 libyuv API:
- I420 → ARGB:
I420ToARGB(img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y], img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U], img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V], (*new_img)->planes[SWITCH_PLANE_PACKED], (*new_img)->stride[SWITCH_PLANE_PACKED], img->d_w, img->d_h);(见 src/switch_core_video.c,其中SWITCH_PLANE_Y/U/V对应 libyuv 的src_y/src_u/src_v,SWITCH_PLANE_PACKED对应dst_argb。)
- ARGB → I420:
ARGBToI420(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED], (*new_img)->planes[SWITCH_PLANE_Y], (*new_img)->stride[SWITCH_PLANE_Y], (*new_img)->planes[SWITCH_PLANE_U], (*new_img)->stride[SWITCH_PLANE_U], (*new_img)->planes[SWITCH_PLANE_V], (*new_img)->stride[SWITCH_PLANE_V], img->d_w, img->d_h);(见 src/switch_core_video.c。)
此外 FreeSWITCH 还封装了带SWITCH_HAVE_YUV保护的switch_I420ToARGB()等便捷函数(src/switch_core_video.c),并把 libyuv 的 0 返回值规范映射为SWITCH_STATUS_SUCCESS。可见I420/ARGB 正是 FreeSWITCH 内部switch_img_fmt_t与 libyuv 之间交互的枢纽格式,与本文第一节的“双核心”结论完全对应。
9.1 所有转 I420 的总入口:ConvertToI420
若你的场景是采集原始帧后统一落地为 I420,可参考 convert.h 的ConvertToI420:
int ConvertToI420(const uint8_t* sample, size_t sample_size, uint8_t* dst_y, int dst_stride_y, uint8_t* dst_u, int dst_stride_u, uint8_t* dst_v, int dst_stride_v, int crop_x, int crop_y, int src_width, int src_height, int crop_width, int crop_height, enum RotationMode rotation, uint32_t fourcc);它集成了裁剪(crop)、旋转(rotation,0/90/180/270)与垂直翻转,并通过fourcc参数(如'I420'、'YUY2')分发到具体的格式转换器。关键参数说明:
dst_stride_y:dst_y平面每行字节数,通常等于dst_width,建议 16 字节对齐以获得更高效率;dst_stride_u:通常等于(dst_width + 1) / 2,同样建议 16 字节对齐;- 旋转 90/270 度时 stride 会受影响,调用方需按旋转后的尺寸分配缓冲;
- 居中裁剪:
crop_x = (src_width - dst_width) / 2,crop_y = (src_height - dst_height) / 2; src_height可为负值,表示源图像垂直翻转;- 返回 0 表示成功,-1 表示非法参数。
FreeSWITCH 在 src/switch_core_video.c 中已有调用范例(src_size传 0,因为 MJPG 场景不支持)。
十、配合缩放使用的 FilterMode
格式转换常与缩放联动,scale.h 定义了四种滤波模式,可在I420Scale/I444Scale/ARGBScale中选用:
| 枚举 | 值 | 说明 |
|---|---|---|
kFilterNone | 0 | 点采样(最近邻),最快,画质最“块状” |
kFilterLinear | 1 | 仅水平滤波 |
kFilterBilinear | 2 | 双线性,比 box 快,但缩小画质较低 |
kFilterBox | 3 | 平均滤波,画质最高 |
yuvconvert 工具(libs/libyuv/util/yuvconvert.cc)默认使用-f 1(双线性),并可指定-s <w> <h>、-d <w> <h>完成源/目标分辨率设置,是验证格式转换与缩放链路的便捷命令行工具。
十一、如何验证与测试
- 单元测试:unit_test/convert_test.cc 通过
TESTPLANARTOPI等宏,以随机内容对 C 实现与 SIMD 优化实现做逐像素比对(--gtest_filter=*I420ToARGB_Opt可单跑某条优化路径); - 基准测试:
--libyuv_width=1280 --libyuv_height=720 --libyuv_repeat=999可对 720p 帧做压测,--libyuv_flags=-1表示启用所有 CPU 优化,--libyuv_cpu_info=1可强制走 C 代码路径对比; - 构建方式:libyuv 支持 GN/ninja、make(
make -f linux.mk)与 CMake 三种构建,具体步骤见 libs/libyuv/docs/getting_started.md。
十二、速查表与常见误区
12.1 字节序与内存顺序速查(小端)
| FOURCC 名称 | 寄存器顺序 | 内存顺序 |
|---|---|---|
| ARGB | A 高字节、B 最低字节 | B G R A |
| BGRA | B 高字节、A 最低字节 | A R G B |
| ABGR | A 高字节、R 最低字节 | R G B A |
| RGBA | R 高字节、A 最低字节 | A B G R |
| RGB24(24BG) | — | B G R |
| RAW | — | R G B |
12.2 高频误区
- “ARGB 内存里就是 A R G B”是错的:小端机器上内存顺序是 B G R A。这也是 OSX
kCMPixelFormat_32ARGB反而映射FOURCC_BGRA的原因。 - 别名不等于独立格式:
IYUV、YUYV、JPEG、CM32等都会经CanonicalFourCC()归一化到主格式,video_common.cc中那张 18 项的别名表就是全部规则。 V210已移除:不要再假设 10 位 4:2:2 有官方支持。- Bayer(RGGB/BGGR/GRBG/GBRG)已弃用:仅保留枚举,无转换支持。
- ARGBBlend 要求预乘 alpha,其余 ARGB 系函数不要求。
FOURCC_ANY = -1是通配符,用于“匹配任意 fourcc”的查询场景。
结语
libyuv 的格式体系可以用一句话概括:I420 是 YUV 的枢纽,ARGB 是 RGB 的枢纽,其余几十种 FOURCC 都是围绕这两个核心的排列组合、别名或采样变体。把握住“FOURCC 描述寄存器顺序而非内存顺序”这一关键,再配合CanonicalFourCC()的别名归一化规则,就能在 FreeSWITCH 视频管线与各种采集/渲染设备之间自如地进行格式适配。本文所有代码与表格均可直接对照仓库源码(formats.md、video_common.h、convert.h、convert_argb.h、src/switch_core_video.c)逐项验证。
- 通信
- 音视频
【免费下载链接】freeswitch
FreeSWITCH is a Software Defined Telecom Stack enabling the digital transformation from proprietary telecom switches to a versatile software implementation that runs on any commodity hardware. From a Raspberry PI to a multi-core server, FreeSWITCH can unlock the telecommunications potential of any device.
相关推荐
ImageSharp像素格式转换终极指南:无损转换与色彩空间映射技巧
ImageSharp像素格式转换终极指南:无损转换与色彩空间映射技巧 ImageSharp是一个现代化的跨平台2D图形库,专为.NET开发设计,提供高效的图像处
图像处理图形学Dolphin游戏映像格式转换完全指南
Dolphin游戏映像格式转换完全指南 Dolphin模拟器作为GameCube和Wii游戏的优秀模拟平台,支持多种游戏映像格式。了解如何在不同格式间转换,对于
游戏开发图形学跨平台xLua 核心 API 全解析:从 C 调用 Lua 到类型映射与内置宏
xLua 核心 API 全解析:从 C 调用 Lua 到类型映射与内置宏 导读 本文以 xLua 官方 API 参考文档( XLua_API_EN.md htt
游戏开发脚本语言集成
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考