void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[9][2], int *i_mvc )
{
// int16_t (*mvr[2][X264_REF_MAX*2])[2];/* 16x16 mv for each possible ref */
// mb.mvr 是一个指针数组, 指向一块int16_t[2]的数组
// 数组的每一个item保存的是该索引对应的宏块的最佳预测运动向量
// 因此mb.mvr保存的是每个参考list中每个参考帧每个16x16宏块的最佳预测运动向量
int16_t (*mvr)[2] = h->mb.mvr[i_list][i_ref];
int i = 0;
// SET_MVP宏就是拷贝mvp到mvc数组,并将mvc索引增加1
#define SET_MVP(mvp) \
{ \
CP32( mvc[i], mvp ); \
i++; \
}
// 专为SLICE_MBAFF定义的宏
#define SET_IMVP(xy) \
if( xy >= 0 ) \
{ \
int shift = 1 + MB_INTERLACED - h->mb.field[xy]; \
int16_t *mvp = h->mb.mvr[i_list][i_ref<<1>>shift][xy]; \
mvc[i][0] = mvp[0]; \
mvc[i][1] = mvp[1]<<1>>shift; \
i++; \
}
/* b_direct */
if( h->sh.i_type == SLICE_TYPE_B
&& h->mb.cache.ref[i_list][x264_scan8[12]] == i_ref )
{
SET_MVP( h->mb.cache.mv[i_list][x264_scan8[12]] );
}
if( i_ref == 0 && h->frames.b_have_lowres )
{
int idx = i_list ? h->fref[1][0]->i_frame-h->fenc->i_frame-1
: h->fenc->i_frame-h->fref[0][0]->i_frame-1;
if( idx <= h->param.i_bframe )
{
int16_t (*lowres_mv)[2] = h->fenc->lowres_mvs[i_list][idx];
if( lowres_mv[0][0] != 0x7fff )
{
M32( mvc[i] ) = (M32( lowres_mv[h->mb.i_mb_xy] )*2)&0xfffeffff;
i++;
}
}
}
/* spatial predictors */
if( SLICE_MBAFF )
{
SET_IMVP( h->mb.i_mb_left_xy[0] );
SET_IMVP( h->mb.i_mb_top_xy );
SET_IMVP( h->mb.i_mb_topleft_xy );
SET_IMVP( h->mb.i_mb_topright_xy );
}
else
{
// 保存参考list 为i_list, 参考帧索引号为i_ref
// 对应宏块的左宏块的mv到mvc数组
SET_MVP( mvr[h->mb.i_mb_left_xy[0]] );
// 顶宏块
SET_MVP( mvr[h->mb.i_mb_top_xy] );
// 顶左宏块
SET_MVP( mvr[h->mb.i_mb_topleft_xy] );
// 顶右宏块
SET_MVP( mvr[h->mb.i_mb_topright_xy] );
}
#undef SET_IMVP
#undef SET_MVP
// 时间预测
/* temporal predictors */
if( h->fref[0][0]->i_ref[0] > 0 )
{
x264_frame_t *l0 = h->fref[0][0];
int field = h->mb.i_mb_y&1;
// calc poc of reconstruct frame
int curpoc = h->fdec->i_poc + h->fdec->i_delta_poc[field];
// calc poc of reference frame
int refpoc = h->fref[i_list][i_ref>>SLICE_MBAFF]->i_poc;
refpoc += l0->i_delta_poc[field^(i_ref&1)];
#define SET_TMVP( dx, dy ) \
{ \
int mb_index = h->mb.i_mb_xy + dx + dy*h->mb.i_mb_stride; \
int scale = (curpoc - refpoc) * l0->inv_ref_poc[MB_INTERLACED&field]; \
mvc[i][0] = (l0->mv16x16[mb_index][0]*scale + 128) >> 8; \
mvc[i][1] = (l0->mv16x16[mb_index][1]*scale + 128) >> 8; \
i++; \
}
SET_TMVP(0,0); // 当前宏块预测运动向量进行 scale
if( h->mb.i_mb_x < h->mb.i_mb_width-1 )
SET_TMVP(1,0); // 当前宏块右宏块预测向量进行 scale
if( h->mb.i_mb_y < h->mb.i_mb_height-1 )
SET_TMVP(0,1); // 当前宏块底宏块预测向量进行 scale
#undef SET_TMVP
}
*i_mvc = i; // 返回 候选的 mv 数目
}