【FFmpeg学习】YUV采样方式与存储格式

1. 音视频播放原理

音视频播放的原理主要分为:解协议->解封装->解码->音视频同步->播放。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6XASE4OD-1646829498402)(<> “点击并拖拽以移动”)]​

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8CnXBENa-1646829498410)(<> “点击并拖拽以移动”)]​

1.解协议:将流媒体协议的数据解析为相应的封装格式数据,比如RTMP协议解析后得到flv,HLS协议解析后得到ts。流媒体协议在音视频传输的同时,还会包含一些其他的数据,比如RTMP协议会包含一些信令数据,这些信令数据包括对播放的控制(暂停,播放,停止等),或者是对网络状态的描述。HLS协议中会包含索引文件等等。解协议的过程就是只保留音视频数据,去除掉其他的数据。

2.解封装:经过解协议过程,得到视频的封装格式数据后,解封装过程会将其分离成为某种编码格式的音频压缩数据和某种编码格式的视频压缩数据,有的可能还包括字幕和脚本。例如:flv或ts格式的数据,解封装后得到H.264编码的视频码流和AAC编码的音频码流。

3.解码:解封装过程完毕后,分别得到压缩的视频码流和音频码流,解码的过程就是将压缩(编码)后的音视频数据解压,得到系统音频驱动和视频驱动能够识别的音频采样数据(如PCM数据)和视频像素数据(如YUV420P,RGB)。

音频编码: G.711, G722, G726, AAC,MP1/MP2/MP3, AC-3, WMA…

视频编码: h265/H264/H263,MPEG1/2/3/4, WMV, MJPEG, VP8/VP9…

4.视音频同步:根据时间,帧率和采样率采用一定的算法,同步解码出来的视频和音频数据,并将视频音频数据送至显卡和声卡播放出来。

ffmpeg解码流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WQvp6yS2-1646829498433)(<> “点击并拖拽以移动”)]​

1. 注册所有容器格式和CODEC:av_register_all()
2. 打开文件:av_open_input_file()
3. 从文件中提取流信息:av_find_stream_info()
4. 穷举所有的流,查找其中种类为CODEC_TYPE_VIDEO
5. 查找对应的解码器:avcodec_find_decoder()
6. 打开编解码器:avcodec_open()
7. 为解码帧分配内存:avcodec_alloc_frame()
8. 不停地从码流中提取出帧数据:av_read_frame()
9. 判断帧的类型,对于视频帧调用:avcodec_decode_video()
10. 解码完后,释放解码器:avcodec_close()
11. 关闭输入文件:av_close_input_file()

2. 图像篇(YUV 和 RGB)

2.1 YUV 格式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e1DIZvUU-1646829498444)(<> “点击并拖拽以移动”)]​

YUV是视频、图片、相机等应用中使用的一类图像格式,实际上是所有“YUV”像素格式共有的颜色空间的名称。 与RGB格式(红 - 绿 - 蓝)不同,YUV是用一个称为Y(相当于灰度)的“亮度”分量和两个“色度”分量表示,分别称为U(蓝色投影)和V(红色投影),由此得名。

Y表示亮度分量:如果只显示Y的话,图像看起来会是一张黑白照。

U(Cb)表示色度分量:是照片蓝色部分去掉亮度(Y)。

V(Cr)表示色度分量:是照片红色部分去掉亮度(Y)。

YUV格式可以分为三个分量,即Y、U、V一一对应。

但和RGB不一样的是,利用人体眼睛对亮度分量(Y)敏感,而对色度分量(U和V)不敏感的原理,视频可以通过降低色度分量的采样数据,达到降低视频数据量而人眼很难分辨的目的。所以,目前流行的YUV采样,基本都是降低色度分量的采集。也就是说,一个视频帧中,亮度分量Y的采样数不会被改变,但色度分量U和V会被降低采样数(downsampling)。\

2.2 YUV 采样方式

YUV采样格式有:YUV444、YUV440、YUV422、YUV420和YUV411。

采样格式是指按照比例降采样色度分量即UV分量,多个像素中公用一个UV分量来减少带宽。YUVABC格式中表示第一行数据中Y和UV分量采样比例为A:B,第二行数据的Y和UV的采样比例为A:C,而UV采样比例一直是1:1,以此方式不断重复。

关于内存占用,因为YUV模式的每个分量都是存储在一个字节(8bit)中的。那么一个像素点也就占用 24 bit,也就是三个字节。那么一个像素点也就占用 24 bit,也就是三个字节。

一张 1280 * 720 大小的图片,就占用 1280 * 720 * 3 / 1024 / 1024 = 2.63 MB 存储空间。

YUV 图像的主流采样方式有如下三种:

  • YUV 4:4:4 采样
  • YUV 4:2:2 采样
  • YUV 4:2:0 采样

YUV 4:4:4 采样

YUV 4:4:4 采样,意味着 Y、U、V 三个分量的采样比例相同,因此在生成的图像里,每个像素的三个分量信息完整,都是 8 bit,也就是一个字节。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lJ09P509-1646829498452)(<> “点击并拖拽以移动”)]​

其中,Y 分量用叉表示,UV 分量用圆圈表示。

举个例子 :
 
假如图像像素为:[Y0 U0 V0]、[Y1 U1 V1]、[Y2 U2 V2]、[Y3 U3 V3]
 
那么采样的码流为:Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3 
 
最后映射出的像素点依旧为 [Y0 U0 V0]、[Y1 U1 V1]、[Y2 U2 V2]、[Y3 U3 V3]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ijbEWswX-1646829498455)(<> “点击并拖拽以移动”)]

为了方便对比,我们挑画面下方横条渐变色块6x5个像素放大40倍,看像素的YUV值(其它采样也取相同位置)。
从如下图所示,可以看出相邻的像素点的Y/U/V值不相等也可以看出每个像素都有独立的U/V值

I444[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Pr5ahzE-1646829498467)(<> “点击并拖拽以移动”)]​

可以看到这种采样方式的图像和 RGB 颜色模型的图像大小是一样,并没有达到节省带宽的目的,当将 RGB 图像转换为 YUV 图像时,也是先转换为 YUV 4:4:4 采样的图像。

YUV 4:2:2 采样

YUV 4:2:2 采样,意味着 UV 分量是 Y 分量采样的一半,Y 分量和 UV 分量按照 2 : 1 的比例采样。如果水平方向有 10 个像素点,那么采样了 10 个 Y 分量,而只采样了 5 个 UV 分量。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0NlT6Oug-1646829498477)(<> “点击并拖拽以移动”)]​

其中,Y 分量用叉表示,UV 分量用圆圈表示。

总之,Y 分量肯定是一直都有的

 举个例子 :
 
 假如图像像素为:[Y0 U0 V0]、[Y1 U1 V1]、[Y2 U2 V2]、[Y3 U3 V3]
 
 那么采样的码流为:Y0 U0 Y1 V1 Y2 U2 Y3 V3 
 
 其中,每采样过一个像素点,都会采样其 Y 分量,而 U、V 分量就会间隔一个采集一个。
 
 最后映射出的像素点为 [Y0 U0 V1]、[Y1 U0 V1]、[Y2 U2 V3]、[Y3 U2 V3]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9pQkpyF-1646829498482)(<> “点击并拖拽以移动”)]

422采样,水平方向每两个像素共用一对U/V值,下如图绿色框(U channel)和蓝色框(V channel)标记的一个框在内存中只有一个值。

I422[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oS17tAcM-1646829498493)(<> “点击并拖拽以移动”)]​

采样的码流映射为像素点,还是要满足每个像素点有 Y、U、V 三个分量。但是可以看到,第一和第二像素点公用了 U0、V1 分量,第三和第四个像素点公用了 U2、V3 分量,这样就节省了图像空间。

一张 1280 * 720 大小的图片,在 YUV 4:2:2 采样时的大小为:

(1280 * 720 * 8 + 1280 * 720 * 0.5 * 8 * 2)/ 8 / 1024 / 1024 = 1.76 MB,其中8是 比特

可以看到 YUV 4:2:2 采样的图像比 RGB 模型图像节省了三分之一的存储空间,在传输时占用的带宽也会随之减少。

YUV 4:2:0 采样

YUV 4:2:0 采样,并不是指只采样 U 分量而不采样 V 分量。而是指,在每一行扫描时,只扫描一种色度分量(U 或者 V),和 Y 分量按照 2 : 1 的方式采样。比如,第一行扫描时,YU 按照 2 : 1 的方式采样,那么第二行扫描时,YV 分量按照 2:1 的方式采样。对于每个色度分量来说,它的水平方向和竖直方向的采样和 Y 分量相比都是 2:1 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0z3sIjPD-1646829498498)(<> “点击并拖拽以移动”)]​

其中,Y 分量用叉表示,UV 分量用圆圈表示。

假设第一行扫描了 U 分量,第二行扫描了 V 分量,那么需要扫描两行才能够组成完整的 UV 分量。

假设图像像素为:

[Y0 U0 V0]、[Y1 U1 V1]、 [Y2 U2 V2]、 [Y3 U3 V3]
[Y5 U5 V5]、[Y6 U6 V6]、 [Y7 U7 V7] 、[Y8 U8 V8]

那么采样的码流为:Y0 U0 Y1 Y2 U2 Y3 Y5 V5 Y6 Y7 V7 Y8
// 第一行取u分量,取u0,u2; 第二行取 V分量,取v5,v7。[因为上下2像素类似,分别取uv]

其中,每采样过一个像素点,都会采样其 Y 分量,而 U、V 分量就会间隔一行按照 2 : 1 进行采样。

最后映射出的像素点为:

[Y0 U0 V5]、[Y1 U0 V5]、[Y2 U2 V7]、[Y3 U2 V7]
[Y5 U0 V5]、[Y6 U0 V6]、[Y7 U2 V7]、[Y8 U2 V8]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vG1CPTpn-1646829498500)(<> “点击并拖拽以移动”)]

从映射出的像素点中可以看到,四个 Y 分量是共用了一套 UV 分量,而且是按照 2*2 的小方格的形式分布的,相比 YUV 4:2:2 采样中两个 Y 分量共用一套 UV 分量,这样更能够节省空间。

一张 1280 * 720 大小的图片,在 YUV 4:2:0 采样时的大小为:

(1280 * 720 * 8 + 1280 * 720 * 0.25 * 8 * 2)/ 8 / 1024 / 1024 = 1.32 MB

420采样,因为是相邻的4个像素共用一对U/V,所以会出现如下图所示,每四个相邻的像素就出现4个相同的UV值。

I420[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ddwVcNp-1646829498517)(<> “点击并拖拽以移动”)]​

可以看到 YUV 4:2:0 采样的图像比 RGB 模型图像节省了一半的存储空间,因此它也是比较主流的采样方式。

一文读懂 YUV 的采样与格式_cindywry的博客-CSDN博客_yuv采样

2.3 YUV 存储格式

YUV 的存储格式,有两种:

  • planar  平面格式

    • 指先连续存储所有像素点的 Y 分量,然后存储 U 分量,最后是 V 分量。
  • packed  打包模式

    • 指每个像素点的 Y、U、V 分量是连续交替存储的。
  • 半平面格式YUV

介入上面两种格式的一种中间格式.Y分量单独存储,但是UV分量交叉存储。eg YYYYUVUV,

代表格式有NV12 NV21.,后缀是SP,YUV420SP。

根据采样方式和存储格式的不同,就有了多种 YUV 格式。这些格式主要是基于 YUV 4:2:2 和 YUV 4:2:0 采样。

YUV 4:2:2 采样
YUYV 格式
UYVY 格式
YUV 422P 格式

常见的基于 YUV 4:2:0 采样的格式如下表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YtTwak7R-1646829498525)(<> “点击并拖拽以移动”)]​

1)packed  打包模式

YUYV 格式

YUYV 格式是采用打包格式进行存储的,指每个像素点都采用 Y 分量,但是每隔一个像素采样它的 UV 分量,排列顺序如下:

Y0 UO Y1 V0  Y2 U2 Y3 V2

Y0 和 Y1 公用 U0 V0 分量,Y2 和 Y3 公用 U2 V2 分量….

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5HtRWa3Z-1646829498532)(<> “点击并拖拽以移动”)]​

UYVY 格式

UYVY 格式也是采用打包格式进行存储,它的顺序和 YUYV 相反,先采用 U 分量再采样 Y 分量,排列顺序如下:

U0 Y0 V0 Y1 U2 Y2 V2 Y3

Y0 和 Y1 公用 U0 V0 分量,Y2 和 Y3 公用 U2 V2 分量….

根据 UV 和 Y 的顺序还有其他格式,比如,YVYU 格式,VYUY 格式等等,原理大致一样了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GcVYrwC-1646829498546)(<> “点击并拖拽以移动”)]​

2)planar  平面格式

基于 YUV 4:2:0 采样的格式主要有 YUV 420P 和 YUV 420SP 两种类型,每个类型又对应其他具体格式。

  • YUV 420P 类型

    • YU12 格式
    • YV12 格式
  • YUV 420SP 类型

    • NV12 格式
    • NV21 格式

YUV 420P 和 YUV 420SP 都是基于  Planar 平面模式 进行存储的,先存储所有的 Y 分量后, YUV420P 类型就会先存储所有的 U 分量或者 V 分量,而 YUV420SP 则是按照 UV 或者 VU 的交替顺序进行存储了,具体查看看下图:

YUV420P 的格式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RCu5ikGL-1646829498553)(<> “点击并拖拽以移动”)]​

YUV420SP 的格式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RMq0EiKN-1646829498563)(<> “点击并拖拽以移动”)]​

NV12 和 NV21 格式

NV12 和 NV21 格式都属于 YUV420SP 类型。它也是先存储了 Y 分量,但接下来并不是再存储所有的 U 或者 V 分量,而是把 UV 分量交替连续存储。

NV12 是 IOS 中有的模式,它的存储顺序是先存 Y 分量,再 UV 进行交替存储。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J2PTTiUU-1646829498572)(<> “点击并拖拽以移动”)]​

NV21 是 安卓 中有的模式,它的存储顺序是先存 Y 分量,在 VU 交替存储。

2.4 YUV 与 RGB 相互转换

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

RGB 到 YUV 的转换,就是将图像所有像素点的 R、G、B 分量转换到 Y、U、V 分量。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9SHWlVxi-1646829498588)(<> “点击并拖拽以移动”)]​

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ecQtRUl-1646829498599)(<> “点击并拖拽以移动”)]​

此时的转换结束后,每个像素点都有完整的 Y、U、V 分量。而之前提到 Y 和 UV 分量是可以分离的,接下来通过不同的采样方式,可以将图像的 Y、U、V 分量重新组合。

◆ RGB 转 YUV:

Y = 0.299R + 0.587G + 0.114B

U= -0.147R - 0.289G + 0.436B

V = 0.615R - 0.515G - 0.100B

◆ YUV 转 RGB:

R = Y + 1.14V

G = Y - 0.39U - 0.58V

B = Y + 2.03U

YUV格式详解【全】_xkuzhang的博客-CSDN博客_yuv

音视频&流媒体的原理以及基础入门知识_zhangbijun1230的专栏-CSDN博客

【Android 音视频开发打怪升级:音视频硬解码篇】一、音视频基础知识 - 简书

音视频播放器工作原理_WayneSun729的博客-CSDN博客

\

猜你喜欢

转载自blog.csdn.net/qq_40587575/article/details/123386794