static void interpolate_comp(mv_data_t* mv_data, uint8_t* p0, int s0, uint8_t* p1, int s1, uint8_t* out, int so, int wP, int hP, int pad, int chroma) { const int bw=mv_data->bw; const int bh=mv_data->bh; const int bs=chroma ? mv_data->bs/2 : mv_data->bs; for (int yp=0; yp<bh; yp++) { for (int xp=0; xp<bw; xp++) { int xstart=xp*bs; int ystart=yp*bs; mv_t mv0=mv_data->mv[0][yp*bw+xp]; mv_t mv1=mv_data->mv[1][yp*bw+xp]; if (chroma){ mv1.x >>= 1; mv1.y >>= 1; mv0 = scale_mv(mv1, -mv_data->wt[1], mv_data->wt[0]); } mot_comp_avg(xstart, ystart, p0, s0, p1, s1, out, so, mv0, mv1, wP, hP, pad, bs, mv_data->wt); } } }
static void merge_candidate_search(mv_t* cand_list, int num_cands, mv_data_t* mv_data, mv_t* mv0, mv_t* mv1, yuv_frame_t* picdata[2], int xp, int yp) { int xstart=xp*mv_data->bs; int ystart=yp*mv_data->bs; // Do this search on the smaller blocks int size=mv_data->bs; uint32_t best_cost=COST_MAX; mv_t best_mv={0,0}; mv_t best_scaled_mv={0,0}; for (int i=0; i<num_cands; ++i){ mv_t rmv; mv_t mv[2]; rmv=cand_list[i]; // Vectors are normalised to 1 for pic1, which is always further away. This means that we get enough accuracy, as the nearest mvs will be smaller. mv[1].x = rmv.x; mv[1].y = rmv.y; mv[0] = scale_mv(rmv, -mv_data->wt[1], mv_data->wt[0]); uint32_t bcost=0; bcost = sad_cost(xstart, ystart, picdata, mv, size, bcost, best_cost); if (bcost<best_cost){ best_cost=bcost; best_mv=rmv; best_scaled_mv=mv[0]; } } mv1[yp*mv_data->bw+xp]=best_mv; mv0[yp*mv_data->bw+xp]=best_scaled_mv; mv_data->cost[0][yp*mv_data->bw+xp]=best_cost; mv_data->cost[1][yp*mv_data->bw+xp]=best_cost; }
static void upscale_mv_data_2x2(mv_data_t* mv_data_in, mv_data_t* mv_data_out) { assert(mv_data_in->ratio==mv_data_out->ratio); assert(mv_data_in->pos==mv_data_out->pos); assert(mv_data_in->wt[0]==mv_data_out->wt[0]); assert(mv_data_in->wt[1]==mv_data_out->wt[1]); int bwo=mv_data_out->bw; int bho=mv_data_out->bh; int bwi=mv_data_in->bw; memset(mv_data_out->mv[0], 0, sizeof(mv_t)*bwo*bho); memset(mv_data_out->mv[1], 0, sizeof(mv_t)*bwo*bho); for (int i=0; i<bho; ++i) { for (int j=0; j<bwo; ++j) { int po=i*bwo+j; int pi=(i/2)*bwi+(j/2); mv_data_out->mv[1][po].x=mv_data_in->mv[1][pi].x<<1; mv_data_out->mv[1][po].y=mv_data_in->mv[1][pi].y<<1; mv_data_out->mv[0][po]=scale_mv(mv_data_out->mv[1][po], -mv_data_out->wt[1], mv_data_out->wt[0]); } } }
static void make_skip_vector(mv_data_t* mv_data, int xp, int yp, int xstep, int ystep) { int bw=mv_data->bw; mv_data->skip_mv.x=0; mv_data->skip_mv.y=0; mv_t vlist[3]; int num=0; if (yp>0 && xp<bw-xstep) vlist[num++]=mv_data->mv[1][(yp-ystep)*bw+xp+xstep]; if (xp>0) vlist[num++]=mv_data->mv[1][yp*bw+xp-xstep]; if (yp>0) vlist[num++]=mv_data->mv[1][(yp-ystep)*bw+xp]; if (num) mv_data->skip_mv=mv_absdist_filter(vlist,num); mv_data->scaled_skip_mv=scale_mv(mv_data->skip_mv, -mv_data->wt[1], mv_data->wt[0]); }
static int get_cands(mv_data_t* mv_data, mv_t* cand_list, mv_data_t** guide_mv_data, int num_guides, int xp, int yp, int max_cands, int xstep, int ystep) { // Zero int len=0; mv_t zero={0,0}; int pos=yp*mv_data->bw+xp; len=add_cand(cand_list, max_cands, len, zero); for (int i=0; i<num_guides; ++i) { mv_data_t* gmv_data=guide_mv_data[i]; int numer=(mv_data->reversed==gmv_data->reversed)? mv_data->wt[0] : -mv_data->wt[0]; int denom=gmv_data->wt[0]; mv_t gmv; gmv = scale_mv(gmv_data->mv[1][pos], numer, denom); len=add_cand(cand_list, max_cands, len, gmv); // if (xp<mv_data->bw-xstep && yp<mv_data->bh-ystep) { // gmv = scale_mv(gmv_data->mv[1][pos+mv_data->bw*ystep+xstep], numer, denom); // len=add_cand(cand_list, max_cands, len, gmv); // } // if (xp<mv_data->bw-xstep) { // gmv = scale_mv(gmv_data->mv[1][pos+xstep], numer, denom); // len=add_cand(cand_list, max_cands, len, gmv); // } // if (yp<mv_data->bh-ystep) { // gmv = scale_mv(gmv_data->mv[1][pos+ystep*mv_data->bw], numer, denom); // len=add_cand(cand_list, max_cands, len, gmv); // } // } if (yp>0 && xp<mv_data->bw-xstep) { len=add_cand(cand_list, max_cands, len, mv_data->mv[1][(yp-ystep)*mv_data->bw+xp+xstep]); } // if (yp>0 && xp>0) { // len=add_cand(cand_list, max_cands, len, mv_data->mv[1][(yp-ystep)*mv_data->bw+xp-xstep]); // } if (xp>0) { len=add_cand(cand_list, max_cands, len, mv_data->mv[1][yp*mv_data->bw+xp-xstep]); } if (yp>0) { len=add_cand(cand_list, max_cands, len, mv_data->mv[1][(yp-ystep)*mv_data->bw+xp]); } return len; }
// This function searches the neighbourhood of a given MB/SB and populates a // list of candidate reference vectors. // void vp9_find_mv_refs( MACROBLOCKD *xd, MODE_INFO *here, MODE_INFO *lf_here, MV_REFERENCE_FRAME ref_frame, int_mv *mv_ref_list, int *ref_sign_bias ) { int i; MODE_INFO *candidate_mi; MB_MODE_INFO * mbmi = &xd->mode_info_context->mbmi; int_mv candidate_mvs[MAX_MV_REF_CANDIDATES]; int_mv c_refmv; int_mv c2_refmv; MV_REFERENCE_FRAME c_ref_frame; MV_REFERENCE_FRAME c2_ref_frame; int candidate_scores[MAX_MV_REF_CANDIDATES]; int index = 0; int split_count = 0; int (*mv_ref_search)[2]; int *ref_distance_weight; // Blank the reference vector lists and other local structures. vpx_memset(mv_ref_list, 0, sizeof(int_mv) * MAX_MV_REF_CANDIDATES); vpx_memset(candidate_mvs, 0, sizeof(int_mv) * MAX_MV_REF_CANDIDATES); vpx_memset(candidate_scores, 0, sizeof(candidate_scores)); if (mbmi->sb_type) { mv_ref_search = sb_mv_ref_search; ref_distance_weight = sb_ref_distance_weight; } else { mv_ref_search = mb_mv_ref_search; ref_distance_weight = mb_ref_distance_weight; } // We first scan for candidate vectors that match the current reference frame // Look at nearest neigbours for (i = 0; i < 2; ++i) { if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) && ((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) { candidate_mi = here + mv_ref_search[i][0] + (mv_ref_search[i][1] * xd->mode_info_stride); if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { clamp_mv(xd, &c_refmv); addmv_and_shuffle(candidate_mvs, candidate_scores, &index, c_refmv, ref_distance_weight[i] + 16); } split_count += (candidate_mi->mbmi.mode == SPLITMV); } } // Look in the last frame candidate_mi = lf_here; if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { clamp_mv(xd, &c_refmv); addmv_and_shuffle(candidate_mvs, candidate_scores, &index, c_refmv, 18); } // More distant neigbours for (i = 2; (i < MVREF_NEIGHBOURS) && (index < (MAX_MV_REF_CANDIDATES - 1)); ++i) { if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) && ((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) { candidate_mi = here + mv_ref_search[i][0] + (mv_ref_search[i][1] * xd->mode_info_stride); if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { clamp_mv(xd, &c_refmv); addmv_and_shuffle(candidate_mvs, candidate_scores, &index, c_refmv, ref_distance_weight[i] + 16); } } } // If we have not found enough candidates consider ones where the // reference frame does not match. Break out when we have // MAX_MV_REF_CANDIDATES candidates. // Look first at spatial neighbours if (index < (MAX_MV_REF_CANDIDATES - 1)) { for (i = 0; i < MVREF_NEIGHBOURS; ++i) { if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) && ((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) { candidate_mi = here + mv_ref_search[i][0] + (mv_ref_search[i][1] * xd->mode_info_stride); get_non_matching_candidates(candidate_mi, ref_frame, &c_ref_frame, &c_refmv, &c2_ref_frame, &c2_refmv); if (c_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias); addmv_and_shuffle(candidate_mvs, candidate_scores, &index, c_refmv, ref_distance_weight[i]); } if (c2_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias); addmv_and_shuffle(candidate_mvs, candidate_scores, &index, c2_refmv, ref_distance_weight[i]); } } if (index >= (MAX_MV_REF_CANDIDATES - 1)) { break; } } } // Look at the last frame if (index < (MAX_MV_REF_CANDIDATES - 1)) { candidate_mi = lf_here; get_non_matching_candidates(candidate_mi, ref_frame, &c_ref_frame, &c_refmv, &c2_ref_frame, &c2_refmv); if (c_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias); addmv_and_shuffle(candidate_mvs, candidate_scores, &index, c_refmv, 2); } if (c2_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias); addmv_and_shuffle(candidate_mvs, candidate_scores, &index, c2_refmv, 2); } } // Define inter mode coding context. // 0,0 was best if (candidate_mvs[0].as_int == 0) { // 0,0 is only candidate if (index <= 1) { mbmi->mb_mode_context[ref_frame] = 0; // non zero candidates candidates available } else if (split_count == 0) { mbmi->mb_mode_context[ref_frame] = 1; } else { mbmi->mb_mode_context[ref_frame] = 2; } // Non zero best, No Split MV cases } else if (split_count == 0) { if (candidate_scores[0] >= 32) { mbmi->mb_mode_context[ref_frame] = 3; } else { mbmi->mb_mode_context[ref_frame] = 4; } // Non zero best, some split mv } else { if (candidate_scores[0] >= 32) { mbmi->mb_mode_context[ref_frame] = 5; } else { mbmi->mb_mode_context[ref_frame] = 6; } } // 0,0 is always a valid reference. for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) { if (candidate_mvs[i].as_int == 0) break; } if (i == MAX_MV_REF_CANDIDATES) { candidate_mvs[MAX_MV_REF_CANDIDATES-1].as_int = 0; } // Copy over the candidate list. vpx_memcpy(mv_ref_list, candidate_mvs, sizeof(candidate_mvs)); }
static void adaptive_search_v2(mv_data_t* mv_data, int guided, mv_t * cand_list, int num_cands, yuv_frame_t* picdata[2], int xp, int yp, int xstep, int ystep) { // Do the search with the larger size, but data is stored at the smaller int xstart=xp*mv_data->bs; int ystart=yp*mv_data->bs; mv_t cross[4]; int size=mv_data->bbs; mv_t best_mv=cand_list[0]; mv_t best_scaled_mv; best_scaled_mv=scale_mv(best_mv, -mv_data->wt[1], mv_data->wt[0]); mv_t mv[2]; mv[1] = best_mv; mv[0] = best_scaled_mv; uint32_t best_cost=COST_MAX; mv_t cand_refine_list[MAX_CANDS]; mv_t cand_refine_scaled_list[MAX_CANDS]; uint32_t cand_best_costs[MAX_CANDS]; uint32_t lambda = guided ? LAMBDA/4 : LAMBDA; for (int c=0; c<num_cands; c++) { mv[1].x = cand_list[c].x; mv[1].y = cand_list[c].y; mv[0] = scale_mv(cand_list[c], -mv_data->wt[1], mv_data->wt[0]); cand_best_costs[c]=get_mv_cost(cand_list[c], mv_data, 1, xp, yp, xstep, ystep, lambda); cand_best_costs[c] = sad_cost(xstart, ystart, picdata, mv, size, cand_best_costs[c], COST_MAX); cand_refine_list[c]=mv[1]; cand_refine_scaled_list[c]=mv[0]; if ((((4+c)*cand_best_costs[c])/8) < best_cost) { int shift=guided ? 0+ACC_BITS : 3+ACC_BITS; int count=guided ? 8 : 64; while (shift>=ACC_BITS && count>0) { make_cross(cross, 1<<shift, cand_refine_list[c]); int better=0; for (int i=0; i<4; ++i) { mv_t rmv=cross[i]; mv[1].x = rmv.x; mv[1].y = rmv.y; mv[0] = scale_mv(rmv, -mv_data->wt[1], mv_data->wt[0]); uint32_t bcost=get_mv_cost(rmv, mv_data, 1, xp, yp, xstep, ystep, lambda); bcost = sad_cost(xstart, ystart, picdata, mv, size, bcost, cand_best_costs[c]); if (bcost<cand_best_costs[c]){ cand_best_costs[c]=bcost; cand_refine_list[c]=rmv; cand_refine_scaled_list[c]=mv[0]; better=1; } } if (!better) shift--; count -= 4; }; } if (cand_best_costs[c]<best_cost) { best_mv=cand_refine_list[c]; best_scaled_mv=cand_refine_scaled_list[c]; best_cost=cand_best_costs[c]; } } mv_data->mv[1][yp*mv_data->bw+xp]=best_mv; mv_data->mv[0][yp*mv_data->bw+xp]=best_scaled_mv; mv_data->cost[1][yp*mv_data->bw+xp]=best_cost; mv_data->cost[0][yp*mv_data->bw+xp]=best_cost; }