【音视频系列1】视频格式YUV444、YUV422,、YUV420详解
本篇文章仅介绍YUV444、YUV422、YUV420等使用比较频繁的格式
简介:
YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
历史:
Y'UV的发明是由于彩色电视与黑白电视的过渡时期。黑白视频只有Y(Luma,Luminance)视频,也就是灰阶值。到了彩色电视规格的制定,是以YUV/YIQ的格式来处理彩色电视图像,把UV视作表示彩度的C(Chrominance或Chroma),如果忽略C信号,那么剩下的Y(Luma)信号就跟之前的黑白电视频号相同,这样一来便解决彩色电视机与黑白电视机的兼容问题。Y'UV最大的优点在于只需占用极少的带宽。
YUV颜色空间分布:
如果一个图像的宽和高已经确定,那么对于转换后的YUV各个格式的字节占用如下:
YUV444:表示每一个Y对应一个UV分量(如图),那么YUV对应的个数相同,YUV444所占用空间:即编码字节空间为=宽*高*3 (Y = U = V 宽高均相等)
YUV422:表示每两个Y对应一个UV分量,那么Y的个数是UV的个数*2,YUV422那么所占空间:即编码字节空间为=(Y)宽*高 + (U)宽*高*1/2 + (V)宽*高*1/2 = 宽*高*2 (Y宽 = 2*U宽 = 2*V宽,高度YUV相同)
YUV420:表示每4个Y对应一个UV分量,那么Y的个数是UV的个数*4,YUV420那么所占空间:即编码字节空间为=(Y)宽*高 + (U)宽*高*1/4 * (V)宽*高*1/4 = 宽*高*3/2 (Y宽高均为UV宽高的两倍)
分析:
编写C代码分别对各个格式进行读写分析,其中需要把YUV的每个分量保存为Y分量文件 ,此时需要YUV播放的软件,暂时使用YUV player
1:先用ffmpeg转换出3中格式的文件(本文使用图片进行测试:相当于一帧的视频)
网络获取一张图片,使用ffmpeg生成3种格式的YUV文件,命令如下:
1 2 3 | ffmpeg -i test .jpg -pix_fmt yuv444p test_444.yuv ffmpeg -i test .jpg -pix_fmt yuv422p test_422.yuv ffmpeg -i test .jpg -pix_fmt yuv420p test_420.yuv |
2:用C代码读取并分别分离出各个文件的Y、U、V分量文件:
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 | enum YUVTYPE { YUV444, YUV422, YUV420 }; void read_split_yuvfile( const char * file, int width, int heiht, YUVTYPE yuvtype, int frames) { FILE * yuvFp = fopen (file, "rb+" ); FILE * yFp = fopen ( "E:\\test_y.y" , "wb+" ); FILE * uFp = fopen ( "E:\\test_u.y" , "wb+" ); FILE * vFp = fopen ( "E:\\test_v.y" , "wb+" ); unsigned char * buf = NULL; int size = width * heiht; if (YUV444 == yuvtype) buf = (unsigned char *) malloc (size * 3); else if (YUV422 == yuvtype) buf = (unsigned char *) malloc (size << 1); else buf = (unsigned char *) malloc (size * 3 >> 1); for ( int i = 0; i < frames; i++) { if (YUV444 == yuvtype) { fread (buf, 1, size * 3, yuvFp); fwrite (buf, 1, size, yFp); fwrite (buf + size, 1, size, uFp); fwrite (buf + (size << 1), 1, size, vFp); } else if (YUV422 == yuvtype) { fread (buf, 1, size << 1, yuvFp); fwrite (buf, 1, size, yFp); fwrite (buf + size, 1, size >> 1, uFp); fwrite (buf + (size * 3 >> 1), 1, size >> 1, vFp); } else { fread (buf, 1, size * 3 >> 1, yuvFp); fwrite (buf, 1, size, yFp); fwrite (buf + size, 1, size >> 2, uFp); fwrite (buf + (size * 5 >> 2), 1, size >> 2, vFp); } } free (buf); buf = NULL; fclose (yuvFp); fclose (yFp); fclose (uFp); fclose (vFp); } |
生成文件大小与YUV的分量比相同,YUV444为1:1:1 YUV422为2:1:1 YUV420为4:1:1
由于压缩比较高,所以YUV420使用的比较多,YUV分量图示如下:
Y:
U:
V:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现