I帧和IDR帧的区别
IDR帧属于I帧。解码器收到IDR frame 时,将所有的参考帧队列丢弃(用x264_reference_reset函数实现——在encoder.c文件中)。这点是所有I帧共有的特性,但是收到IDR帧时,解码器另外需要做的工作就是:把所有的PPS和SPS参数进行更新。由此可见,在编码器端,每发一个IDR,就相应地发一个 PPS&SPS_nal_unit
这是网上搜索到的一个答案,有一定参考价值吧。
先说明:所有的IDR帧都是I帧,但是并不是所有I帧都是IDR帧。就是说,IDR帧是I帧的子集。(我们程序中设定的是每250帧出现一个IDR帧)
我们用的程序是这样的:
/* ------------------- Setup frame context ----------------------------- */
/* 5: Init data dependant of frame type */
if( h->fenc->i_type == X264_TYPE_IDR )
{
/* reset ref pictures */
x264_reference_reset( h );
i_nal_type = NAL_SLICE_IDR;
i_nal_ref_idc = NAL_PRIORITY_HIGHEST;
i_slice_type = SLICE_TYPE_I;
}
else if( h->fenc->i_type == X264_TYPE_I )
{
i_nal_type = NAL_SLICE;
i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/
i_slice_type = SLICE_TYPE_I;
}
else if( h->fenc->i_type == X264_TYPE_P )
{
i_nal_type = NAL_SLICE;
i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/
i_slice_type = SLICE_TYPE_P;
}
else if( h->fenc->i_type == X264_TYPE_BREF )
{
i_nal_type = NAL_SLICE;
i_nal_ref_idc = NAL_PRIORITY_HIGH; /* maybe add MMCO to forget it? -> low */
i_slice_type = SLICE_TYPE_B;
}
else /* B frame */
{
i_nal_type = NAL_SLICE;
i_nal_ref_idc = NAL_PRIORITY_DISPOSABLE;
i_slice_type = SLICE_TYPE_B;
}
x264_reference_reset函数的定义如下:(其实,因为这个代码是通用的,所以应该是参考帧队列。但是,我们只用一个参考帧,“队列”并没有意义。)
static inline void x264_reference_reset( x264_t *h )
{
int i;
/* reset ref pictures */
for( i = 1; i < h->frames.i_max_dpb; i++ )
{
h->frames.reference[i]->i_poc = -1;
}
h->frames.reference[0]->i_poc = 0;
}
看来,好像是遇到IDR帧时才会将所有的参考帧队列丢弃(x264_reference_reset( h );)。其实,我们的程序默认只用一个参考帧,这个问题就不是十分有意义了。
多参考帧情况下。
举个例子:有如下帧序列:IPPPPIPPPP……(我们程序没有B帧,所以帧序列简单些,但道理是一样的)。按照3个参考帧编码。
因为“按照3个参考帧编码”,所以参考帧队列长度为3。
遇到绿色的I时,并不清空参考帧队列,把这个I帧加入参考帧队列(当然I编码时不用参考帧。)。再检测到红色的P帧时,用到的就是PPI三帧做参考了。
不怕自己罗嗦(好记性不如烂笔头),再强调一个:一个参考帧,就是参考当前帧的前面的那帧(因为没涉及到B帧,所以“前面的那帧”既是播放顺序的,也是编码顺序的)。多个参考帧是一个道理。(我以前一直误解为从前面的几帧中找到最合适的一个参考帧)
最后,“但是收到IDR帧时,解码器另外需要做的工作就是:把所有的PPS和SPS参数进行更新。由此可见,在编码器端,每发一个IDR,就相应地发一个 PPS&SPS_nal_unit”应该是对的吧。先这样认为:)