homerHEVC代码阅读(31)——帧间预测之AMVP模式(常规帧间预测)

来源:互联网 发布:plsql怎么导出表数据 编辑:程序博客网 时间:2024/05/21 06:46

一、帧间预测的理论知识请看 HEVC/H.265理论知识(4)——帧间预测   HEVC/H.265理论知识(10)——率失真优化

二、AMVP模式也就是普通帧间预测,这种模式的大概思路:

1、利用AMVP技术,选出候选MV,然后选取率失真最优的一个作为预测MV

2、利用预测MV确定运动估计搜索的起点

3、进行运动估计(为了提高准确性,还会进行运动补偿),得到MV


三、普通帧间预测(AMVP技术)的主函数hmr_cu_motion_estimation(过程和上面说的大致相同):

int hmr_cu_motion_estimation(henc_thread_t* et, ctu_info_t* ctu, int gcnt, int depth, int part_position, PartSize part_size_type, uint threshold, unsigned int action){double distortion = 0.;int i;uint32_t sad = 0, mv_total_cost = 0;picture_t *currpict = &et->enc_engine->current_pict;slice_t *currslice = &currpict->slice;ctu_info_t *ctu_rd = et->ctu_rd;int orig_buff_stride, reference_buff_stride;int orig_buff_stride_chroma, reference_buff_stride_chroma;/* 原始数据的三个分量的buffer和参考数据的三个分量的buffer */int16_t  *orig_buff, *orig_buff_u, *orig_buff_v;int16_t  *reference_buff_cu_position, *reference_buff_cu_position_u, *reference_buff_cu_position_v;/* 参考窗口 */wnd_t *reference_wnd = NULL;//, *resi_wnd = NULL;int curr_part_size, curr_part_size_shift;int curr_part_size_chroma, curr_part_size_shift_chroma;int curr_part_x, curr_part_y, curr_part_global_x, curr_part_global_y;int curr_part_x_chroma, curr_part_y_chroma, curr_part_global_x_chroma, curr_part_global_y_chroma;int curr_depth = depth;/* 父亲partition信息和当前partition的信息 */cu_partition_info_t *parent_part_info;cu_partition_info_t *curr_cu_info;int num_partitions, npart, part_incr = 1;if (ctu->ctu_number == 2){int iiiii = 0;}curr_cu_info = &ctu->partition_list[et->partition_depth_start[curr_depth]] + part_position;if (part_size_type == SIZE_2Nx2N){parent_part_info = curr_cu_info->parent;num_partitions = 1;}else if (part_size_type == SIZE_NxN){parent_part_info = curr_cu_info->parent;curr_cu_info = parent_part_info->children[0];num_partitions = 4;part_incr = 1;}sad = 0;/* 遍历所有partition */for (npart = 0; npart < num_partitions; npart += part_incr){int ref_list = 0;/* 预设最优代价 */uint32_t best_cost[2] = { MAX_COST, MAX_COST };/* MV的最优代价 */uint32_t mv_best_cost[2] = { 0, 0 };/* 双向预测的最优代价 */uint32_t best_cost_bi = MAX_COST;/* 双向预测MV的代价 */uint32_t mv_best_cost_bi;/* 双向预测的两个MV */motion_vector_t mv_bi[2];/* 双向预测的两个最优的MV候选者 */motion_vector_t mv_best_cand_bi[2];/* 双向预测的MVP */motion_vector_t mvp_bi[2];/* 参考帧的索引*/int ref_index_bi[2];/* MVP的索引*/int mvp_idx[2];/* 最优的候选mv的索引 */int best_cand_idx[2];curr_depth = curr_cu_info->depth;curr_part_x = curr_cu_info->x_position;curr_part_y = curr_cu_info->y_position;curr_part_global_x = ctu->x[Y_COMP] + curr_part_x;curr_part_global_y = ctu->y[Y_COMP] + curr_part_y;curr_part_size = curr_cu_info->size;curr_part_size_shift = et->max_cu_size_shift - curr_depth;curr_part_x_chroma = curr_cu_info->x_position_chroma;curr_part_y_chroma = curr_cu_info->y_position_chroma;curr_part_global_x_chroma = ctu->x[CHR_COMP] + curr_part_x_chroma;curr_part_global_y_chroma = ctu->y[CHR_COMP] + curr_part_y_chroma;curr_part_size_chroma = curr_cu_info->size_chroma;curr_part_size_shift_chroma = et->max_cu_size_shift - curr_depth - 1;//420orig_buff_stride = WND_STRIDE_2D(et->curr_mbs_wnd, Y_COMP);orig_buff = WND_POSITION_2D(int16_t *, et->curr_mbs_wnd, Y_COMP, curr_part_x, curr_part_y, gcnt, et->ctu_width);orig_buff_stride_chroma = WND_STRIDE_2D(et->curr_mbs_wnd, CHR_COMP);orig_buff_u = WND_POSITION_2D(int16_t *, et->curr_mbs_wnd, U_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);orig_buff_v = WND_POSITION_2D(int16_t *, et->curr_mbs_wnd, V_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);if (et->enc_engine->num_encoded_frames == 2 && ctu->ctu_number == 5 && curr_cu_info->abs_index >= 144 && curr_cu_info->depth == 2)// && curr_cu_info->depth==3 && npart==2)// && curr_cu_info->abs_index>=32)// && curr_partition_info->abs_index>=192)// && curr_depth==2){int iiiiii = 0;}//unidirectional prediction/* 常规处理,选择候选AMVP,运动估计等 */for (ref_list = 0; ref_list <= (int)REF_PIC_LIST_1; ref_list++){int ref_idx;for (ref_idx = 0; ref_idx < currslice->num_ref_idx[ref_list]; ref_idx++){mv_candiate_list_tamvp_candidate_list;int mvp_candidate_idx;uint32_t cost, mv_cost;uint32_t cost_temp_l0[32];motion_vector_t mv_temp_l0[32], mv, subpix_mv;reference_wnd = &currslice->ref_pic_list[ref_list][ref_idx]->img;//[0] up to now we only use one referencereference_buff_stride = WND_STRIDE_2D(*reference_wnd, Y_COMP);reference_buff_cu_position = WND_POSITION_2D(int16_t *, *reference_wnd, Y_COMP, curr_part_global_x, curr_part_global_y, gcnt, et->ctu_width);reference_buff_stride_chroma = WND_STRIDE_2D(*reference_wnd, CHR_COMP);reference_buff_cu_position_u = WND_POSITION_2D(int16_t *, *reference_wnd, U_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);reference_buff_cu_position_v = WND_POSITION_2D(int16_t *, *reference_wnd, V_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);/* 获取AMVP */get_amvp_candidates(et, currslice, ctu, curr_cu_info, &amvp_candidate_list, ref_list, ref_idx, part_size_type);//get candidates for advanced motion vector prediction from the neigbour CUs/* 如果两个参考列表的mv都相同,那么需要选择 */if (ref_list == REF_PIC_LIST_1 && currslice->list1_idx_to_list0_idx[ref_idx] >= 0)//equal reference frames in both lists{mv = mv_temp_l0[currslice->list1_idx_to_list0_idx[ref_idx]];cost = cost_temp_l0[currslice->list1_idx_to_list0_idx[ref_idx]];mv_cost = select_mv_candidate(et, curr_cu_info, &amvp_candidate_list, &mv, &mvp_candidate_idx);//&curr_cu_info->best_candidate_idx[ref_list]);}/* 如果不是,那么进行运动估计,最后还是会选择MV */else{#ifdef COMPUTE_AS_HMcost = hmr_motion_estimation_HM(et, ctu, curr_cu_info, orig_buff, orig_buff_stride, reference_buff_cu_position, reference_buff_stride, curr_part_global_x, curr_part_global_y, 0, 0, curr_part_size, curr_part_size_shift, 64, 64, et->pict_width[Y_COMP], et->pict_height[Y_COMP], &mv);mv_cost = select_mv_candidate(et, curr_cu_info, &amvp_candidate_list, &mv, &mvp_candidate_idx);//&curr_cu_info->best_candidate_idx[ref_list]);//curr_cu_info->best_dif_mv[ref_list].hor_vector = mv.hor_vector-et->amvp_candidates[ref_list].mv_candidates[curr_cu_info->best_candidate_idx[ref_list]].mv.hor_vector;//curr_cu_info->best_dif_mv[ref_list].ver_vector = mv.ver_vector-et->amvp_candidates[ref_list].mv_candidates[curr_cu_info->best_candidate_idx[ref_list]].mv.ver_vector;if (ref_list == REF_PIC_LIST_0){mv_temp_l0[ref_idx] = mv;cost_temp_l0[ref_idx] = cost;}}#elseet->mv_search_candidates.num_mv_candidates = 0;//get_mv_search_candidates(et, currslice, ctu, curr_cu_info, REF_PIC_LIST_0, ref_idx, part_size_type);//get candidates for motion search from the neigbour CUsfor (i = 0; i < amvp_candidate_list.num_mv_candidates; i++)//for(i=0;i<et->amvp_candidates[ref_list].num_mv_candidates;i++){motion_vector_t mv = amvp_candidate_list.mv_candidates[i].mv; //et->amvp_candidates[ref_list].mv_candidates[i].mv;if (mv.hor_vector != 0 && mv.ver_vector != 0){et->mv_search_candidates.mv_candidates[et->mv_search_candidates.num_mv_candidates++].mv = mv;}}if (et->enc_engine->num_encoded_frames == 2 && ctu->ctu_number == 5 && curr_cu_info->abs_index == 128 && curr_cu_info->depth == 1)printf("\r\n ref_list:%d, parent_mv(%d, %d) \r\n", ref_list, curr_cu_info->parent->inter_mv[ref_list].hor_vector, curr_cu_info->parent->inter_mv[ref_list].ver_vector);if (curr_cu_info->parent && (curr_cu_info->parent->inter_mv[ref_list].hor_vector != 0 && curr_cu_info->parent->inter_mv[ref_list].ver_vector != 0)){et->mv_search_candidates.mv_candidates[et->mv_search_candidates.num_mv_candidates++].mv = curr_cu_info->parent->inter_mv[ref_list];}if ((action & (MOTION_HALF_PEL_MASK | MOTION_QUARTER_PEL_MASK) && !(action & (MOTION_PEL_MASK)))){mv = curr_cu_info->inter_mv[ref_list];subpix_mv = curr_cu_info->subpix_mv[ref_list];}/* 进行运动估计,为了选择最优的一个MV  */cost = hmr_motion_estimation(et, ctu, curr_cu_info, orig_buff, orig_buff_stride, reference_buff_cu_position, reference_buff_stride, curr_part_global_x, curr_part_global_y, 0, 0, curr_part_size, curr_part_size_shift, MOTION_SEARCH_RANGE_X, MOTION_SEARCH_RANGE_Y, et->pict_width[Y_COMP], et->pict_height[Y_COMP], &mv, &subpix_mv, &amvp_candidate_list, threshold, action);//|MOTION_HALF_PEL_MASK|MOTION_QUARTER_PEL_MASK);/* 快速选择MV */mv_cost = select_mv_candidate_fast(et, curr_cu_info, &amvp_candidate_list, &mv, &mvp_candidate_idx);curr_cu_info->subpix_mv[REF_PIC_LIST_0] = subpix_mv;if (ref_list == REF_PIC_LIST_0){mv_temp_l0[ref_idx] = mv;cost_temp_l0[ref_idx] = cost;}}#endif#ifdef COMPUTE_AS_HMif (cost < best_cost[ref_list])#else/* 更新最优的代价和模式 */if (cost + mv_cost < best_cost[ref_list] + mv_best_cost[ref_list])#endif{best_cost[ref_list] = cost;mv_best_cost[ref_list] = mv_cost;//set mvs and ref_idxcurr_cu_info->inter_mv[ref_list] = mv;curr_cu_info->inter_ref_index[ref_list] = ref_idx;curr_cu_info->inter_mode = (1 << ref_list);//vector predictionet->amvp_candidates[ref_list] = amvp_candidate_list;curr_cu_info->best_candidate_idx[ref_list] = mvp_candidate_idx;curr_cu_info->best_dif_mv[ref_list].hor_vector = mv.hor_vector - et->amvp_candidates[ref_list].mv_candidates[mvp_candidate_idx].mv.hor_vector;curr_cu_info->best_dif_mv[ref_list].ver_vector = mv.ver_vector - et->amvp_candidates[ref_list].mv_candidates[mvp_candidate_idx].mv.ver_vector;}}//for ( ref_idx = 0; ref_idx < currslice->num_ref_idx[ref_list]; ref_idx++)/*对于参考类列表中的每一个参考帧 */}//for (ref_list = 0; ref_list <= (int)REF_PIC_LIST_1; ref_list++ ) /* 至此两个列表都遍历完毕了 *///bi-prediction motion estimation/* 如果是B片,并且CU的大小大于等于8 ,会进行一些比较特别的处理(再次运动估计等等)*/if (currslice->slice_type == B_SLICE && curr_cu_info->size >= 8){int ref_idx = 0, num_ref_idx;uint cost, mv_cost;mv_bi[REF_PIC_LIST_0] = curr_cu_info->inter_mv[REF_PIC_LIST_0];mv_bi[REF_PIC_LIST_1] = curr_cu_info->inter_mv[REF_PIC_LIST_1];ref_index_bi[REF_PIC_LIST_0] = curr_cu_info->inter_ref_index[REF_PIC_LIST_0];ref_index_bi[REF_PIC_LIST_1] = curr_cu_info->inter_ref_index[REF_PIC_LIST_1];mvp_idx[REF_PIC_LIST_0] = curr_cu_info->best_candidate_idx[0];mvp_idx[REF_PIC_LIST_1] = curr_cu_info->best_candidate_idx[1];mv_best_cand_bi[REF_PIC_LIST_0] = et->amvp_candidates[REF_PIC_LIST_0].mv_candidates[mvp_idx[REF_PIC_LIST_0]].mv;mv_best_cand_bi[REF_PIC_LIST_1] = et->amvp_candidates[REF_PIC_LIST_1].mv_candidates[mvp_idx[REF_PIC_LIST_1]].mv;mvp_bi[REF_PIC_LIST_0].hor_vector = mv_bi[REF_PIC_LIST_0].hor_vector - mv_best_cand_bi[REF_PIC_LIST_0].hor_vector;mvp_bi[REF_PIC_LIST_0].ver_vector = mv_bi[REF_PIC_LIST_0].ver_vector - mv_best_cand_bi[REF_PIC_LIST_0].ver_vector;mvp_bi[REF_PIC_LIST_1].hor_vector = mv_bi[REF_PIC_LIST_1].hor_vector - mv_best_cand_bi[REF_PIC_LIST_1].hor_vector;mvp_bi[REF_PIC_LIST_1].ver_vector = mv_bi[REF_PIC_LIST_1].ver_vector - mv_best_cand_bi[REF_PIC_LIST_1].ver_vector;/* 如果mvd_l1_zero_flag为true(mvd_l1_zero_flag这个标志还不知道是什么意思),那么进行一次运动补偿 */if (currslice->mvd_l1_zero_flag){int16_t *pred_other_y, *pred_other_u, *pred_other_v;int pred_other_y_stride, pred_other_ch_stride;motion_vector_t mv = mv_best_cand_bi[REF_PIC_LIST_1];ref_idx = curr_cu_info->inter_ref_index[REF_PIC_LIST_1];mv_bi[REF_PIC_LIST_1] = mv_best_cand_bi[REF_PIC_LIST_1];pred_other_y_stride = WND_STRIDE_2D(et->prediction_wnd[1 + REF_PIC_LIST_1], Y_COMP);pred_other_y = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + REF_PIC_LIST_1], Y_COMP, curr_part_x, curr_part_y, gcnt, et->ctu_width);pred_other_ch_stride = WND_STRIDE_2D(et->prediction_wnd[1 + REF_PIC_LIST_1], U_COMP);pred_other_u = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + REF_PIC_LIST_1], U_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);pred_other_v = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + REF_PIC_LIST_1], V_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);reference_wnd = &currslice->ref_pic_list[REF_PIC_LIST_1][ref_idx]->img;reference_buff_stride = WND_STRIDE_2D(*reference_wnd, Y_COMP);reference_buff_cu_position = WND_POSITION_2D(int16_t *, *reference_wnd, Y_COMP, curr_part_global_x, curr_part_global_y, gcnt, et->ctu_width);reference_buff_stride_chroma = WND_STRIDE_2D(*reference_wnd, U_COMP);reference_buff_cu_position_u = WND_POSITION_2D(int16_t *, *reference_wnd, U_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);reference_buff_cu_position_v = WND_POSITION_2D(int16_t *, *reference_wnd, V_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);/* 运动补偿(在HomerHEVC中运动补偿就是I一个插值操作。。。) */hmr_motion_compensation_luma(et, curr_cu_info, reference_buff_cu_position, reference_buff_stride, pred_other_y, pred_other_y_stride, curr_part_size, curr_part_size, curr_part_size_shift, &mv, 0);hmr_motion_compensation_chroma(et, reference_buff_cu_position_u, reference_buff_stride_chroma, pred_other_u, pred_other_ch_stride, curr_part_size_chroma, curr_part_size_shift_chroma, &mv, 0);hmr_motion_compensation_chroma(et, reference_buff_cu_position_v, reference_buff_stride_chroma, pred_other_v, pred_other_ch_stride, curr_part_size_chroma, curr_part_size_shift_chroma, &mv, 0);}if (best_cost[REF_PIC_LIST_0] > best_cost[REF_PIC_LIST_1] || currslice->mvd_l1_zero_flag)ref_list = REF_PIC_LIST_0;elseref_list = REF_PIC_LIST_1;/* 如果mvd_l1_zero_flag为true(mvd_l1_zero_flag这个标志还不知道是什么意思) */if (!currslice->mvd_l1_zero_flag){int16_t *pred_other_y, *pred_other_u, *pred_other_v;int pred_other_y_stride, pred_other_ch_stride;int ref_list_other = 1 - ref_list;motion_vector_t mv = mv_bi[ref_list_other];ref_idx = curr_cu_info->inter_ref_index[ref_list_other];//mv_bi[ref_list_other] = mvp_bi[ref_list_other].mv;pred_other_y_stride = WND_STRIDE_2D(et->prediction_wnd[1 + ref_list_other], Y_COMP);pred_other_y = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + ref_list_other], Y_COMP, curr_part_x, curr_part_y, gcnt, et->ctu_width);pred_other_ch_stride = WND_STRIDE_2D(et->prediction_wnd[1 + ref_list_other], U_COMP);pred_other_u = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + ref_list_other], U_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);pred_other_v = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + ref_list_other], V_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);reference_wnd = &currslice->ref_pic_list[ref_list_other][ref_idx]->img;//[0] up to now we only use one referencereference_buff_stride = WND_STRIDE_2D(*reference_wnd, Y_COMP);reference_buff_cu_position = WND_POSITION_2D(int16_t *, *reference_wnd, Y_COMP, curr_part_global_x, curr_part_global_y, gcnt, et->ctu_width);reference_buff_stride_chroma = WND_STRIDE_2D(*reference_wnd, U_COMP);reference_buff_cu_position_u = WND_POSITION_2D(int16_t *, *reference_wnd, U_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);reference_buff_cu_position_v = WND_POSITION_2D(int16_t *, *reference_wnd, V_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);hmr_motion_compensation_luma(et, curr_cu_info, reference_buff_cu_position, reference_buff_stride, pred_other_y, pred_other_y_stride, curr_part_size, curr_part_size, curr_part_size_shift, &mv, 0);hmr_motion_compensation_chroma(et, reference_buff_cu_position_u, reference_buff_stride_chroma, pred_other_u, pred_other_ch_stride, curr_part_size_chroma, curr_part_size_shift_chroma, &mv, 0);hmr_motion_compensation_chroma(et, reference_buff_cu_position_v, reference_buff_stride_chroma, pred_other_v, pred_other_ch_stride, curr_part_size_chroma, curr_part_size_shift_chroma, &mv, 0);}num_ref_idx = currslice->num_ref_idx[ref_list];//for(iter=0;iter<num_iter;iter++)/* 遍历参考帧 ,进行运动估计 */for (ref_idx = 0; ref_idx < num_ref_idx; ref_idx++){int16_t *pred_other_y, *pred_other_u, *pred_other_v;int pred_other_y_stride, pred_other_ch_stride;int orig_buff_stride;int mvp_candidate_idx;mv_candiate_list_tamvp_candidate_list;int16_t *aux_y, *aux_u, *aux_v;int aux_y_stride, aux_ch_stride;int list_other = 1 - (int)ref_list;//int ref_idx = curr_cu_info->inter_ref_index[ref_list];motion_vector_t mv = curr_cu_info->inter_mv[ref_list];wnd_copy(et->funcs->sse_copy_16_16, &et->curr_mbs_wnd, &et->curr_mbs_aux_wnd);aux_y_stride = WND_STRIDE_2D(et->curr_mbs_aux_wnd, Y_COMP);aux_y = WND_POSITION_2D(int16_t *, et->curr_mbs_aux_wnd, Y_COMP, curr_part_x, curr_part_y, gcnt, et->ctu_width);aux_ch_stride = WND_STRIDE_2D(et->curr_mbs_aux_wnd, U_COMP);aux_u = WND_POSITION_2D(int16_t *, et->curr_mbs_aux_wnd, U_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);aux_v = WND_POSITION_2D(int16_t *, et->curr_mbs_aux_wnd, V_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);pred_other_y_stride = WND_STRIDE_2D(et->prediction_wnd[1 + list_other], Y_COMP);pred_other_y = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + list_other], Y_COMP, curr_part_x, curr_part_y, gcnt, et->ctu_width);pred_other_ch_stride = WND_STRIDE_2D(et->prediction_wnd[1 + list_other], U_COMP);pred_other_u = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + list_other], U_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);pred_other_v = WND_POSITION_2D(int16_t *, et->prediction_wnd[1 + list_other], V_COMP, curr_part_x_chroma, curr_part_y_chroma, gcnt, et->ctu_width);/* 移除高频信息 */remove_high_freq(pred_other_y, pred_other_y_stride, aux_y, aux_y_stride, curr_cu_info->size, curr_cu_info->size);remove_high_freq(pred_other_u, pred_other_ch_stride, aux_u, aux_ch_stride, curr_cu_info->size_chroma, curr_cu_info->size_chroma);remove_high_freq(pred_other_v, pred_other_ch_stride, aux_v, aux_ch_stride, curr_cu_info->size_chroma, curr_cu_info->size_chroma);reference_wnd = &currslice->ref_pic_list[ref_list][ref_idx]->img;//[0] up to now we only use one referencereference_buff_stride = WND_STRIDE_2D(*reference_wnd, Y_COMP);reference_buff_cu_position = WND_POSITION_2D(int16_t *, *reference_wnd, Y_COMP, curr_part_global_x, curr_part_global_y, gcnt, et->ctu_width);reference_buff_stride_chroma = WND_STRIDE_2D(*reference_wnd, U_COMP);reference_buff_cu_position_u = WND_POSITION_2D(int16_t *, *reference_wnd, U_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);reference_buff_cu_position_v = WND_POSITION_2D(int16_t *, *reference_wnd, V_COMP, curr_part_global_x_chroma, curr_part_global_y_chroma, gcnt, et->ctu_width);/* 使用HM中的双向运动估计 */cost = hmr_bi_motion_estimation_HM(et, ctu, curr_cu_info, aux_y, aux_y_stride, reference_buff_cu_position, reference_buff_stride, curr_part_global_x, curr_part_global_y, 0, 0, curr_part_size, curr_part_size_shift, 4, 4, et->pict_width[Y_COMP], et->pict_height[Y_COMP], &mv);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//!!esto deberia guardarlo en un conjunto de listas para de candidatos y coger la lista de candidatos que queremos!!//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!/* 获取候选的AMVP */get_amvp_candidates(et, currslice, ctu, curr_cu_info, &amvp_candidate_list, ref_list, ref_idx, part_size_type);//get candidates for advanced motion vector prediction from the neigbour CUs/* 选择候选的MV */mv_cost = select_mv_candidate(et, curr_cu_info, &amvp_candidate_list, &mv, &mvp_candidate_idx);/* 更新最优的MV */if (cost < best_cost_bi){mv_bi[ref_list] = mv;ref_index_bi[ref_list] = ref_idx;mvp_bi[ref_list].hor_vector = mv.hor_vector - amvp_candidate_list.mv_candidates[mvp_candidate_idx].mv.hor_vector;mvp_bi[ref_list].ver_vector = mv.ver_vector - amvp_candidate_list.mv_candidates[mvp_candidate_idx].mv.ver_vector;mvp_idx[ref_list] = mvp_candidate_idx;best_cost_bi = cost;mv_best_cost_bi = mv_cost;//set mvs and ref_idx}}}#ifdef COMPUTE_AS_HMif (best_cost_bi <= best_cost[REF_PIC_LIST_0] && best_cost_bi <= best_cost[REF_PIC_LIST_1])#else/* 更新最优的代价和模式 */if ((best_cost_bi + mv_best_cost_bi) <= best_cost[REF_PIC_LIST_0] + mv_best_cost[REF_PIC_LIST_0] && best_cost_bi <= best_cost[REF_PIC_LIST_1] + mv_best_cost[REF_PIC_LIST_1])#endif{sad += best_cost_bi;mv_total_cost += mv_best_cost_bi;curr_cu_info->best_candidate_idx[REF_PIC_LIST_0] = mvp_idx[REF_PIC_LIST_0];curr_cu_info->best_dif_mv[REF_PIC_LIST_0] = mvp_bi[REF_PIC_LIST_0];curr_cu_info->best_candidate_idx[REF_PIC_LIST_1] = mvp_idx[REF_PIC_LIST_1];curr_cu_info->best_dif_mv[REF_PIC_LIST_1] = mvp_bi[REF_PIC_LIST_1];curr_cu_info->inter_mv[REF_PIC_LIST_0] = mv_bi[REF_PIC_LIST_0];curr_cu_info->inter_mv[REF_PIC_LIST_1] = mv_bi[REF_PIC_LIST_1];//curr_cu_info->inter_ref_list = //REF_PIC_LIST_0 | REF_PIC_LIST_1;curr_cu_info->inter_ref_index[REF_PIC_LIST_0] = ref_index_bi[REF_PIC_LIST_0];curr_cu_info->inter_ref_index[REF_PIC_LIST_1] = ref_index_bi[REF_PIC_LIST_1];curr_cu_info->inter_mode = (0x1 << REF_PIC_LIST_0) | (0x1 << REF_PIC_LIST_1);}#ifdef COMPUTE_AS_HMelse if (best_cost[REF_PIC_LIST_0] <= best_cost[REF_PIC_LIST_1])#elseelse if (best_cost[REF_PIC_LIST_0] + mv_best_cost[REF_PIC_LIST_0] <= best_cost[REF_PIC_LIST_1] + mv_best_cost[REF_PIC_LIST_1])#endif{sad += best_cost[REF_PIC_LIST_0];mv_total_cost += mv_best_cost[REF_PIC_LIST_0];curr_cu_info->inter_ref_index[REF_PIC_LIST_1] = -1;//curr_cu_info->inter_ref_list = REF_PIC_LIST_0;curr_cu_info->inter_mode = (0x1 << REF_PIC_LIST_0);}else{sad += best_cost[REF_PIC_LIST_1];mv_total_cost += mv_best_cost[REF_PIC_LIST_1];curr_cu_info->inter_ref_index[REF_PIC_LIST_0] = -1;//curr_cu_info->inter_ref_list = REF_PIC_LIST_1;curr_cu_info->inter_mode = (0x1 << REF_PIC_LIST_1);}if (part_size_type == SIZE_NxN){SET_INTER_MV_BUFFS(et, ctu, curr_cu_info, curr_cu_info->abs_index, curr_cu_info->num_part_in_cu);memset(&ctu->mv_ref_idx[REF_PIC_LIST_0][curr_cu_info->abs_index], curr_cu_info->inter_ref_index[REF_PIC_LIST_0], curr_cu_info->num_part_in_cu*sizeof(ctu->mv_ref_idx[0][0]));memset(&ctu->mv_ref_idx[REF_PIC_LIST_1][curr_cu_info->abs_index], curr_cu_info->inter_ref_index[REF_PIC_LIST_1], curr_cu_info->num_part_in_cu*sizeof(ctu->mv_ref_idx[0][0]));memset(&ctu->inter_mode[curr_cu_info->abs_index], curr_cu_info->inter_mode, curr_cu_info->num_part_in_cu*sizeof(ctu->inter_mode[0]));memset(&ctu->pred_mode[curr_cu_info->abs_index], INTER_MODE, curr_cu_info->num_part_in_cu*sizeof(ctu->pred_mode[0]));}curr_cu_info++;}return sad + 1 * mv_total_cost;//.5*mv_cost;}

四、AMVP选择候选MV,从空域、时域建立MV候选列表,对邻居的处理顺序请参考 HEVC/H.265理论知识(4)——帧间预测 

void get_amvp_candidates(henc_thread_t* et, slice_t *currslice, ctu_info_t* ctu, cu_partition_info_t *curr_cu_info, mv_candiate_list_t*search_candidate_list,int ref_pic_list, int ref_idx, PartSize part_size_type)//get candidates for motion search from the neigbour CUs{//mv_candiate_list_t*search_candidate_list = &et->amvp_candidates[ref_pic_list];ctu_info_t*ctu_left = NULL, *ctu_left_bottom = NULL, *ctu_top = NULL, *ctu_top_right = NULL, *ctu_top_left = NULL;uintpart_idx_lb, part_idx_l, aux_part_idx;intadded = FALSE, added_smvp = FALSE;intnum_partitions_height = curr_cu_info->size >> 2;intnum_partitions_width = curr_cu_info->size >> 2;intmax_partitions_width = et->max_cu_size >> 2;uint num_partitions_mask = curr_cu_info->num_part_in_cu - 1;int abs_index_lb = et->enc_engine->raster2abs_table[curr_cu_info->raster_index + max_partitions_width*(num_partitions_height - 1)];int abs_index_tl = et->enc_engine->raster2abs_table[curr_cu_info->raster_index];int abs_index_tr = et->enc_engine->raster2abs_table[curr_cu_info->raster_index + num_partitions_width - 1];cu_partition_info_t *partition_info_lb = &ctu->partition_list[et->partition_depth_start[et->max_cu_depth]] + abs_index_lb;cu_partition_info_t *partition_tl = &ctu->partition_list[et->partition_depth_start[et->max_cu_depth]] + abs_index_tl;cu_partition_info_t *partition_tr = &ctu->partition_list[et->partition_depth_start[et->max_cu_depth]] + abs_index_tr;int left_pixel_x = ctu->x[Y_COMP] + curr_cu_info->x_position + curr_cu_info->size;search_candidate_list->num_mv_candidates = 0;partition_info_lb->left_bottom_neighbour = curr_cu_info->left_bottom_neighbour;ctu_left_bottom = get_pu_left_bottom(et, ctu, partition_info_lb, &part_idx_lb);//tmpCU = getPUBelowLeft(idx, uiPartIdxLB);added_smvp = (ctu_left_bottom != NULL) && (ctu_left_bottom->pred_mode[part_idx_lb] != INTRA_MODE);if (!added_smvp){ctu_left = get_pu_left(ctu, partition_info_lb, &part_idx_l);//ctu->ctu_left;added_smvp = (ctu_left != NULL) && (ctu_left->pred_mode[part_idx_l] != INTRA_MODE);}//get spatial candidatesadded = add_amvp_cand(search_candidate_list, currslice, ctu_left_bottom, ref_pic_list, ref_idx, part_idx_lb);if (!added){ctu_left = get_pu_left(ctu, partition_info_lb, &part_idx_l);//ctu->ctu_left;added = add_amvp_cand(search_candidate_list, currslice, ctu_left, ref_pic_list, ref_idx, part_idx_l);}if (!added){added = add_amvp_cand_order(search_candidate_list, currslice, ctu_left_bottom, ref_pic_list, ref_idx, part_idx_lb);if (!added){added = add_amvp_cand_order(search_candidate_list, currslice, ctu_left, ref_pic_list, ref_idx, part_idx_l);}}partition_tr->top_right_neighbour = curr_cu_info->top_right_neighbour;ctu_top_right = get_pu_top_right(ctu, partition_tr, &aux_part_idx);added = add_amvp_cand(search_candidate_list, currslice, ctu_top_right, ref_pic_list, ref_idx, aux_part_idx);if (!added){ctu_top = get_pu_top(ctu, partition_tr, &aux_part_idx, 0);added = add_amvp_cand(search_candidate_list, currslice, ctu_top, ref_pic_list, ref_idx, aux_part_idx);}if (!added){ctu_top_left = get_pu_top_left(ctu, partition_tl, &aux_part_idx);added = add_amvp_cand(search_candidate_list, currslice, ctu_top_left, ref_pic_list, ref_idx, aux_part_idx);}if (!added_smvp){ctu_top_right = get_pu_top_right(ctu, partition_tr, &aux_part_idx);added = add_amvp_cand_order(search_candidate_list, currslice, ctu_top_right, ref_pic_list, ref_idx, aux_part_idx);if (!added){ctu_top = get_pu_top(ctu, partition_tr, &aux_part_idx, 0);added = add_amvp_cand_order(search_candidate_list, currslice, ctu_top, ref_pic_list, ref_idx, aux_part_idx);}if (!added){ctu_top_left = get_pu_top_left(ctu, partition_tl, &aux_part_idx);added = add_amvp_cand_order(search_candidate_list, currslice, ctu_top_left, ref_pic_list, ref_idx, aux_part_idx);}}if ((ctu_left_bottom != NULL && ctu_left_bottom->pred_mode[part_idx_lb] != INTRA_MODE) || (ctu_left != NULL && ctu_left->pred_mode[part_idx_l] != INTRA_MODE)){//reorder�?}if (search_candidate_list->num_mv_candidates == 2 && search_candidate_list->mv_candidates[0].mv.hor_vector == search_candidate_list->mv_candidates[1].mv.hor_vector && search_candidate_list->mv_candidates[0].mv.ver_vector == search_candidate_list->mv_candidates[1].mv.ver_vector){search_candidate_list->num_mv_candidates = 1;}//get temporal candidates//.....if (search_candidate_list->num_mv_candidates > AMVP_MAX_NUM_CANDS)search_candidate_list->num_mv_candidates = AMVP_MAX_NUM_CANDS;while (search_candidate_list->num_mv_candidates < AMVP_MAX_NUM_CANDS){search_candidate_list->mv_candidates[search_candidate_list->num_mv_candidates].mv.hor_vector = 0;search_candidate_list->mv_candidates[search_candidate_list->num_mv_candidates++].mv.ver_vector = 0;}}

五、从MV候选列表中选取率失真最优的MV,来作为运动估计的搜索起点

uint32_t select_mv_candidate(henc_thread_t* et, cu_partition_info_t* curr_cu_info, mv_candiate_list_t*search_candidate_list, motion_vector_t *mv, int *best_candidate){//mv_candiate_list_t*search_candidate_list = &et->amvp_candidates[ref_pic_list];int idx;uint32_t best_cost = INT_MAX, best_idx = 0;/* 遍历所有候选的MV */for (idx = 0; idx < search_candidate_list->num_mv_candidates; idx++){#ifdef COMPUTE_AS_HMdouble cost_mvx = 30 * sqrt((float)abs(search_candidate_list->mv_candidates[idx].mv.hor_vector - mv->hor_vector));double cost_mvy = 30 * sqrt((float)abs(search_candidate_list->mv_candidates[idx].mv.ver_vector - mv->ver_vector));#else/* 计算MV横向和纵向上的代价 */double cost_mvx = curr_cu_info->qp*squareRoot((float)abs(search_candidate_list->mv_candidates[idx].mv.hor_vector - mv->hor_vector));double cost_mvy = curr_cu_info->qp*squareRoot((float)abs(search_candidate_list->mv_candidates[idx].mv.ver_vector - mv->ver_vector));#endifuint32_t cost = (uint32_t)(3. + cost_mvx + cost_mvy + .5);/* 更新最优代价 */if (best_cost > cost){best_cost = cost;best_idx = idx;}}*best_candidate = best_idx;return best_cost;}

六、根据上一步确定的MV来确定搜索起点,然后进行运动估计(算法比较复杂)

uint32_t hmr_motion_estimation(henc_thread_t* et, ctu_info_t* ctu, cu_partition_info_t* curr_cu_info,int16_t *orig_buff, int orig_buff_stride, int16_t *reference_buff, int reference_buff_stride,int curr_part_global_x, int curr_part_global_y,int init_x, int init_y, int curr_part_size, int curr_part_size_shift, int search_range_x, int search_range_y,int frame_size_x, int frame_size_y, motion_vector_t *mv, motion_vector_t *subpix_mv, mv_candiate_list_t *amvp_candidate_list, uint32_t threshold, unsigned int action){int i, l;int xlow, xhigh, ylow, yhigh;/* 预测的最好的SAD、预测的最好的rd,当前最好的SAD、当前最好的rd*/uint32_t prev_best_sad = 0, prev_best_rd = 0, curr_best_sad = 0, curr_best_rd = 0, best_sad = MAX_COST, best_rd = 0;int prev_best_x, prev_best_y, curr_best_x, curr_best_y, best_x = 0, best_y = 0;int dist = 1;int end;/* 搜索到的MV候选列表 */mv_candiate_list_t*search_candidate_list = &et->mv_search_candidates;//&et->mv_candidates[REF_PIC_LIST_0];int mv_cost = 0;/* 亚像素精度的MV */motion_vector_t half_mv;int next_start;/* 搜索的尺寸、砖石搜索的尺寸 */int search_size, diamond_size;/* 最优的候选者 */int best_candidate;subpix_mv->hor_vector = 0;subpix_mv->ver_vector = 0;threshold = 0;/* xlow和xhigh组成横向的搜索范围 */xlow = ((curr_part_global_x - search_range_x) < 0) ? -curr_part_global_x : -search_range_x;xhigh = ((curr_part_global_x + search_range_x) > (frame_size_x - curr_part_size)) ? frame_size_x - curr_part_global_x - curr_part_size : search_range_x;/* ylow和yhigh组成纵向搜索范围 */ylow = ((curr_part_global_y - search_range_y) < 0) ? -curr_part_global_y : -search_range_y;yhigh = ((curr_part_global_y + search_range_y) > (frame_size_y - curr_part_size)) ? frame_size_y - curr_part_global_y - curr_part_size : search_range_y;/* 整像素的运动估计 */if (action & MOTION_PEL_MASK){/* 设定搜索的范围 */curr_best_x = init_x;curr_best_y = init_y;if (curr_best_x < xlow)curr_best_x = xlow;if (curr_best_x > xhigh)curr_best_x = xhigh;if (curr_best_y < ylow)curr_best_y = ylow;if (curr_best_y > yhigh)curr_best_y = yhigh;/* 计算该范围内的SAD */curr_best_sad = et->funcs->sad(orig_buff, orig_buff_stride, reference_buff + curr_best_y*reference_buff_stride + curr_best_x, reference_buff_stride, curr_cu_info->size);mv->hor_vector = curr_best_x << 2;mv->ver_vector = curr_best_y << 2;subpix_mv->hor_vector = 0;subpix_mv->ver_vector = 0;/* 选择一个最优的MV ,来计算该mv是否为最优的运动估计 */mv_cost = select_mv_candidate_fast(et, curr_cu_info, amvp_candidate_list, mv, &best_candidate);curr_best_rd = curr_best_sad + mv_cost;best_sad = curr_best_sad;best_rd = curr_best_rd;best_x = curr_best_x;best_y = curr_best_y;//if(best_sad<=2*curr_part_size*curr_part_size)/* 如果SAD已经小于阈值,那么直接进行最后一次搜索 */if (best_sad <= threshold)goto last_search;//curr_best_x = 0;//curr_best_y = 0;/* 如果最优的MV还不是最优的运动估计 ,那么需要遍历所有的候选MV,确定最优的运动估计 */for (i = 0; i < search_candidate_list->num_mv_candidates; i++){uint32_t curr_sad, curr_rd;int curr_x = search_candidate_list->mv_candidates[i].mv.hor_vector >> 2;int curr_y = search_candidate_list->mv_candidates[i].mv.ver_vector >> 2;if (curr_x == 0 && curr_y == 0){continue;}if (curr_x >= xlow && curr_x <= xhigh && curr_y >= ylow && curr_y <= yhigh){curr_sad = et->funcs->sad(orig_buff, orig_buff_stride, reference_buff + curr_y*reference_buff_stride + curr_x, reference_buff_stride, curr_cu_info->size);mv->hor_vector = curr_x << 2;mv->ver_vector = curr_y << 2;mv_cost = select_mv_candidate_fast(et, curr_cu_info, amvp_candidate_list, mv, &best_candidate);curr_rd = curr_sad + mv_cost;if (curr_rd < curr_best_rd){curr_best_sad = curr_sad;curr_best_rd = curr_rd;curr_best_x = curr_x;curr_best_y = curr_y;}}}best_sad = curr_best_sad;best_rd = curr_best_rd;best_x = curr_best_x;best_y = curr_best_y;//if(best_sad<=2*curr_part_size*curr_part_size)/* 如果已经是最优 ,那么进行最后一次的搜索 */if (best_sad <= threshold)//curr_part_size*curr_part_size)goto last_search;/* 以确定的点位起点,按照钻石型来搜索 */for (i = 0; i < sizeof(diamond_small) / sizeof(diamond_small[0]); i++){/* 确定当前位置 */int curr_x = best_x + diamond_small[i][0];int curr_y = best_y + diamond_small[i][1];uint32_t curr_sad, curr_rd;/* 如果当前位置在搜索范围内,那么计算该点是否为最优的运动估计 */if (curr_x >= xlow && curr_x <= xhigh && curr_y >= ylow && curr_y <= yhigh){curr_sad = et->funcs->sad(orig_buff, orig_buff_stride, reference_buff + curr_y*reference_buff_stride + curr_x, reference_buff_stride, curr_cu_info->size);mv->hor_vector = curr_x << 2;mv->ver_vector = curr_y << 2;/* 选择一个最优的MV */mv_cost = select_mv_candidate_fast(et, curr_cu_info, amvp_candidate_list, mv, &best_candidate);curr_rd = curr_sad + mv_cost;if (curr_rd < curr_best_rd){curr_best_sad = curr_sad;curr_best_rd = curr_rd;curr_best_x = curr_x;curr_best_y = curr_y;}}}/* 如果已经是最优的运动估计,那么直接跳到最后一次搜索 ,否则继续往下 */if (best_sad <= threshold)//curr_part_size*curr_part_size)goto last_search;dist = 2;if (best_x != 0 && best_y != 0)end = 4;elseend = 8;diamond_size = sizeof(diamond_big) / sizeof(diamond_big[0]);/* 进行一次搜索 */for (l = 0; l < 1; l++){next_start = 0;search_size = diamond_size;best_sad = curr_best_sad;best_rd = curr_best_rd;best_x = curr_best_x;best_y = curr_best_y;if (l == 1){dist = 1;end = 2;}//for(dist = 1; dist<8; dist*=2)/* 当步幅还没达到end的时候就一直搜索 */while (dist < end){//for(i=0;i<diamond_size;i++)/* 在指定的范围内搜索 */for (i = next_start; i < next_start + search_size; i++){/* 确定搜索位置 */int index = i%diamond_size;int curr_x = best_x + diamond_big[index][0] * dist;int curr_y = best_y + diamond_big[index][1] * dist;uint32_t curr_sad, curr_rd;/* 搜索位置在范围内 */if (curr_x >= xlow && curr_x <= xhigh && curr_y >= ylow && curr_y <= yhigh){/* 计算SAD的值 */curr_sad = et->funcs->sad(orig_buff, orig_buff_stride, reference_buff + curr_y*reference_buff_stride + curr_x, reference_buff_stride, curr_cu_info->size);mv->hor_vector = curr_x << 2;mv->ver_vector = curr_y << 2;/* 一个候选的mv */mv_cost = select_mv_candidate_fast(et, curr_cu_info, amvp_candidate_list, mv, &best_candidate);curr_rd = curr_sad + mv_cost;if (curr_rd < curr_best_rd){curr_best_sad = curr_sad;curr_best_rd = curr_rd;curr_best_x = curr_x;curr_best_y = curr_y;next_start = (index - 2 + diamond_size) % diamond_size;search_size = diamond_size - 3;}}}if (l == 1 && (best_x != curr_best_x || best_y != curr_best_y)){best_sad = curr_best_sad;best_rd = curr_best_rd;best_x = curr_best_x;best_y = curr_best_y;dist = 2;}elsedist *= 2; /* 步幅加倍 */}}/* 最后的一次搜索 */last_search:best_sad = curr_best_sad;best_rd = curr_best_rd;best_x = curr_best_x;best_y = curr_best_y;prev_best_rd = MAX_COST;prev_best_sad = MAX_COST;prev_best_x = best_x;prev_best_y = best_y;//if(best_sad<=threshold/2)//goto end;next_start = 0;diamond_size = sizeof(diamond_small) / sizeof(diamond_small[0]);search_size = diamond_size;while (1){//for(i=0;i<diamond_size;i++)/* 在此范围内 搜索 */for (i = next_start; i < next_start + search_size; i++){int index = i%diamond_size;/* 确定位置 */int curr_x = best_x + diamond_small[index][0];int curr_y = best_y + diamond_small[index][1];uint32_t curr_sad, curr_rd;/* 合理位置,进行估计 */if (curr_x >= xlow && curr_x <= xhigh && curr_y >= ylow && curr_y <= yhigh){curr_sad = et->funcs->sad(orig_buff, orig_buff_stride, reference_buff + curr_y*reference_buff_stride + curr_x, reference_buff_stride, curr_cu_info->size);mv->hor_vector = curr_x << 2;mv->ver_vector = curr_y << 2;mv_cost = select_mv_candidate_fast(et, curr_cu_info, amvp_candidate_list, mv, &best_candidate);curr_rd = curr_sad + mv_cost;/* 更新最优值 */if (curr_rd < curr_best_rd){prev_best_sad = curr_best_sad;prev_best_rd = curr_best_rd;prev_best_x = curr_best_x;prev_best_y = curr_best_y;curr_best_sad = curr_sad;curr_best_rd = curr_rd;curr_best_x = curr_x;curr_best_y = curr_y;next_start = (index - 1 + diamond_size) % diamond_size;search_size = diamond_size - 1;}else if (curr_rd < prev_best_rd){prev_best_sad = curr_sad;prev_best_rd = curr_rd;prev_best_x = curr_x;prev_best_y = curr_y;}}}/* 如果当前点就是最优点,那么跳出循环*/if (best_x == curr_best_x && best_y == curr_best_y){break;}/* 否则调整最优点位置 ,继续while循环*/else{best_sad = curr_best_sad;best_rd = curr_best_rd;best_x = curr_best_x;best_y = curr_best_y;}}best_sad = curr_best_sad;best_x = curr_best_x;best_y = curr_best_y;mv->hor_vector = (best_x << 2);// + curr_best_x;mv->ver_vector = (best_y << 2);// + curr_best_y;subpix_mv->hor_vector = 0;subpix_mv->ver_vector = 0;}/* 半像素精度*/if (action & MOTION_HALF_PEL_MASK)//perform half-sample and quarter-sample motion estimation{int curr_best_idx;/* 搜索的起始位置 */int curr_part_x = curr_cu_info->x_position;int curr_part_y = curr_cu_info->y_position;uint32_t curr_sad;best_x = mv->hor_vector >> 2;best_y = mv->ver_vector >> 2;/* 如果不是整像素的运动估计,那么计算SAD*/if (!(action & MOTION_PEL_MASK))curr_best_sad = et->funcs->sad(orig_buff, orig_buff_stride, reference_buff + best_y*reference_buff_stride + best_x, reference_buff_stride, curr_cu_info->size);/* 亚像素的插值  */hmr_half_pixel_estimation_luma_hm(et, reference_buff + best_y*reference_buff_stride + best_x, reference_buff_stride, curr_cu_info, curr_part_size, curr_part_size, curr_part_size_shift, mv);curr_best_x = 0;curr_best_y = 0;curr_best_idx = 0;/* 从预定的九个点进行估计  */for (i = 0; i < 9; i++){/* 确定起点 */int curr_x = s_acMvRefineH_HM[i][0] * 2;int curr_y = s_acMvRefineH_HM[i][1] * 2;int src_stride;int16_t *src;src_stride = WND_STRIDE_2D(et->filtered_block_wnd[curr_y & 3][curr_x & 3], Y_COMP);src = WND_POSITION_2D(int16_t *, et->filtered_block_wnd[curr_y & 3][curr_x & 3], Y_COMP, curr_part_x, curr_part_y, 0, et->ctu_width);if (curr_x == 2 && (curr_y & 1) == 0){src += 1;}if ((curr_x & 1) == 0 && curr_y == 2){src += src_stride;}/* 计算SAD */curr_sad = sad(orig_buff, orig_buff_stride, src, src_stride, curr_cu_info->size);/* 更新最优的运动估计 */if (curr_sad < curr_best_sad){curr_best_sad = curr_sad;curr_best_x = curr_x;curr_best_y = curr_y;curr_best_idx = i;}}mv->hor_vector = (best_x << 2) + curr_best_x;mv->ver_vector = (best_y << 2) + curr_best_y;subpix_mv->hor_vector = curr_best_x;subpix_mv->ver_vector = curr_best_y;best_sad = curr_best_sad;/* 如果是1/4的像素精度 */if (action & MOTION_QUARTER_PEL_MASK){/* 计算mv */half_mv.hor_vector = s_acMvRefineH_HM[curr_best_idx][0];half_mv.ver_vector = s_acMvRefineH_HM[curr_best_idx][1];/* 1/4像素精度的插值 */hmr_quarter_pixel_estimation_luma_hm(et, reference_buff + best_y*reference_buff_stride + best_x, reference_buff_stride, curr_cu_info, curr_part_size, curr_part_size, curr_part_size_shift, &half_mv);curr_best_x = half_mv.hor_vector * 2;curr_best_y = half_mv.ver_vector * 2;/* 从预定的9个点进行搜索 */for (i = 0; i < 9; i++){/* 确定当前位置 */int curr_x = half_mv.hor_vector * 2 + s_acMvRefineQ[i][0] * 1;int curr_y = half_mv.ver_vector * 2 + s_acMvRefineQ[i][1] * 1;int src_stride;int16_t *src;src_stride = WND_STRIDE_2D(et->filtered_block_wnd[curr_y & 3][curr_x & 3], Y_COMP);src = WND_POSITION_2D(int16_t *, et->filtered_block_wnd[curr_y & 3][curr_x & 3], Y_COMP, curr_part_x, curr_part_y, 0, et->ctu_width);if (curr_x == 2 && (curr_y & 1) == 0){src += 1;}if ((curr_x & 1) == 0 && curr_y == 2){src += src_stride;}/* 计算SAD */curr_sad = sad(orig_buff, orig_buff_stride, src, src_stride, curr_cu_info->size);/* 更新最优的运动估计 */if (curr_sad < curr_best_sad){curr_best_sad = curr_sad;curr_best_x = curr_x;curr_best_y = curr_y;curr_best_idx = i;}}best_sad = curr_best_sad;mv->hor_vector = (best_x << 2) + curr_best_x;mv->ver_vector = (best_y << 2) + curr_best_y;subpix_mv->hor_vector = curr_best_x;subpix_mv->ver_vector = curr_best_y;}}return best_sad;}






0 0
原创粉丝点击