H.264中I幀和IDR幀
阿新 • • 發佈:2019-01-09
IDR幀的作用是立刻重新整理, 使錯誤不致傳播。從IDR幀開始, 重新算一個新的序列開始編碼。而I幀不具有隨機訪問的能力,這個功能是由IDR承擔。IDR幀會導致DPB (DecodedPictureBuffer 參考幀列表——這是關鍵所在)清空,而I不會。
在IDR幀之後的所有幀都不能引用任何IDR幀之前的幀的內容,而普通的I幀之後的B和P幀可以引用位於普通I幀之前的I幀。
從隨機存取的視訊流中,播放器永遠可以從一個IDR幀播放,因為在它之後沒有任何幀引用之前的幀。但是,不能在一個沒有IDR幀的視訊中從任意點開始播放,因為後面的幀總是會引用前面的幀。
x264的x264_encoder_encode()中有一段程式碼:
if( !IS_X264_TYPE_I( h->fenc->i_type ) )//su: 如果當前幀不是關鍵幀 { int valid_refs_left = 0; for( int i = 0; h->frames.reference[i]; i++ ) if( !h->frames.reference[i]->b_corrupt ) valid_refs_left++; /* No valid reference frames left: force an IDR. */ if( !valid_refs_left ) { h->fenc->b_keyframe = 1; h->fenc->i_type = X264_TYPE_IDR; } }
這段程式碼的意思是,從當前幀位置向前尋找參考幀,如果當前幀不會參考前面的幀,那麼就強制設成IDR幀。
if( h->fenc->i_type == X264_TYPE_IDR ) { /* reset ref pictures */ i_nal_type = NAL_SLICE_IDR; i_nal_ref_idc = NAL_PRIORITY_HIGHEST; h->sh.i_type = SLICE_TYPE_I;//su: Slice header型別 reference_reset( h ); h->frames.i_poc_last_open_gop = -1; }
如果是IDR幀,在reference_reset函式中,會清空參考幀列表:
static inline void reference_reset( x264_t *h )
{
while( h->frames.reference[0] )
x264_frame_push_unused( h, x264_frame_pop( h->frames.reference ) );
h->fdec->i_poc =
h->fenc->i_poc = 0;
}