/* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. * See the License for the specific language governing permissions * and limitations under the License. * ------------------------------------------------------------------- */ #include "mp4def.h" #include "mp4enc_lib.h" #include "mp4lib_int.h" #include "m4venc_oscl.h" /* 3/29/01 fast half-pel search based on neighboring guess */ /* value ranging from 0 to 4, high complexity (more accurate) to low complexity (less accurate) */ #define HP_DISTANCE_TH 2 /* half-pel distance threshold */ #define PREF_16_VEC 129 /* 1MV bias versus 4MVs*/ #ifdef __cplusplus extern "C" { #endif void GenerateSearchRegion(UChar *searchPadding, UChar *ref, Int width, Int height, Int ilow, Int ihigh, Int jlow, Int jhigh); void InterpDiag(UChar *prev, Int lx, UChar *pred_block); void InterpHorz(UChar *prev, Int lx, UChar *pred_block); void InterpVert(UChar *prev, Int lx, UChar *pred_block); #ifdef __cplusplus } #endif const static Int distance_tab[9][9] = /* [hp_guess][k] */ { {0, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 1, 2, 3, 4, 3, 2, 1}, {1, 0, 0, 0, 1, 2, 3, 2, 1}, {1, 2, 1, 0, 1, 2, 3, 4, 3}, {1, 2, 1, 0, 0, 0, 1, 2, 3}, {1, 4, 3, 2, 1, 0, 1, 2, 3}, {1, 2, 3, 2, 1, 0, 0, 0, 1}, {1, 2, 3, 4, 3, 2, 1, 0, 1}, {1, 0, 1, 2, 3, 2, 1, 0, 0} }; /*===================================================================== Function: FindHalfPelMB Date: 10/7/2000 Purpose: Find half pel resolution MV surrounding the full-pel MV =====================================================================*/ void FindHalfPelMB(VideoEncData *video, UChar *cur, MOT *mot, UChar *ncand, Int xpos, Int ypos, Int *xhmin, Int *yhmin, Int hp_guess) { // hp_mem = ULong *vertArray; /* 20x17 */ // ULong *horzArray; /* 20x16 */ // ULong *diagArray; /* 20x17 */ Int dmin, d; Int xh, yh; Int k, kmin = 0; Int imin, jmin, ilow, jlow; Int h263_mode = video->encParams->H263_Enabled; /* 3/29/01 */ Int in_range[9] = {0, 1, 1, 1, 1, 1, 1, 1, 1}; /* 3/29/01 */ Int range = video->encParams->SearchRange; Int lx = video->currVop->pitch; Int width = video->currVop->width; /* padding */ Int height = video->vol[video->currLayer]->height; Int(**SAD_MB_HalfPel)(UChar*, UChar*, Int, void*) = video->functionPointer->SAD_MB_HalfPel; void *extra_info = video->sad_extra_info; Int next_hp_pos[9][2] = {{0, 0}, {2, 0}, {1, 1}, {0, 2}, { -1, 1}, { -2, 0}, { -1, -1}, {0, -2}, {0, -1}}; Int next_ncand[9] = {0, 1 , lx, lx, 0, -1, -1, -lx, -lx}; cur = video->currYMB; /**************** check range ***************************/ /* 3/29/01 */ imin = xpos + (mot[0].x >> 1); jmin = ypos + (mot[0].y >> 1); ilow = xpos - range; jlow = ypos - range; if (!h263_mode) { if (imin <= -15 || imin == ilow) in_range[1] = in_range[7] = in_range[8] = 0; else if (imin >= width - 1) in_range[3] = in_range[4] = in_range[5] = 0; if (jmin <= -15 || jmin == jlow) in_range[1] = in_range[2] = in_range[3] = 0; else if (jmin >= height - 1) in_range[5] = in_range[6] = in_range[7] = 0; } else { if (imin <= 0 || imin == ilow) in_range[1] = in_range[7] = in_range[8] = 0; else if (imin >= width - 16) in_range[3] = in_range[4] = in_range[5] = 0; if (jmin <= 0 || jmin == jlow) in_range[1] = in_range[2] = in_range[3] = 0; else if (jmin >= height - 16) in_range[5] = in_range[6] = in_range[7] = 0; } xhmin[0] = 0; yhmin[0] = 0; dmin = mot[0].sad; xh = 0; yh = -1; ncand -= lx; /* initial position */ for (k = 2; k <= 8; k += 2) { if (distance_tab[hp_guess][k] < HP_DISTANCE_TH) { if (in_range[k]) { d = (*(SAD_MB_HalfPel[((yh&1)<<1)+(xh&1)]))(ncand, cur, (dmin << 16) | lx, extra_info); if (d < dmin) { dmin = d; xhmin[0] = xh; yhmin[0] = yh; kmin = k; } else if (d == dmin && PV_ABS(mot[0].x + xh) + PV_ABS(mot[0].y + yh) < PV_ABS(mot[0].x + xhmin[0]) + PV_ABS(mot[0].y + yhmin[0])) { xhmin[0] = xh; yhmin[0] = yh; kmin = k; } } } xh += next_hp_pos[k][0]; yh += next_hp_pos[k][1]; ncand += next_ncand[k]; if (k == 8) { if (xhmin[0] != 0 || yhmin[0] != 0) { k = -1; hp_guess = kmin; } } } mot[0].sad = dmin; mot[0].x += xhmin[0]; mot[0].y += yhmin[0]; return ; } #ifndef NO_INTER4V /*===================================================================== Function: FindHalfPelBlk Date: 10/7/2000 Purpose: Find half pel resolution MV surrounding the full-pel MV And decide between 1MV or 4MV mode =====================================================================*/ ///// THIS FUNCTION IS NOT WORKING!!! NEED TO BE RIVISITED Int FindHalfPelBlk(VideoEncData *video, UChar *cur, MOT *mot, Int sad16, UChar *ncand8[], UChar *mode, Int xpos, Int ypos, Int *xhmin, Int *yhmin, UChar *hp_mem) { Int k, comp; Int xh, yh;//, xhmin, yhmin; Int imin, jmin, ilow, jlow; Int height; UChar *cand, *cur8; UChar *hmem;//[17*17]; /* half-pel memory */ Int d, dmin, sad8; Int lx = video->currVop->pitch; Int width = video->currVop->width; /* , padding */ Int(*SAD_Blk_HalfPel)(UChar*, UChar*, Int, Int, Int, Int, Int, void*) = video->functionPointer->SAD_Blk_HalfPel; void *extra_info = video->sad_extra_info; Int in_range[8]; /* 3/29/01 */ Int range = video->encParams->SearchRange; Int swidth; Int next_hp_pos[8][2] = {{1, 0}, {1, 0}, {0, 1}, {0, 1}, { -1, 0}, { -1, 0}, {0, -1}, {0, -1}}; height = video->vol[video->currLayer]->height; hmem = hp_mem; sad8 = 0; for (comp = 0; comp < 4; comp++) { #ifdef _SAD_STAT num_HP_Blk++; #endif /**************** check range ***************************/ /* 3/29/01 */ M4VENC_MEMSET(in_range, 1, sizeof(Int) << 3); imin = xpos + ((comp & 1) << 3) + (mot[comp+1].x >> 1); jmin = ypos + ((comp & 2) << 2) + (mot[comp+1].y >> 1); ilow = xpos + ((comp & 1) << 3) - range; jlow = ypos + ((comp & 2) << 2) - range; if (imin <= -15 || imin == ilow) in_range[0] = in_range[6] = in_range[7] = 0; else if (imin >= width - 1) in_range[2] = in_range[3] = in_range[4] = 0; if (jmin <= -15 || jmin == jlow) in_range[0] = in_range[1] = in_range[2] = 0; else if (jmin >= height - 1) in_range[4] = in_range[5] = in_range[6] = 0; /**************** half-pel search ***********************/ cur8 = cur + ((comp & 1) << 3) + ((comp & 2) << 2) * width ; /* generate half-pel search region */ { cand = ncand8[comp+1]; swidth = lx; } xhmin[comp+1] = 0; yhmin[comp+1] = 0; dmin = mot[comp+1].sad; xh = -1; yh = -1; for (k = 0; k < 8; k++) { if (in_range[k]) { d = (*SAD_Blk_HalfPel)(cand, cur8, dmin, lx, swidth, xh, yh, extra_info); if (d < dmin) { dmin = d; xhmin[comp+1] = xh; yhmin[comp+1] = yh; } } xh += next_hp_pos[k][0]; yh += next_hp_pos[k][1]; } /********************************************/ mot[comp+1].x += xhmin[comp+1]; mot[comp+1].y += yhmin[comp+1]; mot[comp+1].sad = dmin; sad8 += dmin; if (sad8 >= sad16 - PREF_16_VEC) { *mode = MODE_INTER; for (k = 1; k <= 4; k++) { mot[k].sad = (mot[0].sad + 2) >> 2; mot[k].x = mot[0].x; mot[k].y = mot[0].y; } return sad8; } hmem += (10 * 10); } *mode = MODE_INTER4V; return sad8; } #endif /* NO_INTER4V */