做过一段时间的音视频开发,逐渐知道 MP4 文件中的 MP4 只是一种封装格式,里面的音视频数据则一般实际上是 H264。
而 H264 其实也有很多种的版本,比如 H264 High、H264 Main、H264 Baseline,这些版本的区别在于支持的功能不同,比如 H264 Baseline 不支持 B 帧,H264 Main 支持 4:2:2 色彩取样格式,H264 High 支持 4:4:4 色彩取样格式。
在处理视频文件错误的过程中,也积累了一些经验,逐渐了解了 MP4 文件的 Profile 和 Level,以及 YUV 颜色空间的概念。
Profile 和 Level
**Profile(配置集)**表示编码器在生成视频流时所使用的压缩算法的集合。不同的Profile支持不同的功能和压缩效率。
在H.264中,一些常见的Profile有Baseline、Main和High等。
Baseline Profile 是最基本的 Profile,它提供了基本的视频压缩功能。此前在前面的文章中描述过,遇到视频使用 Baseline Profile 编码,导致视频只有一个关键帧,无法拖动进度条的问题。
Main Profile 在 Baseline 的基础上增加了一些高级功能,例如支持B帧和更复杂的编码。
High Profile 是最高级别的 Profile,它支持更多的功能和更高的压缩效率。
**Level(级别)**表示编码器生成的视频流的各种技术参数的限制。这些参数包括分辨率、帧率、比特率等。
Level 的目的是确保解码器能够正确解码和播放视频流,因为不同的设备和平台对视频流的解码能力有不同的限制。较高的Level通常意味着更高的分辨率、帧率和比特率。
常见的 Level 有 3.0、3.1、4.0、4.1、4.2 等。
可以使用 ffmpeg 命令将视频转为不同的 Profile 和 Level,比如:
shell
ffmpeg -i input.mp4 -profile:v baseline -level 3.0 base-3.0.mp4
ffmpeg -i input.mp4 -profile:v baseline -level 3.1 base-3.1.mp4
ffmpeg -i input.mp4 -profile:v main -level 3.1 main-3.1.mp4
ffmpeg -i input.mp4 -profile:v main -level 4.0 main-4.0.mp4
ffmpeg -i input.mp4 -profile:v high -level 4.0 high-4.0.mp4
ffmpeg -i input.mp4 -profile:v high -level 4.1 high-4.1.mp4
ffmpeg -i input.mp4 -profile:v high -level 4.2 high-4.2.mp4
YUV 颜色空间
YUV是一种常见的颜色空间,用于表示彩色图像。它将颜色信息分为亮度(Y)和色度(U和V)两个分量。
现在 YUV 一般都是指 YCbCr,其中 Y表示图像的亮度信息,而U和V表示图像的色度信息。在视频编码中,通常使用YUV颜色空间来表示原始图像数据,因为它可以更好地压缩和传输彩色图像。
YUV 和 RGB 可以相互转换。
RGB 转 YUV 的公式如下:
js
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
YUV 转 RGB 的公式如下:
js
R = 1.164(Y - 16) + 1.596(V -128)
G = 1.164(Y - 16) - 0.813(V -128) - 0.391(U - 128)
B = 1.164(Y - 16) + 2.018(U - 128)
下面是 RGB 颜色空间和 YUV 颜色空间如果只有单分量的效果:
可以看到如果只有 Y 分量,那就相当于黑白图像,而 U、V 分量则是用来表示颜色的。
电视节目中的彩色图像通常使用YUV颜色空间来表示,可以兼容黑白电视和彩色电视。黑白电视只使用Y分量,而彩色电视使用YUV颜色空间的所有分量。
YUV420 YUV422 YUV444
根据 YUV 分量的取样方式,可以将 YUV 分为 YUV 4:4:4、YUV 4:2:2 和 YUV 4:2:0 三种,其中 YUV4:2:0 则是最常用的一种。
- YUV 4:4:4采样,每一个Y对应一组UV分量。
- YUV 4:2:2采样,每两个Y共用一组UV分量。
- YUV 4:2:0采样,每四个Y共用一组UV分量。
我们有时候会看到 YUV420p 这样的描述,这里的 420 表示的就是 YUV420 的意思,p 表示的是 planar,也就是平面的意思,表示 Y、U、V 三个分量是分开存储的,而不是交叉存储的。
一般来说,YUV420p 和 YUV420 是一个意思。
与之不同的是 YUV420sp 和 YUV420i,但是不常用。其中 sp 表示的是 semi-planar,也就是半平面的意思,表示 Y 分量是单独存储的,而 U、V 分量是交叉存储的。i 表示的是 interleaved,也就是交叉的意思,表示 Y、U、V 三个分量是交叉存储的。
可以使用 ffmpeg 命令将视频转为不同的 YUV 格式,比如:
shell
ffmpeg -i input.mp4 -pix_fmt yuv420p yuv420p.mp4
ffmpeg -i input.mp4 -pix_fmt yuv422p yuv422p.mp4
ffmpeg -i input.mp4 -pix_fmt yuv444p yuv444p.mp4
Profile 和 YUV 颜色空间的关系
虽然Profile和YUV颜色空间是两个不同的概念,但它们在视频编码中是相关的。
在视频编码过程中,编码器将原始的RGB图像转换为YUV颜色空间,然后根据所选的 Profile 对YUV数据进行压缩编码。
因此,Profile 决定了编码器使用的压缩算法和功能,而YUV颜色空间则是表示原始图像数据的一种格式。
一般来说,Profile 和 YUV 颜色空间是一一对应的,比如 H264 Baseline Profile 只支持 YUV420p,H264 Main Profile 一般支持 YUV420p,只有 H264 High Profile 支持 YUV420p、YUV422p 和 YUV444p。
下面是一个视频的 Profile 和 YUV 数据示例:
基于 mp4box.js 读取 MP4 文件的 Profile 和 Level
使用 mp4box.js 分析 MP4 文件,得到视频文件的 moov box 之后,就可以从中读取 Profile 和 Level 了。
这些数据存储在moov(Movie Box)box中的trak(Track Box)box中的mdia(Media Box)box中的minf(Media Information Box)box中的stbl(Sample Table Box)box中的stsd(Sample Description Box)box中的avc1(AVC Sample Entry)box中。
具体来说,avc1 box 中的 avcC(AVC Configuration Box)box 中的 AVCProfileIndication 和 AVCLevelIndication 字段就是 Profile 和 Level 的值。
AVCProfileIndication 一般取值为 66、77、88、100、110、122、244,对应的 Profile 分别是 Baseline、Main、Extended、High、High10、High422、High444。
AVCLevelIndication 一般取值为 30、31、32、40、41、42、50、51、52,对应的 Level 分别是 3.0、3.1、3.2、4.0、4.1、4.2、5.0、5.1、5.2。
js
const ProfileMap = {
66: "Baseline",
77: "Main",
88: "Extended",
100: "High",
110: "High10",
122: "High422",
244: "High444",
};
const ColorSpaceMap = {
66: "YUV4:2:0",
77: "YUV4:2:0",
88: "YUV4:2:0",
100: "YUV4:2:0",
110: "YUV4:2:0",
122: "YUV4:2:2",
244: "YUV4:4:4",
};
下面是读取 Profile 和 Level 的代码:
js
const videoTrackId = info.videoTracks[0].id;
const moovVideoTrack = mp4box.moov.traks.find((track) => track.tkhd.track_id === videoTrackId);
const entries = get(moovVideoTrack, "mdia.minf.stbl.stsd.entries", []);
const profileName = avcC?.AVCProfileIndication &&
`${ProfileMap[avcC.AVCProfileIndication]}@L${(avcC.AVCLevelIndication / 10).toFixed(1)}`;
const colorSpace = avcC?.AVCProfileIndication && ColorSpaceMap[avcC.AVCProfileIndication]
当前主流浏览器支持的视频编码格式中,除了 H264 之外,另一个则是 AV1。
AV1 编码格式
我们知道现在视频常用的编码格式依然是 H264,但是 H264 已经有十多年的历史了,最高只支持 4K 分辨率,而且压缩率也不高,所以需要新的编码格式来取代 H264。
而 H265 由于专利费的原因,没有被广泛使用,基本没有多少硬件支持 H265 编码,需要播放 H265 编码的视频,都需要软件解码,对电脑 CPU 占用很高。
而 Google 推出的 VP8 和 VP9 编码格式,虽然免费,但是没有被广泛支持,所以也没有取代 H264 的趋势。
所以 AV1 成为了最有可能取代 H264 的编码格式。AV1 即 AOMedia Video 1,是由 AOMedia 开发的开源视频编码格式,它的目标是取代 H264 和 VP9,成为下一代的视频编码格式。
AOMedia 是一个由多家科技公司组成的联盟,旨在开发开放、免版权的音视频编码技术。该联盟的创始成员包括谷歌、苹果、亚马逊、Facebook、微软等。
AV1 相比 H264,有着更高的压缩率,可以减少 30% 的码率,同时保持相同的视频质量。相比 H265,AV1 则是免费的,没有专利费,各大厂商也愿意支持 AV1。
但目前 AV1 的硬件支持还不够,所以 AV1 的编码速度比较慢,而且 AV1 的解码速度也比较慢,在国内并没有被广泛支持。