音视频基础: I帧 P帧 B帧
I帧介绍
I 帧通常是每个 GOP的第一个帧,在音视频编码中,I帧(Intra-coded frame)是一种关键帧,它是独立于其他帧的帧,不依赖于其他帧来进行解码。I帧存储了完整的图像信息,而不是基于之前或之后的帧进行压缩
I帧的特点:
关键帧:I帧是视频序列中的关键帧,用于重建整个画面。
独立性:I帧可以单独解码,不需要其他帧的信息。
存储空间较大:由于包含完整图像信息,I帧通常比其他帧(如P帧和B帧)更占用存储空间。
** 帧间预测无效**:因为I帧不依赖于其他帧进行压缩,所以帧间预测在I帧中并不起作用。
P帧介绍
在音视频编码中,P帧(Predictive-coded frame)是一种参考前向预测(Inter-frame prediction)技术生成的预测帧。P帧通常用于根据之前的图像帧进行运动估计和补偿,从而压缩视频数据。
P帧的特点:
- 基于前向预测:P帧通过运动估计和补偿来预测当前帧,使用参考帧中的运动信息和像素值进行编码。
- 相对于I帧和B帧的位置:P帧位于I帧和B帧之间,依赖于前面的I帧和/或P帧作为参考。
- 存储空间较小:由于采用运动补偿技术,P帧通常比I帧占用更少的存储空间。
- 非关键帧:P帧不是视频序列中的关键帧,必须依赖于其他帧(如I帧或之前的P帧)进行解码。
H.264及其他编码标准中的P帧:
- H.264(AVC):H.264是一种先进的视频编码标准,支持I帧、P帧和B帧。P帧在H.264中起着重要作用,通过运动矢量和残差信息实现视频的高效压缩。
- 其他编码标准:除了H.264,其他视频编码标准如MPEG-2、HEVC(H.265)等也支持P帧,这些编码标准都采用类似的前向预测技术。
因此,P帧并不是只有H.264才有的概念,在许多现代音视频编码标准中都存在,用于提高视频压缩效率和减小存储空间。通过利用前向预测,P帧可以有效地压缩视频数据,并在视频编码中发挥重要作用。
在音视频编码中,B帧(Bi-directional-coded frame)是一种双向预测(Inter-frame prediction)技术生成的预测帧,与P帧和I帧一起构成了视频序列的编码。B帧既参考前面的帧也参考后面的帧,以实现更高程度的压缩。
P帧介绍
B帧的特点:
- 双向预测:B帧通过参考前面和后面的帧来进行预测,可以利用两个方向的运动信息来更准确地预测当前帧。
- 存储空间最小:由于采用双向预测,B帧通常比P帧和I帧占用更少的存储空间,可以获得更高的压缩比。
- 非关键帧:B帧不是视频序列中的关键帧,需要依赖其他帧(如I帧、P帧或之后的B帧)进行解码。
H.264及其他编码标准中的B帧:
- H.264(AVC):H.264是一种支持I帧、P帧和B帧的视频编码标准,其中B帧在H.264中起着至关重要的作用。H.264通过B帧的双向预测能够进一步提高视频的编码效率。
- 其他编码标准:类似于P帧,B帧并不只有H.264才有,其他视频编码标准如MPEG-2、HEVC(H.265)等也支持B帧。这些编码标准都采用双向预测技术来增强视频压缩性能。
因此,B帧并非只有H.264才具有的概念,在许多现代音视频编码标准中,包括H.264之外的标准,都存在B帧的概念。通过双向预测技术,B帧能够更好地利用前后帧间的相关性,从而实现更高效的视频压缩和编码。
在视频编码中,I帧(Intra-coded frame)、P帧(Predictive-coded frame)和B帧(Bi-directional-coded frame)之间存在一定的关系,它们共同构成了视频序列的编码结构。
-
I帧:
- I帧是视频序列中的关键帧,独立编码,不依赖于其他帧。它包含完整的图像信息,用于重建整个画面。
-
P帧:
- P帧通过对前向运动进行预测来编码,通常参考前面的I帧或P帧。它能利用运动估计减少数据冗余,压缩视频帧。
-
B帧:
- B帧是通过双向运动预测生成的,同时参考前面和后面的帧。它可以更加高效地压缩视频内容,因为可以利用前后帧的信息进行预测。
相互关系:
- I帧与P帧:P帧通常可以参考之前的I帧或P帧来预测当前帧,从而减少数据冗余。因此,I帧和P帧之间存在着时间上的依赖关系。
- P帧与B帧:B帧通常会参考前面的帧(包括I帧、P帧或先前的B帧),同时也参考后面的帧。因此,P帧和B帧之间具有双向的时间依赖关系。
- I帧与B帧:虽然B帧通常需要参考I帧或P帧才能进行双向预测,但实际上I帧并不直接依赖于B帧,它们之间没有直接的关系。
h264的AVPacket的包为例怎么判断它什么帧
h264的 I帧 P帧 B帧如果看不懂可以参考-android MediaCodec 如何快速seek获取帧
// 判断帧类型函数
int get_frame_type(AVPacket *packet) {
if (packet->data[0] == 0x00 && packet->data[1] == 0x00 && packet->data[2] == 0x00 && packet->data[3] == 0x01) {
int nal_unit_type = packet->data[4] & 0x1F; // 获取 NAL 单元类型
if (nal_unit_type == 5) {
return 1; // I帧
} else if (nal_unit_type == 7 || nal_unit_type == 8) {
return 2; // SPS/PPS
} else if (nal_unit_type == 1) {
return 3; // P帧
} else if (nal_unit_type == 2) {
return 4; // B帧
}
}
return 0; // 未知帧类型
}