视频编解码(一):ffmpeg编码H.264帧类型判断

本文详细介绍了如何使用ffmpeg进行H.264视频编码时设置和判断I帧、P帧和B帧的过程。通过分析编码参数和输出码流,解释了帧类型的标志位和编码结构,纠正了关于I帧和IDR帧的常见误解。同时,提供了不同编码模式下帧序列的示例和参数设置的影响。
摘要由CSDN通过智能技术生成

本文主要讲述ffmpeg编码过程中是如何设置I帧,B帧及P帧的,以及如何通过代码判断帧类型。

之前看过很多网上的文章,讲述如何判断I帧,B帧,P帧,然而都是停留在H.264官方文档中的定义,如果不结合ffmpeg,就仿佛纸上谈兵,有点不切实际,而且很多文章将I帧与I Slice混为一谈,将I Slice当做I帧,这其实是错的。本文就结合ffmpeg讲解ffmpeg中是如何编码各种帧类型的,并纠正其他一些文章的说法。

先有如下定义:

I帧:帧内预测

P帧:前向预测

B帧:前后双向预测

IDR图像:第一个I帧(IDR图像一定是I图像,但I图像不一定是IDR图像),具有随机访问的能力,在IDR帧之后的所有帧都不能引用任何IDR帧之前的帧的内容

(1)IDR帧肯定为I帧
(2)I帧包含了SPS, PPS, I条带
(3)P帧包含P条带
(4)B帧包含B条带


FFMPEG中有以下与帧类型相关的参数:

AVCodecContext* pCodecCtx;
pCodecCtx->gop_size = 25;
pCodecCtx->max_b_frames = 3;

gop_size设置一个gop中有多少帧,默认情况下,一个gop的第一帧为I帧,因此也可以理解为gop_size为相邻两个I帧之间的帧数。max_b_frames设置相邻两个非B帧之间最多出现的B帧数量。

gop有两种类型:封闭式与开放式。封闭式中每个gop的第一帧都是IDR图像,开放式中第一个gop的第一帧是IDR,后续的gop的第一帧非IDR图像。

再看以下编码函数:

int ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);

第2个参数pFrame类型为AVFrame*,其有参数 pFrame->pict_type,用于设置编码的帧类型(这个值由用户设置,默认值为0,编码器不会自动设置该值,即不会自动设置为I帧,B帧的类型),pict_type的类型为:

enum AVPictureType {
    AV_PICTURE_TYPE_NONE = 0, ///< Undefined
    AV_PICTURE_TYPE_I,     ///< Intra
    AV_PICTURE_TYPE_P,     ///< Predicted
    AV_PICTURE_TYPE_B,     ///< Bi-dir predicted
    AV_PICTURE_TYPE_S,     ///< S(GMC)-VOP MPEG4
    AV_PICTURE_TYPE_SI,    ///< Switching Intra
    AV_PICTURE_TYPE_SP,    ///< Switching Predicted
    AV_PICTURE_TYPE_BI,    ///< BI type
};

根据编码输出码流 pkt.data[4] 的值来判断帧类型,其中(pkt.data[4] & 0x1F)即为以下表中的nal_uint_type:

也可以看这个:

这里将一个yuv视频文件编码为H264文件,设置参数如下:

pCodecCtx->max_b_frames = 3;
pFrame->pict_type = AV_PICTURE_TYPE_NONE;
pCodecCtx->gop_size = 25;

以上参数,打印输出如下,其中cNalu =pkt.data[4], type = (

要使用FFmpeg解码H.264视频,你可以使用以下步骤: 1. 首先,需要初始化FFmpeg库。你可以使用`av_register_all()`函数注册所有的FFmpeg组件。 2. 打开输入文件并创建AVFormatContext对象,表示输入的媒体文件。可以使用`avformat_open_input()`函数打开视频文件。 3. 检索流信息,使用`avformat_find_stream_info()`函数获取流信息。 4. 获取视频流的索引。可以使用`av_find_best_stream()`函数或者遍历`AVFormatContext`中的`streams`数组,判断其中的流类型是否为视频流(`AVMEDIA_TYPE_VIDEO`)来确定视频流的索引。 5. 查找并打开解码器。可以使用`avcodec_find_decoder()`函数根据视频流的编码ID查找解码器,然后使用`avcodec_open2()`函数打开解码器。 6. 分配AVPacket对象和AVFrame对象。AVPacket用于存储解码前的压缩数据,AVFrame用于存储解码后的像素数据。 7. 循环读取压缩数据并进行解码。使用`av_read_frame()`函数读取一压缩数据(AVPacket),然后使用`avcodec_send_packet()`函数将AVPacket发送到解码器进行解码,最后使用`avcodec_receive_frame()`函数接收解码后的数据(AVFrame)。 8. 处理解码后的数据。可以将解码后的数据用于渲染、处理等操作。 9. 释放资源。最后,记得释放分配的内存,包括AVPacket对象、AVFrame对象、解码器上下文和AVFormatContext对象等。 这只是一个基本的流程示例,你可以根据实际需求进行调整和扩展。请注意,H.264视频可能使用不同的配置参数和包装方式,你可能需要根据具体情况进行解码器的配置和设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值