michael@0: /* michael@0: * Copyright (c) 2010 The WebM project authors. All Rights Reserved. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license michael@0: * that can be found in the LICENSE file in the root of the source michael@0: * tree. An additional intellectual property rights grant can be found michael@0: * in the file PATENTS. All contributing project authors may michael@0: * be found in the AUTHORS file in the root of the source tree. michael@0: */ michael@0: michael@0: michael@0: #include michael@0: #include "vpx_config.h" michael@0: #include "onyx_int.h" michael@0: #include "mr_dissim.h" michael@0: #include "vpx_mem/vpx_mem.h" michael@0: #include "rdopt.h" michael@0: michael@0: void vp8_cal_low_res_mb_cols(VP8_COMP *cpi) michael@0: { michael@0: int low_res_w; michael@0: michael@0: /* Support arbitrary down-sampling factor */ michael@0: unsigned int iw = cpi->oxcf.Width*cpi->oxcf.mr_down_sampling_factor.den michael@0: + cpi->oxcf.mr_down_sampling_factor.num - 1; michael@0: michael@0: low_res_w = iw/cpi->oxcf.mr_down_sampling_factor.num; michael@0: cpi->mr_low_res_mb_cols = ((low_res_w + 15) >> 4); michael@0: } michael@0: michael@0: #define GET_MV(x) \ michael@0: if(x->mbmi.ref_frame !=INTRA_FRAME) \ michael@0: { \ michael@0: mvx[cnt] = x->mbmi.mv.as_mv.row; \ michael@0: mvy[cnt] = x->mbmi.mv.as_mv.col; \ michael@0: cnt++; \ michael@0: } michael@0: michael@0: #define GET_MV_SIGN(x) \ michael@0: if(x->mbmi.ref_frame !=INTRA_FRAME) \ michael@0: { \ michael@0: mvx[cnt] = x->mbmi.mv.as_mv.row; \ michael@0: mvy[cnt] = x->mbmi.mv.as_mv.col; \ michael@0: if (cm->ref_frame_sign_bias[x->mbmi.ref_frame] \ michael@0: != cm->ref_frame_sign_bias[tmp->mbmi.ref_frame]) \ michael@0: { \ michael@0: mvx[cnt] *= -1; \ michael@0: mvy[cnt] *= -1; \ michael@0: } \ michael@0: cnt++; \ michael@0: } michael@0: michael@0: void vp8_cal_dissimilarity(VP8_COMP *cpi) michael@0: { michael@0: VP8_COMMON *cm = &cpi->common; michael@0: int i; michael@0: michael@0: /* Note: The first row & first column in mip are outside the frame, which michael@0: * were initialized to all 0.(ref_frame, mode, mv...) michael@0: * Their ref_frame = 0 means they won't be counted in the following michael@0: * calculation. michael@0: */ michael@0: if (cpi->oxcf.mr_total_resolutions >1 michael@0: && cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1)) michael@0: { michael@0: /* Store info for show/no-show frames for supporting alt_ref. michael@0: * If parent frame is alt_ref, child has one too. michael@0: */ michael@0: LOWER_RES_FRAME_INFO* store_info michael@0: = (LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info; michael@0: michael@0: store_info->frame_type = cm->frame_type; michael@0: michael@0: if(cm->frame_type != KEY_FRAME) michael@0: { michael@0: store_info->is_frame_dropped = 0; michael@0: for (i = 1; i < MAX_REF_FRAMES; i++) michael@0: store_info->low_res_ref_frames[i] = cpi->current_ref_frames[i]; michael@0: } michael@0: michael@0: if(cm->frame_type != KEY_FRAME) michael@0: { michael@0: int mb_row; michael@0: int mb_col; michael@0: /* Point to beginning of allocated MODE_INFO arrays. */ michael@0: MODE_INFO *tmp = cm->mip + cm->mode_info_stride; michael@0: LOWER_RES_MB_INFO* store_mode_info = store_info->mb_info; michael@0: michael@0: for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++) michael@0: { michael@0: tmp++; michael@0: for (mb_col = 0; mb_col < cm->mb_cols; mb_col ++) michael@0: { michael@0: int dissim = INT_MAX; michael@0: michael@0: if(tmp->mbmi.ref_frame !=INTRA_FRAME) michael@0: { michael@0: int mvx[8]; michael@0: int mvy[8]; michael@0: int mmvx; michael@0: int mmvy; michael@0: int cnt=0; michael@0: const MODE_INFO *here = tmp; michael@0: const MODE_INFO *above = here - cm->mode_info_stride; michael@0: const MODE_INFO *left = here - 1; michael@0: const MODE_INFO *aboveleft = above - 1; michael@0: const MODE_INFO *aboveright = NULL; michael@0: const MODE_INFO *right = NULL; michael@0: const MODE_INFO *belowleft = NULL; michael@0: const MODE_INFO *below = NULL; michael@0: const MODE_INFO *belowright = NULL; michael@0: michael@0: /* If alternate reference frame is used, we have to michael@0: * check sign of MV. */ michael@0: if(cpi->oxcf.play_alternate) michael@0: { michael@0: /* Gather mv of neighboring MBs */ michael@0: GET_MV_SIGN(above) michael@0: GET_MV_SIGN(left) michael@0: GET_MV_SIGN(aboveleft) michael@0: michael@0: if(mb_col < (cm->mb_cols-1)) michael@0: { michael@0: right = here + 1; michael@0: aboveright = above + 1; michael@0: GET_MV_SIGN(right) michael@0: GET_MV_SIGN(aboveright) michael@0: } michael@0: michael@0: if(mb_row < (cm->mb_rows-1)) michael@0: { michael@0: below = here + cm->mode_info_stride; michael@0: belowleft = below - 1; michael@0: GET_MV_SIGN(below) michael@0: GET_MV_SIGN(belowleft) michael@0: } michael@0: michael@0: if(mb_col < (cm->mb_cols-1) michael@0: && mb_row < (cm->mb_rows-1)) michael@0: { michael@0: belowright = below + 1; michael@0: GET_MV_SIGN(belowright) michael@0: } michael@0: }else michael@0: { michael@0: /* No alt_ref and gather mv of neighboring MBs */ michael@0: GET_MV(above) michael@0: GET_MV(left) michael@0: GET_MV(aboveleft) michael@0: michael@0: if(mb_col < (cm->mb_cols-1)) michael@0: { michael@0: right = here + 1; michael@0: aboveright = above + 1; michael@0: GET_MV(right) michael@0: GET_MV(aboveright) michael@0: } michael@0: michael@0: if(mb_row < (cm->mb_rows-1)) michael@0: { michael@0: below = here + cm->mode_info_stride; michael@0: belowleft = below - 1; michael@0: GET_MV(below) michael@0: GET_MV(belowleft) michael@0: } michael@0: michael@0: if(mb_col < (cm->mb_cols-1) michael@0: && mb_row < (cm->mb_rows-1)) michael@0: { michael@0: belowright = below + 1; michael@0: GET_MV(belowright) michael@0: } michael@0: } michael@0: michael@0: if (cnt > 0) michael@0: { michael@0: int max_mvx = mvx[0]; michael@0: int min_mvx = mvx[0]; michael@0: int max_mvy = mvy[0]; michael@0: int min_mvy = mvy[0]; michael@0: int i; michael@0: michael@0: if (cnt > 1) michael@0: { michael@0: for (i=1; i< cnt; i++) michael@0: { michael@0: if (mvx[i] > max_mvx) max_mvx = mvx[i]; michael@0: else if (mvx[i] < min_mvx) min_mvx = mvx[i]; michael@0: if (mvy[i] > max_mvy) max_mvy = mvy[i]; michael@0: else if (mvy[i] < min_mvy) min_mvy = mvy[i]; michael@0: } michael@0: } michael@0: michael@0: mmvx = MAX(abs(min_mvx - here->mbmi.mv.as_mv.row), michael@0: abs(max_mvx - here->mbmi.mv.as_mv.row)); michael@0: mmvy = MAX(abs(min_mvy - here->mbmi.mv.as_mv.col), michael@0: abs(max_mvy - here->mbmi.mv.as_mv.col)); michael@0: dissim = MAX(mmvx, mmvy); michael@0: } michael@0: } michael@0: michael@0: /* Store mode info for next resolution encoding */ michael@0: store_mode_info->mode = tmp->mbmi.mode; michael@0: store_mode_info->ref_frame = tmp->mbmi.ref_frame; michael@0: store_mode_info->mv.as_int = tmp->mbmi.mv.as_int; michael@0: store_mode_info->dissim = dissim; michael@0: tmp++; michael@0: store_mode_info++; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* This function is called only when this frame is dropped at current michael@0: resolution level. */ michael@0: void vp8_store_drop_frame_info(VP8_COMP *cpi) michael@0: { michael@0: /* If the frame is dropped in lower-resolution encoding, this information michael@0: is passed to higher resolution level so that the encoder knows there michael@0: is no mode & motion info available. michael@0: */ michael@0: if (cpi->oxcf.mr_total_resolutions >1 michael@0: && cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1)) michael@0: { michael@0: /* Store info for show/no-show frames for supporting alt_ref. michael@0: * If parent frame is alt_ref, child has one too. michael@0: */ michael@0: LOWER_RES_FRAME_INFO* store_info michael@0: = (LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info; michael@0: michael@0: /* Set frame_type to be INTER_FRAME since we won't drop key frame. */ michael@0: store_info->frame_type = INTER_FRAME; michael@0: store_info->is_frame_dropped = 1; michael@0: } michael@0: }