H.264中I幀和IDR幀

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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章