x264的幀間預測過程

因爲只看了p幀 的預測過程,所以先記錄p幀的,b幀的以後有緣再會。

if( h->sh.i_type == SLICE_TYPE_I )

{

   略;

}

 

else if( h->sh.i_type == SLICE_TYPE_P )

    {

        int b_skip = 0;

        int do_not_try_skip = 0;

 

        h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 0 );

 

        analysis.b_try_skip = 0;

        if( analysis.b_force_intra )

        {

            if( !h->param.analyse.b_psy )

            {

                x264_mb_analyse_init_qp( h, &analysis, X264_MAX( h->mb.i_qp - h->mb.ip_offset, h->param.rc.i_qp_min ) );

                goto intra_analysis;

            }

        }

        else

        {

         //對skip的mv做限制,如果超過邊界條件,則不嘗試skip模式;

            if ((h->mb.cache.pskip_mv[0] & 3) == 0 &&

                (h->mb.cache.pskip_mv[1] & 3) == 0)

            {

                if (h->mb.cache.pskip_mv[0] < h->mb.mv_min[0] || h->mb.cache.pskip_mv[0] > h->mb.mv_max[0])

                    do_not_try_skip = 1;

                if (h->mb.cache.pskip_mv[1] < h->mb.mv_min[1] || h->mb.cache.pskip_mv[1] > h->mb.mv_max[1])

                    do_not_try_skip = 1;

            }

            else

            {

                if (h->mb.cache.pskip_mv[0] < h->mb.mv_min[0] || h->mb.cache.pskip_mv[0] > h->mb.mv_max[0])

                    do_not_try_skip = 1;

                if (h->mb.cache.pskip_mv[1] < h->mb.mv_alert[0] * 4 || h->mb.cache.pskip_mv[1] > h->mb.mv_alert[1] * 4)

                    do_not_try_skip = 1;

            }

            /* Special fast-skip logic using information from mb_info. */

            if( h->fdec->mb_info && (h->fdec->mb_info[h->mb.i_mb_xy]&X264_MBINFO_CONSTANT) )

            {

                if(!SLICE_MBAFF && (h->fdec->i_frame - h->fref[0][0]->i_frame) == 1 && !h->sh.b_weighted_pred &&

                   h->fref[0][0]->effective_qp[h->mb.i_mb_xy] <= h->mb.i_qp && !do_not_try_skip)

                {

                    h->mb.i_partition = D_16x16;

                    /* Use the P-SKIP MV if we can... */

                    if( !M32(h->mb.cache.pskip_mv) )

                    {

                        b_skip = 1;

                        h->mb.i_type = P_SKIP;

                    }

                    /* Otherwise, just force a 16x16 block. */

                    else

                    {

                        h->mb.i_type = P_L0;

                        analysis.l0.me16x16.i_ref = 0;

                        M32( analysis.l0.me16x16.mv ) = 0;

                    }

                    goto skip_analysis;

                }

                /* Reset the information accordingly */

                else if( h->param.analyse.b_mb_info_update )

                    h->fdec->mb_info[h->mb.i_mb_xy] &= ~X264_MBINFO_CONSTANT;

            }

 

            int skip_invalid = h->i_thread_frames > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1];

            /* If the current macroblock is off the frame, just skip it. */

            if( HAVE_INTERLACED && !MB_INTERLACED && h->mb.i_mb_y * 16 >= h->param.i_height && !skip_invalid )

                b_skip = 1;

            /* Fast P_SKIP detection */

            else if( h->param.analyse.b_fast_pskip )

            {

                if( skip_invalid )

                    // FIXME don't need to check this if the reference frame is done

                    {}

                else if(h->param.analyse.i_subpel_refine >= 3)

                    analysis.b_try_skip = 1;

                else if((h->mb.i_mb_type_left[0] == P_SKIP ||

                         h->mb.i_mb_type_top == P_SKIP ||

                         h->mb.i_mb_type_topleft == P_SKIP ||

                         h->mb.i_mb_type_topright == P_SKIP) && !do_not_try_skip)

              b_skip =  x264_macroblock_probe_pskip( h );//判斷是否是skip塊(通過殘差係數確定);

            }

        }

 

        h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 1 );

 

        if (do_not_try_skip)

            b_skip = 0;

 

        //b_skip = 0;

 

        if( b_skip )

        {

            h->mb.i_type = P_SKIP;

            h->mb.i_partition = D_16x16;

            assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->i_thread_frames == 1 );

skip_analysis:

            /* Set up MVs for future predictors */

            for( int i = 0; i < h->mb.pic.i_fref[0]; i++ )

                M32( h->mb.mvr[0][i][h->mb.i_mb_xy] ) = 0;

        }

        else //不是skip塊

        {

            const unsigned int flags = h->param.analyse.inter;

            int i_type;

            int i_partition;

            int i_satd_inter, i_satd_intra;

 

            if (h->param.inter_no_subpart==1)

            {

                int adaptive_th = 30 * h->mb.i_qp - 500;

                h->mb.inter_no_subpart_indicator = (int)(h->fenc->var_per_mb[h->mb.i_mb_xy]) < adaptive_th ? 1 : 0;

            }

 

            x264_mb_analyse_load_costs( h, &analysis );

 

            x264_mb_analyse_inter_p16x16( h, &analysis );//先進行16x16的塊預測;

 

            if( h->mb.i_type == P_SKIP )

            {

                for( int i = 1; i < h->mb.pic.i_fref[0]; i++ )

                    M32( h->mb.mvr[0][i][h->mb.i_mb_xy] ) = 0;

                return;

            }

 

            if ((flags & X264_ANALYSE_PSUB16x16) && (h->mb.inter_no_subpart_indicator==0))//進行8x8塊劃分的預測編碼;

            {

                if( h->param.analyse.b_mixed_references )

                    x264_mb_analyse_inter_p8x8_mixed_ref( h, &analysis );

                else

                    x264_mb_analyse_inter_p8x8( h, &analysis );

            }

 

            /* Select best inter mode */

            i_type = P_L0;

            i_partition = D_16x16;

            i_cost = analysis.l0.me16x16.cost;

 

            if(( flags & X264_ANALYSE_PSUB16x16 ) && (analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost) && (h->mb.inter_no_subpart_indicator == 0))//如果8x8劃分的代價小於16x16的代價,則可以嘗試4x4,4x8,8x4的塊劃分;

            {

                i_type = P_8x8;

                i_partition = D_8x8;

                i_cost = analysis.l0.i_cost8x8;

 

                /* Do sub 8x8 */

                if(flags & X264_ANALYSE_PSUB8x8 )

                {

                    for( int i = 0; i < 4; i++ )

                    {

                        x264_mb_analyse_inter_p4x4( h, &analysis, i );

                        int i_thresh8x4 = analysis.l0.me4x4[i][1].cost_mv + analysis.l0.me4x4[i][2].cost_mv;

                        if(1) // !analysis.b_early_terminate || analysis.l0.i_cost4x4[i] < analysis.l0.me8x8[i].cost + i_thresh8x4 )

                        {

                            int i_cost8x8 = analysis.l0.i_cost4x4[i];

                            h->mb.i_sub_partition[i] = D_L0_4x4;

 

                            x264_mb_analyse_inter_p8x4( h, &analysis, i );

                            COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost8x4[i],

                                         h->mb.i_sub_partition[i], D_L0_8x4 );

 

                            x264_mb_analyse_inter_p4x8( h, &analysis, i );

                            COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost4x8[i],

                                         h->mb.i_sub_partition[i], D_L0_4x8 );

 

                            i_cost += i_cost8x8 - analysis.l0.me8x8[i].cost;

                        }

                        x264_mb_cache_mv_p8x8( h, &analysis, i );

                    }

                    analysis.l0.i_cost8x8 = i_cost;

                }

            }

 

            /* Now do 16x8/8x16 */

            //如果8x8塊劃分的代價小於16x16劃分的代價加上兩個8x8塊的mv代價(總的代價=塊的satd/sad+塊的cost_mv),則可以嘗試8x16和16x8的塊劃分;

            int i_thresh16x8 = analysis.l0.me8x8[1].cost_mv + analysis.l0.me8x8[2].cost_mv;

            if(( flags & X264_ANALYSE_PSUB16x16 ) && (!analysis.b_early_terminate ||

                analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost + i_thresh16x8) && (h->mb.inter_no_subpart_indicator == 0))

            {

             //i_cost_est16x8[1] 即爲估計的下邊16x8塊的代價,用於16x8塊劃分的快速跳出;

                int i_avg_mv_ref_cost = (analysis.l0.me8x8[2].cost_mv + analysis.l0.me8x8[2].i_ref_cost

                                      + analysis.l0.me8x8[3].cost_mv + analysis.l0.me8x8[3].i_ref_cost + 1) >> 1;

                analysis.i_cost_est16x8[1] = analysis.i_satd8x8[0][2] + analysis.i_satd8x8[0][3] + i_avg_mv_ref_cost;

 

                x264_mb_analyse_inter_p16x8( h, &analysis, i_cost );

                COPY3_IF_LT( i_cost, analysis.l0.i_cost16x8, i_type, P_L0, i_partition, D_16x8 );

                 //i_cost_est8x16[1] 即爲估計的右邊16x8塊的代價,用於8x16塊劃分的快速跳出;

                i_avg_mv_ref_cost = (analysis.l0.me8x8[1].cost_mv + analysis.l0.me8x8[1].i_ref_cost

                                  + analysis.l0.me8x8[3].cost_mv + analysis.l0.me8x8[3].i_ref_cost + 1) >> 1;

                analysis.i_cost_est8x16[1] = analysis.i_satd8x8[0][1] + analysis.i_satd8x8[0][3] + i_avg_mv_ref_cost;

 

                x264_mb_analyse_inter_p8x16( h, &analysis, i_cost );

                COPY3_IF_LT( i_cost, analysis.l0.i_cost8x16, i_type, P_L0, i_partition, D_8x16 );

            }

 

            h->mb.i_partition = i_partition;

 

            /* refine qpel */

            //FIXME mb_type costs?

          //對上述各種劃分中選出的最小代價對應的塊劃分進行運動矢量細化(先是1/2像素,再是1/4像素,需要運動補償);

            if( analysis.i_mbrd || !h->mb.i_subpel_refine )

            {

                /* refine later */

            }

            else if( i_partition == D_16x16 )//對16x16塊的mv進行分像素細化;

            {

                x264_me_refine_qpel( h, &analysis.l0.me16x16 );

                i_cost = analysis.l0.me16x16.cost;

            }

            else if( i_partition == D_16x8 )//對兩個16x8塊的mv進行分像素細化;

            {

                x264_mb_predict_mv( h, 0, 0, 4, analysis.l0.me16x8[0].mvp );

                x264_me_refine_qpel( h, &analysis.l0.me16x8[0] );

                x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 2, 0, analysis.l0.me16x8[0].mv );

                x264_mb_predict_mv( h, 0, 8, 4, analysis.l0.me16x8[1].mvp );

                x264_me_refine_qpel( h, &analysis.l0.me16x8[1] );

                x264_macroblock_cache_mv_ptr( h, 0, 2, 4, 2, 0, analysis.l0.me16x8[1].mv );

                i_cost = analysis.l0.me16x8[0].cost + analysis.l0.me16x8[1].cost;

            }

            else if( i_partition == D_8x16 )//對兩個8x16塊的mv進行分像素細化;

            {

                x264_mb_predict_mv( h, 0, 0, 2, analysis.l0.me8x16[0].mvp );

                x264_me_refine_qpel( h, &analysis.l0.me8x16[0] );

                x264_macroblock_cache_mv_ptr( h, 0, 0, 2, 4, 0, analysis.l0.me8x16[0].mv );

                x264_mb_predict_mv( h, 0, 4, 2, analysis.l0.me8x16[1].mvp );

                x264_me_refine_qpel( h, &analysis.l0.me8x16[1] );

                x264_macroblock_cache_mv_ptr( h, 2, 0, 2, 4, 0, analysis.l0.me8x16[1].mv );

                i_cost = analysis.l0.me8x16[0].cost + analysis.l0.me8x16[1].cost;

            }

            else if( i_partition == D_8x8 )//對四個8x8塊的mv進行分像素細化;

            {

                i_cost = 0;

                for( int i8x8 = 0; i8x8 < 4; i8x8++ )

                {

                    int x8 = i8x8&1;

                    int y8 = i8x8>>1;

                    x264_mb_predict_mv( h, 0, 4*i8x8, 2, analysis.l0.me8x8[i8x8].mvp );

                    switch( h->mb.i_sub_partition[i8x8] )

                    {

                        case D_L0_8x8:

                            x264_me_refine_qpel( h, &analysis.l0.me8x8[i8x8] );

                            i_cost += analysis.l0.me8x8[i8x8].cost;

                            break;

                        case D_L0_8x4:

                            x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][0] );

                            x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][1] );

                            i_cost += analysis.l0.me8x4[i8x8][0].cost +

                                      analysis.l0.me8x4[i8x8][1].cost;

                            break;

                        case D_L0_4x8:

                            x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][0] );

                            x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][1] );

                            i_cost += analysis.l0.me4x8[i8x8][0].cost +

                                      analysis.l0.me4x8[i8x8][1].cost;

                            break;

 

                        case D_L0_4x4:

                            x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][0] );

                            x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][1] );

                            x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][2] );

                            x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][3] );

                            i_cost += analysis.l0.me4x4[i8x8][0].cost +

                                      analysis.l0.me4x4[i8x8][1].cost +

                                      analysis.l0.me4x4[i8x8][2].cost +

                                      analysis.l0.me4x4[i8x8][3].cost;

                            break;

                        default:

                            x264_log( h, X264_LOG_ERROR, "internal error (!8x8 && !4x4)\n" );

                            break;

                    }

                    x264_macroblock_cache_mv_ptr( h, 2*x8, 2*y8, 2, 2, 0, analysis.l0.me8x8[i8x8].mv );

                }

            }

 

            if( h->mb.b_chroma_me )

            {

                if( CHROMA444 )

                {

                    x264_mb_analyse_intra( h, &analysis, i_cost );

                    x264_mb_analyse_intra_chroma( h, &analysis );

                }

                else

                {

                    x264_mb_analyse_intra_chroma( h, &analysis );

                    x264_mb_analyse_intra( h, &analysis, i_cost - analysis.i_satd_chroma );

                }

                analysis.i_satd_i16x16 += analysis.i_satd_chroma;

                analysis.i_satd_i8x8   += analysis.i_satd_chroma;

                analysis.i_satd_i4x4   += analysis.i_satd_chroma;

            }

            else //嘗試幀內模式;

                x264_mb_analyse_intra( h, &analysis, i_cost );

 

            i_satd_inter = i_cost;

            i_satd_intra = X264_MIN3( analysis.i_satd_i16x16,

                                      analysis.i_satd_i8x8,

                                      analysis.i_satd_i4x4 );

 

            if( analysis.i_mbrd )

            {

                x264_mb_analyse_p_rd( h, &analysis, X264_MIN(i_satd_inter, i_satd_intra) );

                i_type = P_L0;

                i_partition = D_16x16;

                i_cost = analysis.l0.i_rd16x16;

                COPY2_IF_LT( i_cost, analysis.l0.i_cost16x8, i_partition, D_16x8 );

                COPY2_IF_LT( i_cost, analysis.l0.i_cost8x16, i_partition, D_8x16 );

                COPY3_IF_LT( i_cost, analysis.l0.i_cost8x8, i_partition, D_8x8, i_type, P_8x8 );

                h->mb.i_type = i_type;

                h->mb.i_partition = i_partition;

                if( i_cost < COST_MAX )

                    x264_mb_analyse_transform_rd( h, &analysis, &i_satd_inter, &i_cost );

                x264_intra_rd( h, &analysis, i_satd_inter * 5/4 + 1 );

            }

         //比較幀間各種劃分的cost和幀內模式的cost是,選擇最優的劃分模式;

            COPY2_IF_LT( i_cost, analysis.i_satd_i16x16, i_type, I_16x16 );

            COPY2_IF_LT( i_cost, analysis.i_satd_i8x8, i_type, I_8x8 );

            COPY2_IF_LT( i_cost, analysis.i_satd_i4x4, i_type, I_4x4 );

            COPY2_IF_LT( i_cost, analysis.i_satd_pcm, i_type, I_PCM );

 

            h->mb.i_type = i_type;

 

            if( analysis.b_force_intra && !IS_INTRA(i_type) )

            {

                /* Intra masking: copy fdec to fenc and re-encode the block as intra in order to make it appear as if

                 * it was an inter block. */

                x264_analyse_update_cache( h, &analysis );

                x264_macroblock_encode( h );

                for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ )

                    h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, h->mb.pic.p_fdec[p], FDEC_STRIDE, 16 );

                if( !CHROMA444 )

                {

                    int height = 16 >> CHROMA_V_SHIFT;

                    h->mc.copy[PIXEL_8x8]  ( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE, height );

                    h->mc.copy[PIXEL_8x8]  ( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE, height );

                }

                x264_mb_analyse_init_qp( h, &analysis, X264_MAX( h->mb.i_qp - h->mb.ip_offset, h->param.rc.i_qp_min ) );

                goto intra_analysis;

            }

 

            if( analysis.i_mbrd >= 2 && h->mb.i_type != I_PCM )

            {

                if( IS_INTRA( h->mb.i_type ) )

                {

                    x264_intra_rd_refine( h, &analysis );

                }

                else if( i_partition == D_16x16 )

                {

                    x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, analysis.l0.me16x16.i_ref );

                    analysis.l0.me16x16.cost = i_cost;

                    x264_me_refine_qpel_rd( h, &analysis.l0.me16x16, analysis.i_lambda2, 0, 0 );

                }

                else if( i_partition == D_16x8 )

                {

                    h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =

                    h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;

                    x264_macroblock_cache_ref( h, 0, 0, 4, 2, 0, analysis.l0.me16x8[0].i_ref );

                    x264_macroblock_cache_ref( h, 0, 2, 4, 2, 0, analysis.l0.me16x8[1].i_ref );

                    x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[0], analysis.i_lambda2, 0, 0 );

                    x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[1], analysis.i_lambda2, 8, 0 );

                }

                else if( i_partition == D_8x16 )

                {

                    h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =

                    h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;

                    x264_macroblock_cache_ref( h, 0, 0, 2, 4, 0, analysis.l0.me8x16[0].i_ref );

                    x264_macroblock_cache_ref( h, 2, 0, 2, 4, 0, analysis.l0.me8x16[1].i_ref );

                    x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[0], analysis.i_lambda2, 0, 0 );

                    x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[1], analysis.i_lambda2, 4, 0 );

                }

                else if( i_partition == D_8x8 )

                {

                    x264_analyse_update_cache( h, &analysis );

                    for( int i8x8 = 0; i8x8 < 4; i8x8++ )

                    {

                        if( h->mb.i_sub_partition[i8x8] == D_L0_8x8 )

                        {

                            x264_me_refine_qpel_rd( h, &analysis.l0.me8x8[i8x8], analysis.i_lambda2, i8x8*4, 0 );

                        }

                        else if( h->mb.i_sub_partition[i8x8] == D_L0_8x4 )

                        {

                            x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8][0], analysis.i_lambda2, i8x8*4+0, 0 );

                            x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8][1], analysis.i_lambda2, i8x8*4+2, 0 );

                        }

                        else if( h->mb.i_sub_partition[i8x8] == D_L0_4x8 )

                        {

                            x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x8][0], analysis.i_lambda2, i8x8*4+0, 0 );

                            x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x8][1], analysis.i_lambda2, i8x8*4+1, 0 );

                        }

                        else if( h->mb.i_sub_partition[i8x8] == D_L0_4x4 )

                        {

                            x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][0], analysis.i_lambda2, i8x8*4+0, 0 );

                            x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][1], analysis.i_lambda2, i8x8*4+1, 0 );

                            x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][2], analysis.i_lambda2, i8x8*4+2, 0 );

                            x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][3], analysis.i_lambda2, i8x8*4+3, 0 );

                        }

                    }

                }

            }

        }

    }

else if( h->sh.i_type == SLICE_TYPE_B )

{

   略;

}

 

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