博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

I,P,B帧和PTS,DTS的关系

Posted on 2017-01-12 11:42  bw_0927  阅读(881)  评论(0编辑  收藏  举报

http://blog.csdn.net/dssxk/article/details/8269354

http://blog.csdn.net/sidumqz/article/details/53063854

http://www.cnblogs.com/my_life/articles/6742683.html

 

音视频编码卡的视频编码算法从JPEG 发展到MPEG-1、MPEG-2、MPEG-4和H.264。JPEG是一种著名的图像压缩方法,最初由Joint Photographic Experts Group在1986年提出并于1992年正式成为ISO标准(ISO/IEC 10918),主要应用于静态图像压缩,如果把它用在运动图像压缩的时候,就是我们通常所说的Motion-JPEG,由于JPEG相当于MPEG的帧内压缩,因而没有去除时域上的冗余,所以在保证一定图像质量的时候,压缩比不高,通常只有10-30倍,但是它有一个固定的优点,就是延迟在40ms,实时性很好,所以在某些特殊应用的场合仍然可以看到它的踪影。

MPEG运动图像编码技术标准是由Motion Picture Experts Group在1988年提出,并于1992年11月通过,1993年8月作为ISO/IEC 11172标准公布,这就是通常所说的MPEG-1。MPEG-1为了追求更高的压缩效率,更注重去除图像系列的时间冗余度。

因此引入了I帧(帧内编码)、P帧(前向预测编码)、B帧(双向预测编码)。P帧由前一个I帧或P帧图像来预测,而B帧由前后的两个P帧或一个I帧和一个P帧来预测,因而编解码和帧的显示顺序有所不同,如图1所示

I B B P B B P…B B I    I P B B P B B … I B B
1 2 3 4 5 6 7 …           1 4 2 3 7 5 6 …
(a) 显示顺序                 (b) 编解码顺序
          
        在此有两个问题需要说明:首先是插多少B 帧最合适?理论上说I、P之间插入的B帧越多,压缩比越高,但是编解码器所需的帧存储器(缓存)也越大,因此实际应用中一般最多两个。其次,B帧的引入会增加编解码端的延迟,如果追求网络监视的时延,最好是不使用B帧
        MPEG-1标准的一个成功应用范例是小型激光视盘(VCD)。由于它的压缩比相对于M- JPEG大为提高,因而在数字监控系统中得到广泛的应用。

但是并不是最适合数字监控系统的应用,主要表现在码率固定,代价是引起图像质量的抖动,而数字监控系统最需要的不是恒定码率,而是恒定质量。同时MPEG-1本身的技术限制,其压缩比也没有达到用户满意的程度。而2000年提出的MPEG-4不仅是一个非常开放的标准,而且增加了许多新的工具,以达到降低某些应用或图像场景中要求的图像质量所需的比特率。值得注意的是虽然大部分用来降低比特率的工具是为非实时应用开发的,无法使用到数字监控系统中,但是相对MPEG-1,由于使用半像素和1/4像素图像匹配、帧内预测、高级运动矢量预测等新的技术,因而采用MPEG-4的压缩标准之后,在PAL CIF 25fps情况下,大部分情况下码率在300k-500k的MPEG-4压缩图像质量超过1.25Mbit的MPEG-1图像,因而在数字监控系统中得到最广泛和成功的应用。

 

 

 

基本概念:

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.360doc.com/content/13/1227/10/1317564_340465349.shtml

4.DTS, PTS
对于一个ES来说,比如视频,他有许多I,P,B帧。由于B帧是前向后向参考,因此要对B帧作decode的话,就必须先decode该B帧后面的P,或者I帧。于是,decode的时间与帧的真正的present的时间就不一致了,按照DTS一次对各个帧进行decode,然后再按照PTS对各个帧进行展现。
有时候PES包头里面也会有DTS,PTS,对于PTS来说,他代表了这个PES包的payload里面的第一个完整的audio access unit或者video access unit的PTS时间(并不是每个audio/video access unit都带有PTS/DTS,因此,你可以在PES里面指定一个,作为开始)。
PES包头的DTS也是这个原理,只不过注意的是:对于video来说他的DTS和PTS是可以不一样的,因为B帧的存在使其顺序可以倒置。而对于audio来说,audio没有双向的预测,他的DTS和PTS可以看成是一个顺序的,因此可一直采用一个,即可只采用PTS。

 

 

(1)scr(system_clock_reference)系统参考时钟,存在于ts流和program流中,用于多节目流间的同步;

 
(2)pcr(program-_clock_reference)节目参考时钟,存在于ts流里,用于确定同一节目的解码时序;
 
 
Generally the PTS and DTS will only differ when the stream we are playing has B frames in it.
 
========================================
http://blog.chinaunix.net/uid-20235103-id-1970911.html
 

首先,MPEG-1压缩的基本思想:帧内压缩和帧间压缩。 
其次,时间相关性的统计分析:统计的结果表明,在间隔1~2帧的图像中,各像素只有10%以下的点,其亮度差值变化超过2%,而色度差值的变化只有1%以下。

采用的压缩方法: 分组:把几帧图像分为一组(GOP),为防止运动变化,帧数不宜取多。 
1.定义帧:将每组内各帧图像定义为三种类型,即I帧、B帧和P帧; 
2.预测帧:以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧; 
3.数据传输:最后将I帧数据与预测的差值信息进行存储和传输。

I帧:帧内编码帧 
I帧特点: 
1.它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输; 
2.解码时仅用I帧的数据就可重构完整图像; 
3.I帧描述了图像背景和运动主体的详情; 
4.I帧不需要参考其他画面而生成; 
5.I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量); 
6.I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧
7.I帧不需要考虑运动矢量; 
8.I帧所占数据的信息量比较大。

P帧:前向预测编码帧。 
P帧的预测与重构:P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。 
P帧特点: 
1.P帧是I帧后面相隔1~2帧的编码帧; 
2.P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差); 
3.解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像; 
4.P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧
5.P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧; 
6.由于P帧是参考帧,它可能造成解码错误的扩散; 
7.由于是差值传送,P帧的压缩比较高。

B帧:双向预测内插编码帧。 
B帧的预测与重构 
B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧。 
B帧特点 
1.B帧是由前面的I或P帧和后面的P帧来进行预测的; 
2.B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量; 
3.B帧是双向预测编码帧; 
4.B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确; 
5.B帧不是参考帧,不会造成解码错误的扩散。

注:I、B、P各帧是根据压缩算法的需要,是人为定义的,它们都是实实在在的物理帧,至于图像中的哪一帧是I帧,是随机的,一但确定了I帧,以后的各帧就严格按规定顺序排列

 
 
===================
http://blog.csdn.net/sidumqz/article/details/53063854
 
对于一个电影,帧是这样来显示的:I B B P。现在我们需要在显示B帧之前知道P帧中的信息。因此,帧可能会按照这样的方式来存储:IPBB。这就是为什么我们会有一个解码时间戳和一个显示时间戳的原因。解码时间戳告诉我们什么时候需要解码,显示时间戳告诉我们什么时候需要显示
 

DTS和PTS

音频和视频流都有一些关于以多快速度和什么时间来播放它们的信息在里面。音频流有采样,视频流有每秒的帧率。然而,如果我们只是简单的通过数帧和乘以帧率的方式来同步视频,那么就很有可能会失去同步

于是作为一种补充,在流中的包有种叫做DTS(解码时间戳)和PTS(显示时间戳)的机制。为了这两个参数,你需要了解电影存放的方式。

像MPEG等格式,使用被叫做B帧(B表示双向bidrectional)的方式。另外两种帧被叫做I帧和P帧(I表示关键帧,P表示预测帧)。I帧包含了某个特定的完整图像。P帧依赖于前面的I帧和P帧并且使用比较或者差分的方式来编码。

B帧与P帧有点类似,但是它是依赖于前面和后面的帧的信息的。这也就解释了为什么我们可能在调用avcodec_decode_video以后会得不到一帧图像

 

ffmpeg中的时间单位

AV_TIME_BASE

ffmpeg中的内部计时单位(时间基),ffmepg中的所有时间都是于它为一个单位,比如AVStream中的duration,即这个流的长度为duration个AV_TIME_BASE。

AV_TIME_BASE定义为:

#define         AV_TIME_BASE   1000000

AV_TIME_BASE_Q

ffmpeg内部时间基的分数表示,实际上它是AV_TIME_BASE的倒数。从它的定义能很清楚的看到这点:

#define         AV_TIME_BASE_Q   (AVRational){1, AV_TIME_BASE}

 

AVRatioal的定义如下:

typedef struct AVRational{
int num; //numerator
int den; //denominator
} AVRational;

 

ffmpeg提供了一个把AVRatioal结构转换成double的函数:

static inline double av_q2d(AVRational a){
/**
* Convert rational to double.
* @param a rational to convert
**/
    return a.num / (double) a.den;
}

 

现在可以根据pts来计算一桢在整个视频中的时间位置:

timestamp(秒) = pts * av_q2d(st->time_base)

计算视频长度的方法:

time(秒) = st->duration * av_q2d(st->time_base)

这里的st是一个AVStream对象指针。

时间基转换公式

  1. timestamp(ffmpeg内部时间戳) = AV_TIME_BASE * time(秒)
  2. time(秒) = AV_TIME_BASE_Q * timestamp(ffmpeg内部时间戳)

 

所以当需要把视频跳转到N秒的时候可以使用下面的方法:

int64_t timestamp = N * AV_TIME_BASE; 

av_seek_frame(fmtctx, index_of_video, timestamp, AVSEEK_FLAG_BACKWARD);

 

ffmpeg同样为我们提供了不同时间基之间的转换函数:

int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)

这个函数的作用是计算a * bq / cq,来把时间戳从一个时基调整到另外一个时基。在进行时基转换的时候,我们应该首选这个函数,因为它可以避免溢出的情况发生。