I,P,B帧和PTS,DTS的关系--待完善

本文介绍了视频编码中的I帧、P帧和B帧的概念,并解释了DTS(解码时间戳)和PTS(播放时间戳)的区别。通过实例展示了不同帧之间的依赖关系,帮助读者更好地理解视频编码原理。

基本概念:

I frame :帧内编码帧 又称intra picture,I 帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。I帧可以看成是一个图像经过压缩后的产物。

P frame: 前向预测编码帧 又称predictive-frame,通过充分将低于图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧;

B frame: 双向预测内插编码帧 又称bi-directional interpolated prediction frame,既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧;

PTS:Presentation Time Stamp。PTS主要用于度量解码后的视频帧什么时候被显示出来

DTS:Decode Time Stamp。DTS主要是标识读入内存中的bit流在什么时候开始送入解码器中进行解码。

在没有B帧存在的情况下DTS的顺序和PTS的顺序应该是一样的。

IPB帧的不同:

I frame:自身可以通过视频解压算法解压成一张单独的完整的图片。

P frame:需要参考其前面的一个I frame 或者B frame来生成一张完整的图片。

B frame:则要参考其前一个I或者P帧及其后面的一个P帧来生成一张完整的图片。

两个I frame之间形成一个GOP,在x264中同时可以通过参数来设定bf的大小,即:I 和p或者两个P之间B的数量。

通过上述基本可以说明如果有B frame 存在的情况下一个GOP的最后一个frame一定是P.

DTS和PTS的不同:

DTS主要用于视频的解码,在解码阶段使用.PTS主要用于视频的同步和输出.在display的时候使用.在没有B frame的情况下.DTS和PTS的输出顺序是一样的.

例子:

下面给出一个GOP为15的例子,其解码的参照frame及其解码的顺序都在里面:

ibpdtspts

如上图:I frame 的解码不依赖于任何的其它的帧.而p frame的解码则依赖于其前面的I frame或者P frame.B frame的解码则依赖于其前的最近的一个I frame或者P frame 及其后的最近的一个P frame.


http://www.cnblogs.com/fpzeng/archive/2012/07/26/dts_pts.html

#include "decode_file.h" #include <QDebug> #include <QImage> Decode_file::Decode_file(QObject *parent) : QObject{parent} { // 初始化FFmpeg avformat_network_init(); decode_video(); } void Decode_file::decode_video() { // 打开文件 if(avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) { qDebug() << "无法打开文件"; return; } // 获取流信息 if(avformat_find_stream_info(pFormatCtx, NULL) < 0) { qDebug() << "无法获取流信息"; return; } // 查找视频流 for(unsigned int i=0; i<pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; origin_par = pFormatCtx->streams[i]->codecpar; break; } } if(video_stream_index == -1) { qDebug() << "未找到视频流"; return; } // 查找解码器(需确认AV_CODEC_ID_CAVS是否支持) codec = avcodec_find_decoder(origin_par->codec_id); if(!codec) { qDebug() << "找不到解码器"; return; } // 创建解码器上下文 codecCtx = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codecCtx, origin_par); // 打开解码器 if(avcodec_open2(codecCtx, codec, NULL) < 0) { qDebug() << "无法打开解码器"; return; } // 分配包内存 frame = av_frame_alloc(); packet = av_packet_alloc(); AVRational time_base = {1, 90000}; // 根据率动态计算 int64_t pts_counter = 0; // 解码循环 while (av_read_frame(pFormatCtx, packet) >= 0) { qDebug() << "video_stream_index:" << video_stream_index; if (packet->stream_index == video_stream_index) { // 重建时间戳 packet->pts = pts_counter; packet->dts = pts_counter; pts_counter += 3600; // 根据率调整 // 发送数据包 int ret = avcodec_send_packet(codecCtx, packet); if (ret < 0 && ret != AVERROR(EAGAIN)) { char err_msg[AV_ERROR_MAX_STRING_SIZE]; if (av_strerror(ret, err_msg, sizeof(err_msg)) < 0) { snprintf(err_msg, AV_ERROR_MAX_STRING_SIZE, "Unknown error %d", ret); } fprintf(stderr, "Error sending packet: %s\n", err_msg); continue; } // 接收 while (ret >= 0) { ret = avcodec_receive_frame(codecCtx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; else if (ret < 0) { char err_msg[AV_ERROR_MAX_STRING_SIZE]; if (av_strerror(ret, err_msg, sizeof(err_msg)) < 0) { snprintf(err_msg, AV_ERROR_MAX_STRING_SIZE, "Unknown error %d", ret); } fprintf(stderr, "Error sending packet: %s\n", err_msg); break; } // 处理(如转换为QImage) convert_frame_to_qimage(frame); av_frame_unref(frame); } } av_packet_unref(packet); } // 刷新解码器 avcodec_send_packet(codecCtx, NULL); while (avcodec_receive_frame(codecCtx, frame) >= 0) { convert_frame_to_qimage(frame); av_frame_unref(frame); } av_packet_free(&packet); av_frame_free(&frame); // 清理资源 av_packet_free(&packet); av_frame_free(&frame); avcodec_free_context(&codecCtx); avformat_close_input(&pFormatCtx); } 完善convert_frame_to_qimageconvert_frame_to_qimage函数
最新发布
03-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值