• 帧内预测1


    帧内预测

    static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_inter )

    {

    ount++;*/

     

    通过一个标志位来决定帧内或帧间

    const unsigned int flags = h->sh.i_type == SLICE_TYPE_I ? h->param.analyse.intra : h->param.analyse.inter;

     

    这里跟我想的很不一样,我分析的是第一个IDR帧,我想这个时候p_dst要么应该是空的要么初值应该和p_src是相同的,但是打印出来并不是这么回事。p_src没有说的就是第一个像素块的地址

    pixel *p_src = h->mb.pic.p_fenc[0];

    pixel *p_dst = h->mb.pic.p_fdec[0];

     

        static const int8_t intra_analysis_shortcut[2][2][2][5] =

        {

            {{{I_PRED_4x4_HU, -1, -1, -1, -1},

              {I_PRED_4x4_DDL, I_PRED_4x4_VL, -1, -1, -1}},

             {{I_PRED_4x4_DDR, I_PRED_4x4_HD, I_PRED_4x4_HU, -1, -1},

              {I_PRED_4x4_DDL, I_PRED_4x4_DDR, I_PRED_4x4_VR, I_PRED_4x4_VL, -1}}},

            {{{I_PRED_4x4_HU, -1, -1, -1, -1},

              {-1, -1, -1, -1, -1}},

             {{I_PRED_4x4_DDR, I_PRED_4x4_HD, I_PRED_4x4_HU, -1, -1},

              {I_PRED_4x4_DDR, I_PRED_4x4_VR, -1, -1, -1}}},

        };

     

    //下面有对这个函数的详细分析,大致说就是通过传递过来的h->mb.i_neighbour_intra这个参数可以决定当前的帧块附近(上,左,上左)是否有宏块存在

    const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra );

     

    /* Not heavily tuned */  没看懂这两行

    static const uint8_t i16x16_thresh_lut[11] = { 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 };

    int i16x16_thresh = a->b_fast_intra ? (i16x16_thresh_lut[h->mb.i_subpel_refine]*i_satd_inter)>>1 : COST_MAX;

     

     

    这个接前面那个通过上面的predict_16x16_mode_available函数可以定位到使用哪几个预测函数,周围宏块数的不同可以使用的个数也不同

     

    由于分析的是IDR帧  这个if先没有分析 直接跳到else  后面有详细解释为什么这里不会执行到,就是因为predict_16x16_mode_available函数

    if( !h->mb.b_lossless && predict_mode[3] >= 0 )

        {

            h->pixf.intra_mbcmp_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir );

            a->i_satd_i16x16_dir[0] += lambda * bs_size_ue(0);

            a->i_satd_i16x16_dir[1] += lambda * bs_size_ue(1);

            a->i_satd_i16x16_dir[2] += lambda * bs_size_ue(2);

            COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[0], a->i_predict16x16, 0 );

            COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[1], a->i_predict16x16, 1 );

            COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[2], a->i_predict16x16, 2 );

     

            /* Plane is expensive, so don't check it unless one of the previous modes was useful. */

            if( a->i_satd_i16x16 <= i16x16_thresh )

            {

                h->predict_16x16[I_PRED_16x16_P]( p_dst );

                a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE );

                a->i_satd_i16x16_dir[I_PRED_16x16_P] += lambda * bs_size_ue(3);

                COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[I_PRED_16x16_P], a->i_predict16x16, 3 );

            }

    }

    直接跳到这里 如果是第一个IDR帧的话,预测方式只有一种

    else

        {

            for( ; *predict_mode >= 0; predict_mode++ )

            {

                int i_satd;

                int i_mode = *predict_mode;

     

               

                if( h->mb.b_lossless )

                    x264_predict_lossless_16x16( h, 0, i_mode );

                else

                    h->predict_16x16[i_mode]( p_dst );          

     

                i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) +

                         lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );

                COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode );

                a->i_satd_i16x16_dir[i_mode] = i_satd;

            }

        }

     

     

    }

     

    static ALWAYS_INLINE const int8_t *predict_16x16_mode_available( int i_neighbour )

    {

    这里首先通过传递过来的i_neighbour 变量和本来定义好的结构体macroblock_position_e做与操作,然后可以得到一个标记idx,这个idx可以标记有多少个宏块,然后再次定位

    int idx = i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT);

    其实主要是为了得到这个idx ,通过它可以直接定位可以用多少种预测方法,但是书上说就四种对于16x16,但是这里冒出来五种,貌似对于IDR的第一个宏块有特殊处理,就是那个I_PRED_16x16_DC_128

        idx = (idx == (MB_TOP|MB_LEFT|MB_TOPLEFT)) ? 4 : idx & (MB_TOP|MB_LEFT);

    得到idx然后通过可以的预测模式就可以得到能使用多少中预测方法了。

        return i16x16_mode_available[idx];

    }

    举个例子 IDR的第一个(第一行第一列)宏块传过来的是i_neighbour传过来的是0,通过两次操作最后得到是0,所以他的预测模式就是 下面二位数组的第一个{I_PRED_16x16_DC_128, -1, -1, -1, -1},里面只有一种可用的预测模式。

    第二行的第一个宏块传递过来的i_neighbour是6,通过两次相与操作后,idx的值为1,所以可用的预测模式就是{I_PRED_16x16_DC_LEFT, I_PRED_16x16_H, -1, -1, -1}

    第二行的第二个到倒数第二个所含的宏块i_neighbour都是15可以以此类推。

    第二行的最后一个i_neighbour的值为11

    比较特殊的就这几个,由于IDR就是I帧,所以可以推测所有的宏块i_neighbour类型

     

     

    static const int8_t i16x16_mode_available[5][5] =

    {

        {I_PRED_16x16_DC_128, -1, -1, -1, -1},

        {I_PRED_16x16_DC_LEFT, I_PRED_16x16_H, -1, -1, -1},

        {I_PRED_16x16_DC_TOP, I_PRED_16x16_V, -1, -1, -1},

        {I_PRED_16x16_V, I_PRED_16x16_H, I_PRED_16x16_DC, -1, -1},

        {I_PRED_16x16_V, I_PRED_16x16_H, I_PRED_16x16_DC, I_PRED_16x16_P, -1},

    };

     

    enum macroblock_position_e

    {

        MB_LEFT     = 0x01,

        MB_TOP      = 0x02,

        MB_TOPRIGHT = 0x04,

        MB_TOPLEFT  = 0x08,

     

        MB_PRIVATE  = 0x10,

     

        ALL_NEIGHBORS = 0xf,

    };

     

     

     

  • 相关阅读:
    C#面向对象的基本原则
    EXTJS学习笔记:类似于Window的登录窗体
    c# 类似于QQ表情弹出框功能的二种实现方法
    EXTJS学习笔记:grid之分组实现groupingview
    RibbonBar屏蔽右键
    webservice安全性浅谈
    js生成二维码以及插入图片
    c++之const解惑
    最短路径连接表形式
    深入理解c++之动态内存和指针
  • 原文地址:https://www.cnblogs.com/hatreds/p/2446168.html
Copyright © 2020-2023  润新知