===============================================
音视频入门基础:像素格式专题系列文章:
音视频入门基础:像素格式专题(2)——不通过第三方库将RGB24格式视频转换为BMP格式图片
音视频入门基础:像素格式专题(3)——FFmpeg源码解析BMP格式图片的底层实现原理
音视频入门基础:像素格式专题(5)——使用OpenGL实现yuv420p转rgb播放视频(三重纹理实现)
===============================================
一、YUV简介
YUV是一种颜色编码方法。它跟我们常见的RGB格式区分开来,常使用在各个视频处理组件中。其中"Y"代表明亮度,"U"和"V"代表其色度。视频播放器把市面上流行的MP4等格式文件的视频部分解码出来,得到的一般会是YUV格式的数据,然后得进行像素格式转换(比如通过opengl的shader或者ffmpeg),把YUV格式的数据转成RGB格式的数据,然后才能在显示屏播放显示。
YUV与RGB相比,优点是:
1.亮度参量和色度参量分开表示,不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大(也就是说色度频道的采样率可比 Y 频道低,同时不会明显降低视觉质量)。
2.兼容老式黑白电视,使黑白电视机也能接收彩色电视信号。
3.只需要极少的频宽来进行视频信号传输。
4.占用空间小,对于同一幅图像,使用YUV420表示比RGB24表示少占用一半的空间,数据率压缩了一倍,而图像的效果基本没发生变化。
RGB24一帧的大小size=width×heigth×3 Byte
RGB32一帧的大小size=width×heigth×4 Byte
YUV420一帧的大小size=width×heigth×1.5 Byte
二、通过FFmpeg命令转换得到YUV文件
如下图所示,工程目录下有video1.mp4这个MP4文件,下面我们介绍把它转为YUV文件的方法。
在命令提示符cmd.exe中进入当前工程所在目录(ffmpeg.exe和video1.mp4所在目录),然后输入命令:
ffmpeg -i video1.mp4 -s 640x272 -pix_fmt yuv420p video1.yuv
该命令的作用是把所在路径下的video1.mp4文件转换为帧宽度为640,帧高度为272,像素格式为yuv420p的YUV文件:video1.yuv。
注:
-i 表示设定输入流
-s 设定画面的宽与高
-pix_fmt 设定的像素格式
YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。yuv420p是planar格式的YUV格式,对于这种格式,其先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V(在ffmpeg中是存储在struct AVFrame的data[]数组中,data[0]存放Y分量、data[1]存放U分量、data[2]存放V分量。AVFrame的linesize[]数组中保存的是对应通道的数据宽度,linesize[0]存放Y分量的宽度,linesize[1]存放U分量的宽度,linesize[2]存放V分量的宽度。注意,linesize[0]的值并不一定等于图片的宽度,有时候为了对齐各解码器的CPU,实际尺寸会大于图片的宽度,所以得作行对齐处理)。 对于packed格式的YUV格式,每个像素点的Y,U,V是连续交叉存储的(在ffmpeg中YUV分量都存贮在AVFrame的data[0]数组中)。
执行该命令后,我们发现工程目录下会生成video1.yuv文件,如下图所示:
三、存贮空间分析
由上图可知,4:2:0 水平方向是1/2,垂直方向是1/2,表示一个色度像素对应了四个图形像素。
所以对于一张yuv420p格式的分辨率为640 * 272的图片,
每一个像素都需要一个亮度(luminance)值,即y。那么总共需要 640 * 272 = 174080 字节
每四个像素都需要一个色度(chrominance)u值,那么总共需要 640 * 272 / 4 = 43520 字节
每四个像素都需要一个色度(chrominance)v值,那么总共需要 640 * 272 / 4 = 43520 字节
把 y、u、v 三个 plane 加起来就是:174080 + 43520 + 43520 = 261120 字节
所以对于一张yuv420p格式的分辨率为640 * 272的图片,其需要占用261120字节的存贮空间。
然后由命令:
ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 video1.mp4
可以知道video1.mp4总共有5443帧(5443张图片)。
注:
-v error
这隐藏了“信息”输出(版本信息等),使分析更容易。
-count_frames
计算每个流的帧数并在相应的流部分报告。
-select_streams v:0
只选择视频流。
-show_entries stream=nb_read_frames
仅显示读取帧的数量。
-of default=nokey=1:noprint_wrappers=1
设置输出格式(即“作者”)default
,不要打印每个字段(nokey=1
)的关键字,并且不要打印节标题和页脚
所以可以计算出video1.yuv大小为:5443 * 261120 = 1421276160字节。
查看video1.yuv的属性,可以看到系统显示的大小和我们计算的完全吻合。
四、使用ffplay.exe播放YUV文件
YUV文件用市面上流行的播放器我们一般无法直接播放。但我们可以通过FFmpeg提供的ffplay.exe播放YUV文件。
在命令提示符cmd.exe中进入当前工程所在目录(ffplay.exe和video1.yuv所在目录),然后输入命令:
ffplay -video_size 640x272 -i video1.yuv
该命令的作用是使用ffplay播放帧宽度为640,帧高度为272的YUV文件vido1.yuv
注:
-i 表示指定的输入文件
-video_size 播放的视频文件的帧宽度和帧高度
如下图所示,看到如下画面,则表示播放成功。
使用代码用OpenGL播放YUV(yuv420p)文件的方法可以参考:《windows下使用OpenGL实现yuv420p转rgb播放视频(三重纹理实现)》
五、附件资源下载
本博文附件资源下载地址在https://download.csdn.net/download/u014552102/10700001,资源里面包含博文演示用的ffplay.exe,ffmpeg.exe工具,转换用的video1.mp4视频文件,和转换成功的video1.yuv文件,用户可以结合该资源和博文学习生成和播放yuv文件的方法