帧内预测
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,
};