summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp')
-rw-r--r--media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp1741
1 files changed, 1741 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp
new file mode 100644
index 0000000..997b78d
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp
@@ -0,0 +1,1741 @@
+/* ------------------------------------------------------------------
+ * 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"
+
+//#define PRINT_MV
+#define MIN_GOP 1 /* minimum size of GOP, 1/23/01, need to be tested */
+
+#define CANDIDATE_DISTANCE 0 /* distance candidate from one another to consider as a distinct one */
+/* shouldn't be more than 3 */
+
+#define ZERO_MV_PREF 0 /* 0: bias (0,0)MV before full-pel search, lowest complexity*/
+/* 1: bias (0,0)MV after full-pel search, before half-pel, highest comp */
+/* 2: bias (0,0)MV after half-pel, high comp, better PSNR */
+
+#define RASTER_REFRESH /* instead of random INTRA refresh, do raster scan, 2/26/01 */
+
+#ifdef RASTER_REFRESH
+#define TARGET_REFRESH_PER_REGION 4 /* , no. MB per frame to be INTRA refreshed */
+#else
+#define TARGET_REFRESH_PER_REGION 1 /* , no. MB per region to be INTRA refreshed */
+#endif
+
+#define ALL_CAND_EQUAL 10 /* any number greater than 5 will work */
+
+#define NumPixelMB 256 /* number of pixels used in SAD calculation */
+
+#define DEF_8X8_WIN 3 /* search region for 8x8 MVs around the 16x16 MV */
+#define MB_Nb 256
+
+#define PREF_NULL_VEC 129 /* for zero vector bias */
+#define PREF_16_VEC 129 /* 1MV bias versus 4MVs*/
+#define PREF_INTRA 512 /* bias for INTRA coding */
+
+const static Int tab_exclude[9][9] = // [last_loc][curr_loc]
+{
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 1, 1, 1, 0, 0},
+ {0, 0, 0, 0, 1, 1, 1, 1, 1},
+ {0, 0, 0, 0, 0, 0, 1, 1, 1},
+ {0, 1, 1, 0, 0, 0, 1, 1, 1},
+ {0, 1, 1, 0, 0, 0, 0, 0, 1},
+ {0, 1, 1, 1, 1, 0, 0, 0, 1},
+ {0, 0, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 0, 0}
+}; //to decide whether to continue or compute
+
+const static Int refine_next[8][2] = /* [curr_k][increment] */
+{
+ {0, 0}, {2, 0}, {1, 1}, {0, 2}, { -1, 1}, { -2, 0}, { -1, -1}, {0, -2}
+};
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ void MBMotionSearch(VideoEncData *video, UChar *cur, UChar *best_cand[],
+ Int i0, Int j0, Int type_pred, Int fullsearch, Int *hp_guess);
+
+ Int fullsearch(VideoEncData *video, Vol *currVol, UChar *ref, UChar *cur,
+ Int *imin, Int *jmin, Int ilow, Int ihigh, Int jlow, Int jhigh);
+ Int fullsearchBlk(VideoEncData *video, Vol *currVol, UChar *cent, UChar *cur,
+ Int *imin, Int *jmin, Int ilow, Int ihigh, Int jlow, Int jhigh, Int range);
+ void CandidateSelection(Int *mvx, Int *mvy, Int *num_can, Int imb, Int jmb,
+ VideoEncData *video, Int type_pred);
+ void RasterIntraUpdate(UChar *intraArray, UChar *Mode, Int totalMB, Int numRefresh);
+ void ResetIntraUpdate(UChar *intraArray, Int totalMB);
+ void ResetIntraUpdateRegion(UChar *intraArray, Int start_i, Int rwidth,
+ Int start_j, Int rheight, Int mbwidth, Int mbheight);
+
+ void MoveNeighborSAD(Int dn[], Int new_loc);
+ Int FindMin(Int dn[]);
+ void PrepareCurMB(VideoEncData *video, UChar *cur);
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************/
+/* 2/28/01, for HYPOTHESIS TESTING */
+#ifdef HTFM /* defined in mp4def.h */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ void CalcThreshold(double pf, double exp_lamda[], Int nrmlz_th[]);
+ void HTFMPrepareCurMB(VideoEncData *video, HTFM_Stat *htfm_stat, UChar *cur);
+#ifdef __cplusplus
+}
+#endif
+
+
+#define HTFM_Pf 0.25 /* 3/2/1, probability of false alarm, can be varied from 0 to 0.5 */
+/***************************************/
+#endif
+
+#ifdef _SAD_STAT
+ULong num_MB = 0;
+ULong num_HP_MB = 0;
+ULong num_Blk = 0;
+ULong num_HP_Blk = 0;
+ULong num_cand = 0;
+ULong num_better_hp = 0;
+ULong i_dist_from_guess = 0;
+ULong j_dist_from_guess = 0;
+ULong num_hp_not_zero = 0;
+#endif
+
+
+
+/*==================================================================
+ Function: MotionEstimation
+ Date: 10/3/2000
+ Purpose: Go through all macroblock for motion search and
+ determine scene change detection.
+====================================================================*/
+
+void MotionEstimation(VideoEncData *video)
+{
+ UChar use_4mv = video->encParams->MV8x8_Enabled;
+ Vol *currVol = video->vol[video->currLayer];
+ Vop *currVop = video->currVop;
+ VideoEncFrameIO *currFrame = video->input;
+ Int i, j, comp;
+ Int mbwidth = currVol->nMBPerRow;
+ Int mbheight = currVol->nMBPerCol;
+ Int totalMB = currVol->nTotalMB;
+ Int width = currFrame->pitch;
+ UChar *mode_mb, *Mode = video->headerInfo.Mode;
+ MOT *mot_mb, **mot = video->mot;
+ UChar *intraArray = video->intraArray;
+ Int FS_en = video->encParams->FullSearch_Enabled;
+ void (*ComputeMBSum)(UChar *, Int, MOT *) = video->functionPointer->ComputeMBSum;
+ void (*ChooseMode)(UChar*, UChar*, Int, Int) = video->functionPointer->ChooseMode;
+
+ Int numIntra, start_i, numLoop, incr_i;
+ Int mbnum, offset;
+ UChar *cur, *best_cand[5];
+ Int sad8 = 0, sad16 = 0;
+ Int totalSAD = 0; /* average SAD for rate control */
+ Int skip_halfpel_4mv;
+ Int f_code_p, f_code_n, max_mag = 0, min_mag = 0;
+ Int type_pred;
+ Int xh[5] = {0, 0, 0, 0, 0};
+ Int yh[5] = {0, 0, 0, 0, 0}; /* half-pel */
+ UChar hp_mem4MV[17*17*4];
+
+#ifdef HTFM
+ /***** HYPOTHESIS TESTING ********/ /* 2/28/01 */
+ Int collect = 0;
+ HTFM_Stat htfm_stat;
+ double newvar[16];
+ double exp_lamda[15];
+ /*********************************/
+#endif
+ Int hp_guess = 0;
+#ifdef PRINT_MV
+ FILE *fp_debug;
+#endif
+
+// FILE *fstat;
+// static int frame_num = 0;
+
+ offset = 0;
+
+ if (video->currVop->predictionType == I_VOP)
+ { /* compute the SAV */
+ mbnum = 0;
+ cur = currFrame->yChan;
+
+ for (j = 0; j < mbheight; j++)
+ {
+ for (i = 0; i < mbwidth; i++)
+ {
+ video->mbnum = mbnum;
+ mot_mb = mot[mbnum];
+
+ (*ComputeMBSum)(cur + (i << 4), width, mot_mb);
+
+ totalSAD += mot_mb[0].sad;
+
+ mbnum++;
+ }
+ cur += (width << 4);
+ }
+
+ video->sumMAD = (float)totalSAD / (float)NumPixelMB;
+
+ ResetIntraUpdate(intraArray, totalMB);
+
+ return ;
+ }
+
+ /* 09/20/05 */
+ if (video->prevBaseVop->padded == 0 && !video->encParams->H263_Enabled)
+ {
+ PaddingEdge(video->prevBaseVop);
+ video->prevBaseVop->padded = 1;
+ }
+
+ /* Random INTRA update */
+ /* suggest to do it in CodeMB */
+ /* 2/21/2001 */
+ //if(video->encParams->RC_Type == CBR_1 || video->encParams->RC_Type == CBR_2)
+ if (video->currLayer == 0 && video->encParams->Refresh)
+ {
+ RasterIntraUpdate(intraArray, Mode, totalMB, video->encParams->Refresh);
+ }
+
+ video->sad_extra_info = NULL;
+
+#ifdef HTFM
+ /***** HYPOTHESIS TESTING ********/ /* 2/28/01 */
+ InitHTFM(video, &htfm_stat, newvar, &collect);
+ /*********************************/
+#endif
+
+ if ((video->encParams->SceneChange_Det == 1) /*&& video->currLayer==0 */
+ && ((video->encParams->LayerFrameRate[0] < 5.0) || (video->numVopsInGOP > MIN_GOP)))
+ /* do not try to detect a new scene if low frame rate and too close to previous I-frame */
+ {
+ incr_i = 2;
+ numLoop = 2;
+ start_i = 1;
+ type_pred = 0; /* for initial candidate selection */
+ }
+ else
+ {
+ incr_i = 1;
+ numLoop = 1;
+ start_i = 0;
+ type_pred = 2;
+ }
+
+ /* First pass, loop thru half the macroblock */
+ /* determine scene change */
+ /* Second pass, for the rest of macroblocks */
+ numIntra = 0;
+ while (numLoop--)
+ {
+ for (j = 0; j < mbheight; j++)
+ {
+ if (incr_i > 1)
+ start_i = (start_i == 0 ? 1 : 0) ; /* toggle 0 and 1 */
+
+ offset = width * (j << 4) + (start_i << 4);
+
+ mbnum = j * mbwidth + start_i;
+
+ for (i = start_i; i < mbwidth; i += incr_i)
+ {
+ video->mbnum = mbnum;
+ mot_mb = mot[mbnum];
+ mode_mb = Mode + mbnum;
+
+ cur = currFrame->yChan + offset;
+
+
+ if (*mode_mb != MODE_INTRA)
+ {
+#if defined(HTFM)
+ HTFMPrepareCurMB(video, &htfm_stat, cur);
+#else
+ PrepareCurMB(video, cur);
+#endif
+ /************************************************************/
+ /******** full-pel 1MV and 4MVs search **********************/
+
+#ifdef _SAD_STAT
+ num_MB++;
+#endif
+ MBMotionSearch(video, cur, best_cand, i << 4, j << 4, type_pred,
+ FS_en, &hp_guess);
+
+#ifdef PRINT_MV
+ fp_debug = fopen("c:\\bitstream\\mv1_debug.txt", "a");
+ fprintf(fp_debug, "#%d (%d,%d,%d) : ", mbnum, mot_mb[0].x, mot_mb[0].y, mot_mb[0].sad);
+ fprintf(fp_debug, "(%d,%d,%d) : (%d,%d,%d) : (%d,%d,%d) : (%d,%d,%d) : ==>\n",
+ mot_mb[1].x, mot_mb[1].y, mot_mb[1].sad,
+ mot_mb[2].x, mot_mb[2].y, mot_mb[2].sad,
+ mot_mb[3].x, mot_mb[3].y, mot_mb[3].sad,
+ mot_mb[4].x, mot_mb[4].y, mot_mb[4].sad);
+ fclose(fp_debug);
+#endif
+ sad16 = mot_mb[0].sad;
+#ifdef NO_INTER4V
+ sad8 = sad16;
+#else
+ sad8 = mot_mb[1].sad + mot_mb[2].sad + mot_mb[3].sad + mot_mb[4].sad;
+#endif
+
+ /* choose between INTRA or INTER */
+ (*ChooseMode)(mode_mb, cur, width, ((sad8 < sad16) ? sad8 : sad16));
+ }
+ else /* INTRA update, use for prediction 3/23/01 */
+ {
+ mot_mb[0].x = mot_mb[0].y = 0;
+ }
+
+ if (*mode_mb == MODE_INTRA)
+ {
+ numIntra++ ;
+
+ /* compute SAV for rate control and fast DCT, 11/28/00 */
+ (*ComputeMBSum)(cur, width, mot_mb);
+
+ /* leave mot_mb[0] as it is for fast motion search */
+ /* set the 4 MVs to zeros */
+ for (comp = 1; comp <= 4; comp++)
+ {
+ mot_mb[comp].x = 0;
+ mot_mb[comp].y = 0;
+ }
+#ifdef PRINT_MV
+ fp_debug = fopen("c:\\bitstream\\mv1_debug.txt", "a");
+ fprintf(fp_debug, "\n");
+ fclose(fp_debug);
+#endif
+ }
+ else /* *mode_mb = MODE_INTER;*/
+ {
+ if (video->encParams->HalfPel_Enabled)
+ {
+#ifdef _SAD_STAT
+ num_HP_MB++;
+#endif
+ /* find half-pel resolution motion vector */
+ FindHalfPelMB(video, cur, mot_mb, best_cand[0],
+ i << 4, j << 4, xh, yh, hp_guess);
+#ifdef PRINT_MV
+ fp_debug = fopen("c:\\bitstream\\mv1_debug.txt", "a");
+ fprintf(fp_debug, "(%d,%d), %d\n", mot_mb[0].x, mot_mb[0].y, mot_mb[0].sad);
+ fclose(fp_debug);
+#endif
+ skip_halfpel_4mv = ((sad16 - mot_mb[0].sad) <= (MB_Nb >> 1) + 1);
+ sad16 = mot_mb[0].sad;
+
+#ifndef NO_INTER4V
+ if (use_4mv && !skip_halfpel_4mv)
+ {
+ /* Also decide 1MV or 4MV !!!!!!!!*/
+ sad8 = FindHalfPelBlk(video, cur, mot_mb, sad16,
+ best_cand, mode_mb, i << 4, j << 4, xh, yh, hp_mem4MV);
+
+#ifdef PRINT_MV
+ fp_debug = fopen("c:\\bitstream\\mv1_debug.txt", "a");
+ fprintf(fp_debug, " (%d,%d,%d) : (%d,%d,%d) : (%d,%d,%d) : (%d,%d,%d) \n",
+ mot_mb[1].x, mot_mb[1].y, mot_mb[1].sad,
+ mot_mb[2].x, mot_mb[2].y, mot_mb[2].sad,
+ mot_mb[3].x, mot_mb[3].y, mot_mb[3].sad,
+ mot_mb[4].x, mot_mb[4].y, mot_mb[4].sad);
+ fclose(fp_debug);
+#endif
+ }
+#endif /* NO_INTER4V */
+ }
+ else /* HalfPel_Enabled ==0 */
+ {
+#ifndef NO_INTER4V
+ //if(sad16 < sad8-PREF_16_VEC)
+ if (sad16 - PREF_16_VEC > sad8)
+ {
+ *mode_mb = MODE_INTER4V;
+ }
+#endif
+ }
+#if (ZERO_MV_PREF==2) /* use mot_mb[7].sad as d0 computed in MBMotionSearch*/
+ /******************************************************/
+ if (mot_mb[7].sad - PREF_NULL_VEC < sad16 && mot_mb[7].sad - PREF_NULL_VEC < sad8)
+ {
+ mot_mb[0].sad = mot_mb[7].sad - PREF_NULL_VEC;
+ mot_mb[0].x = mot_mb[0].y = 0;
+ *mode_mb = MODE_INTER;
+ }
+ /******************************************************/
+#endif
+ if (*mode_mb == MODE_INTER)
+ {
+ if (mot_mb[0].x == 0 && mot_mb[0].y == 0) /* use zero vector */
+ mot_mb[0].sad += PREF_NULL_VEC; /* add back the bias */
+
+ mot_mb[1].sad = mot_mb[2].sad = mot_mb[3].sad = mot_mb[4].sad = (mot_mb[0].sad + 2) >> 2;
+ mot_mb[1].x = mot_mb[2].x = mot_mb[3].x = mot_mb[4].x = mot_mb[0].x;
+ mot_mb[1].y = mot_mb[2].y = mot_mb[3].y = mot_mb[4].y = mot_mb[0].y;
+
+ }
+ }
+
+ /* find maximum magnitude */
+ /* compute average SAD for rate control, 11/28/00 */
+ if (*mode_mb == MODE_INTER)
+ {
+#ifdef PRINT_MV
+ fp_debug = fopen("c:\\bitstream\\mv1_debug.txt", "a");
+ fprintf(fp_debug, "%d MODE_INTER\n", mbnum);
+ fclose(fp_debug);
+#endif
+ totalSAD += mot_mb[0].sad;
+ if (mot_mb[0].x > max_mag)
+ max_mag = mot_mb[0].x;
+ if (mot_mb[0].y > max_mag)
+ max_mag = mot_mb[0].y;
+ if (mot_mb[0].x < min_mag)
+ min_mag = mot_mb[0].x;
+ if (mot_mb[0].y < min_mag)
+ min_mag = mot_mb[0].y;
+ }
+ else if (*mode_mb == MODE_INTER4V)
+ {
+#ifdef PRINT_MV
+ fp_debug = fopen("c:\\bitstream\\mv1_debug.txt", "a");
+ fprintf(fp_debug, "%d MODE_INTER4V\n", mbnum);
+ fclose(fp_debug);
+#endif
+ totalSAD += sad8;
+ for (comp = 1; comp <= 4; comp++)
+ {
+ if (mot_mb[comp].x > max_mag)
+ max_mag = mot_mb[comp].x;
+ if (mot_mb[comp].y > max_mag)
+ max_mag = mot_mb[comp].y;
+ if (mot_mb[comp].x < min_mag)
+ min_mag = mot_mb[comp].x;
+ if (mot_mb[comp].y < min_mag)
+ min_mag = mot_mb[comp].y;
+ }
+ }
+ else /* MODE_INTRA */
+ {
+#ifdef PRINT_MV
+ fp_debug = fopen("c:\\bitstream\\mv1_debug.txt", "a");
+ fprintf(fp_debug, "%d MODE_INTRA\n", mbnum);
+ fclose(fp_debug);
+#endif
+ totalSAD += mot_mb[0].sad;
+ }
+ mbnum += incr_i;
+ offset += (incr_i << 4);
+
+ }
+ }
+
+ if (incr_i > 1 && numLoop) /* scene change on and first loop */
+ {
+ //if(numIntra > ((totalMB>>3)<<1) + (totalMB>>3)) /* 75% of 50%MBs */
+ if (numIntra > (0.30*(totalMB / 2.0))) /* 15% of 50%MBs */
+ {
+ /******** scene change detected *******************/
+ currVop->predictionType = I_VOP;
+ M4VENC_MEMSET(Mode, MODE_INTRA, sizeof(UChar)*totalMB); /* set this for MB level coding*/
+ currVop->quantizer = video->encParams->InitQuantIvop[video->currLayer];
+
+ /* compute the SAV for rate control & fast DCT */
+ totalSAD = 0;
+ offset = 0;
+ mbnum = 0;
+ cur = currFrame->yChan;
+
+ for (j = 0; j < mbheight; j++)
+ {
+ for (i = 0; i < mbwidth; i++)
+ {
+ video->mbnum = mbnum;
+ mot_mb = mot[mbnum];
+
+
+ (*ComputeMBSum)(cur + (i << 4), width, mot_mb);
+ totalSAD += mot_mb[0].sad;
+
+ mbnum++;
+ }
+ cur += (width << 4);
+ }
+
+ video->sumMAD = (float)totalSAD / (float)NumPixelMB;
+ ResetIntraUpdate(intraArray, totalMB);
+ /* video->numVopsInGOP=0; 3/13/01 move it to vop.c*/
+
+ return ;
+ }
+ }
+ /******** no scene change, continue motion search **********************/
+ start_i = 0;
+ type_pred++; /* second pass */
+ }
+
+ video->sumMAD = (float)totalSAD / (float)NumPixelMB; /* avg SAD */
+
+ /* find f_code , 10/27/2000 */
+ f_code_p = 1;
+ while ((max_mag >> (4 + f_code_p)) > 0)
+ f_code_p++;
+
+ f_code_n = 1;
+ min_mag *= -1;
+ while ((min_mag - 1) >> (4 + f_code_n) > 0)
+ f_code_n++;
+
+ currVop->fcodeForward = (f_code_p > f_code_n ? f_code_p : f_code_n);
+
+#ifdef HTFM
+ /***** HYPOTHESIS TESTING ********/ /* 2/28/01 */
+ if (collect)
+ {
+ collect = 0;
+ UpdateHTFM(video, newvar, exp_lamda, &htfm_stat);
+ }
+ /*********************************/
+#endif
+
+ return ;
+}
+
+
+#ifdef HTFM
+void InitHTFM(VideoEncData *video, HTFM_Stat *htfm_stat, double *newvar, Int *collect)
+{
+ Int i;
+ Int lx = video->currVop->width; // padding
+ Int lx2 = lx << 1;
+ Int lx3 = lx2 + lx;
+ Int rx = video->currVop->pitch;
+ Int rx2 = rx << 1;
+ Int rx3 = rx2 + rx;
+
+ Int *offset, *offset2;
+
+ /* 4/11/01, collect data every 30 frames, doesn't have to be base layer */
+ if (((Int)video->numVopsInGOP) % 30 == 1)
+ {
+
+ *collect = 1;
+
+ htfm_stat->countbreak = 0;
+ htfm_stat->abs_dif_mad_avg = 0;
+
+ for (i = 0; i < 16; i++)
+ {
+ newvar[i] = 0.0;
+ }
+// video->functionPointer->SAD_MB_PADDING = &SAD_MB_PADDING_HTFM_Collect;
+ video->functionPointer->SAD_Macroblock = &SAD_MB_HTFM_Collect;
+ video->functionPointer->SAD_MB_HalfPel[0] = NULL;
+ video->functionPointer->SAD_MB_HalfPel[1] = &SAD_MB_HP_HTFM_Collectxh;
+ video->functionPointer->SAD_MB_HalfPel[2] = &SAD_MB_HP_HTFM_Collectyh;
+ video->functionPointer->SAD_MB_HalfPel[3] = &SAD_MB_HP_HTFM_Collectxhyh;
+ video->sad_extra_info = (void*)(htfm_stat);
+ offset = htfm_stat->offsetArray;
+ offset2 = htfm_stat->offsetRef;
+ }
+ else
+ {
+// video->functionPointer->SAD_MB_PADDING = &SAD_MB_PADDING_HTFM;
+ video->functionPointer->SAD_Macroblock = &SAD_MB_HTFM;
+ video->functionPointer->SAD_MB_HalfPel[0] = NULL;
+ video->functionPointer->SAD_MB_HalfPel[1] = &SAD_MB_HP_HTFMxh;
+ video->functionPointer->SAD_MB_HalfPel[2] = &SAD_MB_HP_HTFMyh;
+ video->functionPointer->SAD_MB_HalfPel[3] = &SAD_MB_HP_HTFMxhyh;
+ video->sad_extra_info = (void*)(video->nrmlz_th);
+ offset = video->nrmlz_th + 16;
+ offset2 = video->nrmlz_th + 32;
+ }
+
+ offset[0] = 0;
+ offset[1] = lx2 + 2;
+ offset[2] = 2;
+ offset[3] = lx2;
+ offset[4] = lx + 1;
+ offset[5] = lx3 + 3;
+ offset[6] = lx + 3;
+ offset[7] = lx3 + 1;
+ offset[8] = lx;
+ offset[9] = lx3 + 2;
+ offset[10] = lx3 ;
+ offset[11] = lx + 2 ;
+ offset[12] = 1;
+ offset[13] = lx2 + 3;
+ offset[14] = lx2 + 1;
+ offset[15] = 3;
+
+ offset2[0] = 0;
+ offset2[1] = rx2 + 2;
+ offset2[2] = 2;
+ offset2[3] = rx2;
+ offset2[4] = rx + 1;
+ offset2[5] = rx3 + 3;
+ offset2[6] = rx + 3;
+ offset2[7] = rx3 + 1;
+ offset2[8] = rx;
+ offset2[9] = rx3 + 2;
+ offset2[10] = rx3 ;
+ offset2[11] = rx + 2 ;
+ offset2[12] = 1;
+ offset2[13] = rx2 + 3;
+ offset2[14] = rx2 + 1;
+ offset2[15] = 3;
+
+ return ;
+}
+
+void UpdateHTFM(VideoEncData *video, double *newvar, double *exp_lamda, HTFM_Stat *htfm_stat)
+{
+ if (htfm_stat->countbreak == 0)
+ htfm_stat->countbreak = 1;
+
+ newvar[0] = (double)(htfm_stat->abs_dif_mad_avg) / (htfm_stat->countbreak * 16.);
+
+ if (newvar[0] < 0.001)
+ {
+ newvar[0] = 0.001; /* to prevent floating overflow */
+ }
+ exp_lamda[0] = 1 / (newvar[0] * 1.4142136);
+ exp_lamda[1] = exp_lamda[0] * 1.5825;
+ exp_lamda[2] = exp_lamda[0] * 2.1750;
+ exp_lamda[3] = exp_lamda[0] * 3.5065;
+ exp_lamda[4] = exp_lamda[0] * 3.1436;
+ exp_lamda[5] = exp_lamda[0] * 3.5315;
+ exp_lamda[6] = exp_lamda[0] * 3.7449;
+ exp_lamda[7] = exp_lamda[0] * 4.5854;
+ exp_lamda[8] = exp_lamda[0] * 4.6191;
+ exp_lamda[9] = exp_lamda[0] * 5.4041;
+ exp_lamda[10] = exp_lamda[0] * 6.5974;
+ exp_lamda[11] = exp_lamda[0] * 10.5341;
+ exp_lamda[12] = exp_lamda[0] * 10.0719;
+ exp_lamda[13] = exp_lamda[0] * 12.0516;
+ exp_lamda[14] = exp_lamda[0] * 15.4552;
+
+ CalcThreshold(HTFM_Pf, exp_lamda, video->nrmlz_th);
+ return ;
+}
+
+
+void CalcThreshold(double pf, double exp_lamda[], Int nrmlz_th[])
+{
+ Int i;
+ double temp[15];
+ // printf("\nLamda: ");
+
+ /* parametric PREMODELling */
+ for (i = 0; i < 15; i++)
+ {
+ // printf("%g ",exp_lamda[i]);
+ if (pf < 0.5)
+ temp[i] = 1 / exp_lamda[i] * M4VENC_LOG(2 * pf);
+ else
+ temp[i] = -1 / exp_lamda[i] * M4VENC_LOG(2 * (1 - pf));
+ }
+
+ nrmlz_th[15] = 0;
+ for (i = 0; i < 15; i++) /* scale upto no.pixels */
+ nrmlz_th[i] = (Int)(temp[i] * ((i + 1) << 4) + 0.5);
+
+ return ;
+}
+
+void HTFMPrepareCurMB(VideoEncData *video, HTFM_Stat *htfm_stat, UChar *cur)
+{
+ void* tmp = (void*)(video->currYMB);
+ ULong *htfmMB = (ULong*)tmp;
+ UChar *ptr, byte;
+ Int *offset;
+ Int i;
+ ULong word;
+ Int width = video->currVop->width;
+
+ if (((Int)video->numVopsInGOP) % 30 == 1)
+ {
+ offset = htfm_stat->offsetArray;
+ }
+ else
+ {
+ offset = video->nrmlz_th + 16;
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ ptr = cur + offset[i];
+ word = ptr[0];
+ byte = ptr[4];
+ word |= (byte << 8);
+ byte = ptr[8];
+ word |= (byte << 16);
+ byte = ptr[12];
+ word |= (byte << 24);
+ *htfmMB++ = word;
+
+ word = *(ptr += (width << 2));
+ byte = ptr[4];
+ word |= (byte << 8);
+ byte = ptr[8];
+ word |= (byte << 16);
+ byte = ptr[12];
+ word |= (byte << 24);
+ *htfmMB++ = word;
+
+ word = *(ptr += (width << 2));
+ byte = ptr[4];
+ word |= (byte << 8);
+ byte = ptr[8];
+ word |= (byte << 16);
+ byte = ptr[12];
+ word |= (byte << 24);
+ *htfmMB++ = word;
+
+ word = *(ptr += (width << 2));
+ byte = ptr[4];
+ word |= (byte << 8);
+ byte = ptr[8];
+ word |= (byte << 16);
+ byte = ptr[12];
+ word |= (byte << 24);
+ *htfmMB++ = word;
+ }
+
+ return ;
+}
+
+
+#endif
+
+void PrepareCurMB(VideoEncData *video, UChar *cur)
+{
+ void* tmp = (void*)(video->currYMB);
+ ULong *currYMB = (ULong*)tmp;
+ Int i;
+ Int width = video->currVop->width;
+
+ cur -= width;
+
+ for (i = 0; i < 16; i++)
+ {
+ *currYMB++ = *((ULong*)(cur += width));
+ *currYMB++ = *((ULong*)(cur + 4));
+ *currYMB++ = *((ULong*)(cur + 8));
+ *currYMB++ = *((ULong*)(cur + 12));
+ }
+
+ return ;
+}
+
+
+/*==================================================================
+ Function: MBMotionSearch
+ Date: 09/06/2000
+ Purpose: Perform motion estimation for a macroblock.
+ Find 1MV and 4MVs in half-pels resolutions.
+ Using ST1 algorithm provided by Chalidabhongse and Kuo
+ CSVT March'98.
+
+==================================================================*/
+
+void MBMotionSearch(VideoEncData *video, UChar *cur, UChar *best_cand[],
+ Int i0, Int j0, Int type_pred, Int FS_en, Int *hp_guess)
+{
+ Vol *currVol = video->vol[video->currLayer];
+ UChar *ref, *cand, *ncand = NULL, *cur8;
+ void *extra_info = video->sad_extra_info;
+ Int mbnum = video->mbnum;
+ Int width = video->currVop->width; /* 6/12/01, must be multiple of 16 */
+ Int height = video->currVop->height;
+ MOT **mot = video->mot;
+ UChar use_4mv = video->encParams->MV8x8_Enabled;
+ UChar h263_mode = video->encParams->H263_Enabled;
+ Int(*SAD_Macroblock)(UChar*, UChar*, Int, void*) = video->functionPointer->SAD_Macroblock;
+ Int(*SAD_Block)(UChar*, UChar*, Int, Int, void*) = video->functionPointer->SAD_Block;
+ VideoEncParams *encParams = video->encParams;
+ Int range = encParams->SearchRange;
+
+ Int lx = video->currVop->pitch; /* padding */
+ Int comp;
+ Int i, j, imin, jmin, ilow, ihigh, jlow, jhigh, iorg, jorg;
+ Int d, dmin, dn[9];
+#if (ZERO_MV_PREF==1) /* compute (0,0) MV at the end */
+ Int d0;
+#endif
+ Int k;
+ Int mvx[5], mvy[5], imin0, jmin0;
+ Int num_can, center_again;
+ Int last_loc, new_loc = 0;
+ Int step, max_step = range >> 1;
+ Int next;
+
+ ref = video->forwardRefVop->yChan; /* origin of actual frame */
+
+ cur = video->currYMB; /* use smaller memory space for current MB */
+
+ /* find limit of the search (adjusting search range)*/
+
+ if (!h263_mode)
+ {
+ ilow = i0 - range;
+ if (ilow < -15)
+ ilow = -15;
+ ihigh = i0 + range - 1;
+ if (ihigh > width - 1)
+ ihigh = width - 1;
+ jlow = j0 - range;
+ if (jlow < -15)
+ jlow = -15;
+ jhigh = j0 + range - 1;
+ if (jhigh > height - 1)
+ jhigh = height - 1;
+ }
+ else
+ {
+ ilow = i0 - range;
+ if (ilow < 0)
+ ilow = 0;
+ ihigh = i0 + range - 1;
+ if (ihigh > width - 16)
+ ihigh = width - 16;
+ jlow = j0 - range;
+ if (jlow < 0)
+ jlow = 0;
+ jhigh = j0 + range - 1;
+ if (jhigh > height - 16)
+ jhigh = height - 16;
+ }
+
+ imin = i0;
+ jmin = j0; /* needed for fullsearch */
+ ncand = ref + imin + jmin * lx;
+
+ /* for first row of MB, fullsearch can be used */
+ if (FS_en)
+ {
+ *hp_guess = 0; /* no guess for fast half-pel */
+
+ dmin = fullsearch(video, currVol, ref, cur, &imin, &jmin, ilow, ihigh, jlow, jhigh);
+
+ ncand = ref + imin + jmin * lx;
+
+ mot[mbnum][0].sad = dmin;
+ mot[mbnum][0].x = (imin - i0) << 1;
+ mot[mbnum][0].y = (jmin - j0) << 1;
+ imin0 = imin << 1; /* 16x16 MV in half-pel resolution */
+ jmin0 = jmin << 1;
+ best_cand[0] = ncand;
+ }
+ else
+ { /* 4/7/01, modified this testing for fullsearch the top row to only upto (0,3) MB */
+ /* upto 30% complexity saving with the same complexity */
+ if (video->forwardRefVop->predictionType == I_VOP && j0 == 0 && i0 <= 64 && type_pred != 1)
+ {
+ *hp_guess = 0; /* no guess for fast half-pel */
+ dmin = fullsearch(video, currVol, ref, cur, &imin, &jmin, ilow, ihigh, jlow, jhigh);
+ ncand = ref + imin + jmin * lx;
+ }
+ else
+ {
+ /************** initialize candidate **************************/
+ /* find initial motion vector */
+ CandidateSelection(mvx, mvy, &num_can, i0 >> 4, j0 >> 4, video, type_pred);
+
+ dmin = 65535;
+
+ /* check if all are equal */
+ if (num_can == ALL_CAND_EQUAL)
+ {
+ i = i0 + mvx[0];
+ j = j0 + mvy[0];
+
+ if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+ {
+ cand = ref + i + j * lx;
+
+ d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+
+ if (d < dmin)
+ {
+ dmin = d;
+ imin = i;
+ jmin = j;
+ ncand = cand;
+ }
+ }
+ }
+ else
+ {
+ /************** evaluate unique candidates **********************/
+ for (k = 0; k < num_can; k++)
+ {
+ i = i0 + mvx[k];
+ j = j0 + mvy[k];
+
+ if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+ {
+ cand = ref + i + j * lx;
+ d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+
+ if (d < dmin)
+ {
+ dmin = d;
+ imin = i;
+ jmin = j;
+ ncand = cand;
+ }
+ else if ((d == dmin) && PV_ABS(mvx[k]) + PV_ABS(mvy[k]) < PV_ABS(i0 - imin) + PV_ABS(j0 - jmin))
+ {
+ dmin = d;
+ imin = i;
+ jmin = j;
+ ncand = cand;
+ }
+ }
+ }
+ }
+ if (num_can == 0 || dmin == 65535) /* no candidate selected */
+ {
+ ncand = ref + i0 + j0 * lx; /* use (0,0) MV as initial value */
+ mot[mbnum][7].sad = dmin = (*SAD_Macroblock)(ncand, cur, (65535 << 16) | lx, extra_info);
+#if (ZERO_MV_PREF==1) /* compute (0,0) MV at the end */
+ d0 = dmin;
+#endif
+ imin = i0;
+ jmin = j0;
+ }
+
+#if (ZERO_MV_PREF==0) /* COMPUTE ZERO VECTOR FIRST !!!!!*/
+ dmin -= PREF_NULL_VEC;
+#endif
+
+ /******************* local refinement ***************************/
+ center_again = 0;
+ last_loc = new_loc = 0;
+ // ncand = ref + jmin*lx + imin; /* center of the search */
+ step = 0;
+ dn[0] = dmin;
+ while (!center_again && step <= max_step)
+ {
+
+ MoveNeighborSAD(dn, last_loc);
+
+ center_again = 1;
+ i = imin;
+ j = jmin - 1;
+ cand = ref + i + j * lx;
+
+ /* starting from [0,-1] */
+ /* spiral check one step at a time*/
+ for (k = 2; k <= 8; k += 2)
+ {
+ if (!tab_exclude[last_loc][k]) /* exclude last step computation */
+ { /* not already computed */
+ if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+ {
+ d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+ dn[k] = d; /* keep it for half pel use */
+
+ if (d < dmin)
+ {
+ ncand = cand;
+ dmin = d;
+ imin = i;
+ jmin = j;
+ center_again = 0;
+ new_loc = k;
+ }
+ else if ((d == dmin) && PV_ABS(i0 - i) + PV_ABS(j0 - j) < PV_ABS(i0 - imin) + PV_ABS(j0 - jmin))
+ {
+ ncand = cand;
+ imin = i;
+ jmin = j;
+ center_again = 0;
+ new_loc = k;
+ }
+ }
+ }
+ if (k == 8) /* end side search*/
+ {
+ if (!center_again)
+ {
+ k = -1; /* start diagonal search */
+ cand -= lx;
+ j--;
+ }
+ }
+ else
+ {
+ next = refine_next[k][0];
+ i += next;
+ cand += next;
+ next = refine_next[k][1];
+ j += next;
+ cand += lx * next;
+ }
+ }
+ last_loc = new_loc;
+ step ++;
+ }
+ if (!center_again)
+ MoveNeighborSAD(dn, last_loc);
+
+ *hp_guess = FindMin(dn);
+
+ }
+
+#if (ZERO_MV_PREF==1) /* compute (0,0) MV at the end */
+ if (d0 - PREF_NULL_VEC < dmin)
+ {
+ ncand = ref + i0 + j0 * lx;
+ dmin = d0;
+ imin = i0;
+ jmin = j0;
+ }
+#endif
+ mot[mbnum][0].sad = dmin;
+ mot[mbnum][0].x = (imin - i0) << 1;
+ mot[mbnum][0].y = (jmin - j0) << 1;
+ imin0 = imin << 1; /* 16x16 MV in half-pel resolution */
+ jmin0 = jmin << 1;
+ best_cand[0] = ncand;
+ }
+ /* imin and jmin is the best 1 MV */
+#ifndef NO_INTER4V
+ /******************* Find 4 motion vectors ****************************/
+ if (use_4mv && !h263_mode)
+ {
+#ifdef _SAD_STAT
+ num_Blk += 4;
+#endif
+ /* starting from the best 1MV */
+ //offset = imin + jmin*lx;
+ iorg = i0;
+ jorg = j0;
+
+ for (comp = 0; comp < 4; comp++)
+ {
+ i0 = iorg + ((comp & 1) << 3);
+ j0 = jorg + ((comp & 2) << 2);
+
+ imin = (imin0 >> 1) + ((comp & 1) << 3); /* starting point from 16x16 MV */
+ jmin = (jmin0 >> 1) + ((comp & 2) << 2);
+ ncand = ref + imin + jmin * lx;
+
+ cur8 = cur + ((comp & 1) << 3) + (((comp & 2) << 2) << 4) ; /* 11/30/05, smaller cache */
+
+ /* find limit of the search (adjusting search range)*/
+ ilow = i0 - range;
+ ihigh = i0 + range - 1 ;/* 4/9/01 */
+ if (ilow < -15)
+ ilow = -15;
+ if (ihigh > width - 1)
+ ihigh = width - 1;
+ jlow = j0 - range;
+ jhigh = j0 + range - 1 ;/* 4/9/01 */
+ if (jlow < -15)
+ jlow = -15;
+ if (jhigh > height - 1)
+ jhigh = height - 1;
+
+ SAD_Block = video->functionPointer->SAD_Block;
+
+ if (FS_en) /* fullsearch enable, center around 16x16 MV */
+ {
+ dmin = fullsearchBlk(video, currVol, ncand, cur8, &imin, &jmin, ilow, ihigh, jlow, jhigh, range);
+ ncand = ref + imin + jmin * lx;
+
+ mot[mbnum][comp+1].sad = dmin;
+ mot[mbnum][comp+1].x = (imin - i0) << 1;
+ mot[mbnum][comp+1].y = (jmin - j0) << 1;
+ best_cand[comp+1] = ncand;
+ }
+ else /* no fullsearch, do local search */
+ {
+ /* starting point from 16x16 */
+ dmin = (*SAD_Block)(ncand, cur8, 65536, lx, extra_info);
+
+ /******************* local refinement ***************************/
+ center_again = 0;
+ last_loc = 0;
+
+ while (!center_again)
+ {
+ center_again = 1;
+ i = imin;
+ j = jmin - 1;
+ cand = ref + i + j * lx;
+
+ /* starting from [0,-1] */
+ /* spiral check one step at a time*/
+ for (k = 2; k <= 8; k += 2)
+ {
+ if (!tab_exclude[last_loc][k]) /* exclude last step computation */
+ { /* not already computed */
+ if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+ {
+ d = (*SAD_Block)(cand, cur8, dmin, lx, extra_info);
+
+ if (d < dmin)
+ {
+ ncand = cand;
+ dmin = d;
+ imin = i;
+ jmin = j;
+ center_again = 0;
+ new_loc = k;
+ }
+ else if ((d == dmin) &&
+ PV_ABS(i0 - i) + PV_ABS(j0 - j) < PV_ABS(i0 - imin) + PV_ABS(j0 - jmin))
+ {
+ ncand = cand;
+ imin = i;
+ jmin = j;
+ center_again = 0;
+ new_loc = k;
+ }
+ }
+ }
+ if (k == 8) /* end side search*/
+ {
+ if (!center_again)
+ {
+ k = -1; /* start diagonal search */
+ if (j <= height - 1 && j > 0) cand -= lx;
+ j--;
+ }
+ }
+ else
+ {
+ next = refine_next[k][0];
+ cand += next;
+ i += next;
+ next = refine_next[k][1];
+ cand += lx * next;
+ j += next;
+ }
+ }
+ last_loc = new_loc;
+ }
+ mot[mbnum][comp+1].sad = dmin;
+ mot[mbnum][comp+1].x = (imin - i0) << 1;
+ mot[mbnum][comp+1].y = (jmin - j0) << 1;
+ best_cand[comp+1] = ncand;
+ }
+ /********************************************/
+ }
+ }
+ else
+#endif /* NO_INTER4V */
+ {
+ mot[mbnum][1].sad = mot[mbnum][2].sad = mot[mbnum][3].sad = mot[mbnum][4].sad = (dmin + 2) >> 2;
+ mot[mbnum][1].x = mot[mbnum][2].x = mot[mbnum][3].x = mot[mbnum][4].x = mot[mbnum][0].x;
+ mot[mbnum][1].y = mot[mbnum][2].y = mot[mbnum][3].y = mot[mbnum][4].y = mot[mbnum][0].y;
+ best_cand[1] = best_cand[2] = best_cand[3] = best_cand[4] = ncand;
+
+ }
+ return ;
+}
+
+
+/*===============================================================================
+ Function: fullsearch
+ Date: 09/16/2000
+ Purpose: Perform full-search motion estimation over the range of search
+ region in a spiral-outward manner.
+ Input/Output: VideoEncData, current Vol, previou Vop, pointer to the left corner of
+ current VOP, current coord (also output), boundaries.
+===============================================================================*/
+
+Int fullsearch(VideoEncData *video, Vol *currVol, UChar *prev, UChar *cur,
+ Int *imin, Int *jmin, Int ilow, Int ihigh, Int jlow, Int jhigh)
+{
+ Int range = video->encParams->SearchRange;
+ UChar *cand;
+ Int i, j, k, l;
+ Int d, dmin;
+ Int i0 = *imin; /* current position */
+ Int j0 = *jmin;
+ Int(*SAD_Macroblock)(UChar*, UChar*, Int, void*) = video->functionPointer->SAD_Macroblock;
+ void *extra_info = video->sad_extra_info;
+// UChar h263_mode = video->encParams->H263_Enabled;
+ Int lx = video->currVop->pitch; /* with padding */
+
+ Int offset = i0 + j0 * lx;
+
+ OSCL_UNUSED_ARG(currVol);
+
+ cand = prev + offset;
+
+ dmin = (*SAD_Macroblock)(cand, cur, (65535 << 16) | lx, (void*)extra_info) - PREF_NULL_VEC;
+
+ /* perform spiral search */
+ for (k = 1; k <= range; k++)
+ {
+
+ i = i0 - k;
+ j = j0 - k;
+
+ cand = prev + i + j * lx;
+
+ for (l = 0; l < 8*k; l++)
+ {
+ /* no need for boundary checking again */
+ if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+ {
+ d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, (void*)extra_info);
+
+ if (d < dmin)
+ {
+ dmin = d;
+ *imin = i;
+ *jmin = j;
+ }
+ else if ((d == dmin) && PV_ABS(i0 - i) + PV_ABS(j0 - j) < PV_ABS(i0 - *imin) + PV_ABS(j0 - *jmin))
+ {
+ dmin = d;
+ *imin = i;
+ *jmin = j;
+ }
+ }
+
+ if (l < (k << 1))
+ {
+ i++;
+ cand++;
+ }
+ else if (l < (k << 2))
+ {
+ j++;
+ cand += lx;
+ }
+ else if (l < ((k << 2) + (k << 1)))
+ {
+ i--;
+ cand--;
+ }
+ else
+ {
+ j--;
+ cand -= lx;
+ }
+ }
+ }
+
+ return dmin;
+}
+
+#ifndef NO_INTER4V
+/*===============================================================================
+ Function: fullsearchBlk
+ Date: 01/9/2001
+ Purpose: Perform full-search motion estimation of an 8x8 block over the range
+ of search region in a spiral-outward manner centered at the 16x16 MV.
+ Input/Output: VideoEncData, MB coordinate, pointer to the initial MV on the
+ reference, pointer to coor of current block, search range.
+===============================================================================*/
+Int fullsearchBlk(VideoEncData *video, Vol *currVol, UChar *cent, UChar *cur,
+ Int *imin, Int *jmin, Int ilow, Int ihigh, Int jlow, Int jhigh, Int range)
+{
+ UChar *cand, *ref;
+ Int i, j, k, l, istart, jstart;
+ Int d, dmin;
+ Int lx = video->currVop->pitch; /* with padding */
+ Int(*SAD_Block)(UChar*, UChar*, Int, Int, void*) = video->functionPointer->SAD_Block;
+ void *extra_info = video->sad_extra_info;
+
+ OSCL_UNUSED_ARG(currVol);
+
+ /* starting point centered at 16x16 MV */
+ ref = cent;
+ istart = *imin;
+ jstart = *jmin;
+
+ dmin = (*SAD_Block)(ref, cur, 65536, lx, (void*)extra_info);
+
+ cand = ref;
+ /* perform spiral search */
+ for (k = 1; k <= range; k++)
+ {
+
+ i = istart - k;
+ j = jstart - k;
+ cand -= (lx + 1); /* candidate region */
+
+ for (l = 0; l < 8*k; l++)
+ {
+ /* no need for boundary checking again */
+ if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+ {
+ d = (*SAD_Block)(cand, cur, dmin, lx, (void*)extra_info);
+
+ if (d < dmin)
+ {
+ dmin = d;
+ *imin = i;
+ *jmin = j;
+ }
+ else if ((d == dmin) &&
+ PV_ABS(istart - i) + PV_ABS(jstart - j) < PV_ABS(istart - *imin) + PV_ABS(jstart - *jmin))
+ {
+ dmin = d;
+ *imin = i;
+ *jmin = j;
+ }
+ }
+
+ if (l < (k << 1))
+ {
+ i++;
+ cand++;
+ }
+ else if (l < (k << 2))
+ {
+ j++;
+ cand += lx;
+ }
+ else if (l < ((k << 2) + (k << 1)))
+ {
+ i--;
+ cand--;
+ }
+ else
+ {
+ j--;
+ cand -= lx;
+ }
+ }
+ }
+
+ return dmin;
+}
+#endif /* NO_INTER4V */
+
+/*===============================================================================
+ Function: CandidateSelection
+ Date: 09/16/2000
+ Purpose: Fill up the list of candidate using spatio-temporal correlation
+ among neighboring blocks.
+ Input/Output: type_pred = 0: first pass, 1: second pass, or no SCD
+ Modified: 09/23/01, get rid of redundant candidates before passing back.
+===============================================================================*/
+
+void CandidateSelection(Int *mvx, Int *mvy, Int *num_can, Int imb, Int jmb,
+ VideoEncData *video, Int type_pred)
+{
+ MOT **mot = video->mot;
+ MOT *pmot;
+ Int mbnum = video->mbnum;
+ Vol *currVol = video->vol[video->currLayer];
+ Int mbwidth = currVol->nMBPerRow;
+ Int mbheight = currVol->nMBPerCol;
+ Int i, j, same, num1;
+
+ *num_can = 0;
+
+ if (video->forwardRefVop->predictionType == P_VOP)
+ {
+ /* Spatio-Temporal Candidate (five candidates) */
+ if (type_pred == 0) /* first pass */
+ {
+ pmot = &mot[mbnum][0]; /* same coordinate previous frame */
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ if (imb >= (mbwidth >> 1) && imb > 0) /*left neighbor previous frame */
+ {
+ pmot = &mot[mbnum-1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ else if (imb + 1 < mbwidth) /*right neighbor previous frame */
+ {
+ pmot = &mot[mbnum+1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+
+ if (jmb < mbheight - 1) /*bottom neighbor previous frame */
+ {
+ pmot = &mot[mbnum+mbwidth][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ else if (jmb > 0) /*upper neighbor previous frame */
+ {
+ pmot = &mot[mbnum-mbwidth][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+
+ if (imb > 0 && jmb > 0) /* upper-left neighbor current frame*/
+ {
+ pmot = &mot[mbnum-mbwidth-1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (jmb > 0 && imb < mbheight - 1) /* upper right neighbor current frame*/
+ {
+ pmot = &mot[mbnum-mbwidth+1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ }
+ else /* second pass */
+ /* original ST1 algorithm */
+ {
+ pmot = &mot[mbnum][0]; /* same coordinate previous frame */
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+
+ if (imb > 0) /*left neighbor current frame */
+ {
+ pmot = &mot[mbnum-1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (jmb > 0) /*upper neighbor current frame */
+ {
+ pmot = &mot[mbnum-mbwidth][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (imb < mbwidth - 1) /*right neighbor previous frame */
+ {
+ pmot = &mot[mbnum+1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (jmb < mbheight - 1) /*bottom neighbor previous frame */
+ {
+ pmot = &mot[mbnum+mbwidth][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ }
+ }
+ else /* only Spatial Candidate (four candidates)*/
+ {
+ if (type_pred == 0) /*first pass*/
+ {
+ if (imb > 1) /* neighbor two blocks away to the left */
+ {
+ pmot = &mot[mbnum-2][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (imb > 0 && jmb > 0) /* upper-left neighbor */
+ {
+ pmot = &mot[mbnum-mbwidth-1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (jmb > 0 && imb < mbheight - 1) /* upper right neighbor */
+ {
+ pmot = &mot[mbnum-mbwidth+1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ }
+//#ifdef SCENE_CHANGE_DETECTION
+ /* second pass (ST2 algorithm)*/
+ else if (type_pred == 1) /* 4/7/01 */
+ {
+ if (imb > 0) /*left neighbor current frame */
+ {
+ pmot = &mot[mbnum-1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (jmb > 0) /*upper neighbor current frame */
+ {
+ pmot = &mot[mbnum-mbwidth][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (imb < mbwidth - 1) /*right neighbor current frame */
+ {
+ pmot = &mot[mbnum+1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ if (jmb < mbheight - 1) /*bottom neighbor current frame */
+ {
+ pmot = &mot[mbnum+mbwidth][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ }
+//#else
+ else /* original ST1 algorithm */
+ {
+ if (imb > 0) /*left neighbor current frame */
+ {
+ pmot = &mot[mbnum-1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+
+ if (jmb > 0) /*upper-left neighbor current frame */
+ {
+ pmot = &mot[mbnum-mbwidth-1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+
+ }
+ if (jmb > 0) /*upper neighbor current frame */
+ {
+ pmot = &mot[mbnum-mbwidth][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+
+ if (imb < mbheight - 1) /*upper-right neighbor current frame */
+ {
+ pmot = &mot[mbnum-mbwidth+1][0];
+ mvx[(*num_can)] = (pmot->x) >> 1;
+ mvy[(*num_can)++] = (pmot->y) >> 1;
+ }
+ }
+ }
+//#endif
+ }
+
+ /* 3/23/01, remove redundant candidate (possible k-mean) */
+ num1 = *num_can;
+ *num_can = 1;
+ for (i = 1; i < num1; i++)
+ {
+ same = 0;
+ j = 0;
+ while (!same && j < *num_can)
+ {
+#if (CANDIDATE_DISTANCE==0)
+ if (mvx[i] == mvx[j] && mvy[i] == mvy[j])
+#else
+ // modified k-mean, 3/24/01, shouldn't be greater than 3
+ if (PV_ABS(mvx[i] - mvx[j]) + PV_ABS(mvy[i] - mvy[j]) < CANDIDATE_DISTANCE)
+#endif
+ same = 1;
+ j++;
+ }
+ if (!same)
+ {
+ mvx[*num_can] = mvx[i];
+ mvy[*num_can] = mvy[i];
+ (*num_can)++;
+ }
+ }
+
+#ifdef _SAD_STAT
+ num_cand += (*num_can);
+#endif
+
+ if (num1 == 5 && *num_can == 1)
+ *num_can = ALL_CAND_EQUAL; /* all are equal */
+
+ return ;
+}
+
+/*===========================================================================
+ Function: RasterIntraUpdate
+ Date: 2/26/01
+ Purpose: To raster-scan assign INTRA-update .
+ N macroblocks are updated (also was programmable).
+===========================================================================*/
+void RasterIntraUpdate(UChar *intraArray, UChar *Mode, Int totalMB, Int numRefresh)
+{
+ Int indx, i;
+
+ /* find the last refresh MB */
+ indx = 0;
+ while (intraArray[indx] == 1 && indx < totalMB)
+ indx++;
+
+ /* add more */
+ for (i = 0; i < numRefresh && indx < totalMB; i++)
+ {
+ Mode[indx] = MODE_INTRA;
+ intraArray[indx++] = 1;
+ }
+
+ /* if read the end of frame, reset and loop around */
+ if (indx >= totalMB - 1)
+ {
+ ResetIntraUpdate(intraArray, totalMB);
+ indx = 0;
+ while (i < numRefresh && indx < totalMB)
+ {
+ intraArray[indx] = 1;
+ Mode[indx++] = MODE_INTRA;
+ i++;
+ }
+ }
+
+ return ;
+}
+
+/*===========================================================================
+ Function: ResetIntraUpdate
+ Date: 11/28/00
+ Purpose: Reset already intra updated flags to all zero
+===========================================================================*/
+
+void ResetIntraUpdate(UChar *intraArray, Int totalMB)
+{
+ M4VENC_MEMSET(intraArray, 0, sizeof(UChar)*totalMB);
+ return ;
+}
+
+/*===========================================================================
+ Function: ResetIntraUpdateRegion
+ Date: 12/1/00
+ Purpose: Reset already intra updated flags in one region to all zero
+===========================================================================*/
+void ResetIntraUpdateRegion(UChar *intraArray, Int start_i, Int rwidth,
+ Int start_j, Int rheight, Int mbwidth, Int mbheight)
+{
+ Int indx, j;
+
+ if (start_i + rwidth >= mbwidth)
+ rwidth = mbwidth - start_i;
+ if (start_j + rheight >= mbheight)
+ rheight = mbheight - start_j;
+
+ for (j = start_j; j < start_j + rheight; j++)
+ {
+ indx = j * mbwidth;
+ M4VENC_MEMSET(intraArray + indx + start_i, 0, sizeof(UChar)*rwidth);
+ }
+
+ return ;
+}
+
+/*************************************************************
+ Function: MoveNeighborSAD
+ Date: 3/27/01
+ Purpose: Move neighboring SAD around when center has shifted
+*************************************************************/
+
+void MoveNeighborSAD(Int dn[], Int new_loc)
+{
+ Int tmp[9];
+ tmp[0] = dn[0];
+ tmp[1] = dn[1];
+ tmp[2] = dn[2];
+ tmp[3] = dn[3];
+ tmp[4] = dn[4];
+ tmp[5] = dn[5];
+ tmp[6] = dn[6];
+ tmp[7] = dn[7];
+ tmp[8] = dn[8];
+ dn[0] = dn[1] = dn[2] = dn[3] = dn[4] = dn[5] = dn[6] = dn[7] = dn[8] = 65536;
+
+ switch (new_loc)
+ {
+ case 0:
+ break;
+ case 1:
+ dn[4] = tmp[2];
+ dn[5] = tmp[0];
+ dn[6] = tmp[8];
+ break;
+ case 2:
+ dn[4] = tmp[3];
+ dn[5] = tmp[4];
+ dn[6] = tmp[0];
+ dn[7] = tmp[8];
+ dn[8] = tmp[1];
+ break;
+ case 3:
+ dn[6] = tmp[4];
+ dn[7] = tmp[0];
+ dn[8] = tmp[2];
+ break;
+ case 4:
+ dn[1] = tmp[2];
+ dn[2] = tmp[3];
+ dn[6] = tmp[5];
+ dn[7] = tmp[6];
+ dn[8] = tmp[0];
+ break;
+ case 5:
+ dn[1] = tmp[0];
+ dn[2] = tmp[4];
+ dn[8] = tmp[6];
+ break;
+ case 6:
+ dn[1] = tmp[8];
+ dn[2] = tmp[0];
+ dn[3] = tmp[4];
+ dn[4] = tmp[5];
+ dn[8] = tmp[7];
+ break;
+ case 7:
+ dn[2] = tmp[8];
+ dn[3] = tmp[0];
+ dn[4] = tmp[6];
+ break;
+ case 8:
+ dn[2] = tmp[1];
+ dn[3] = tmp[2];
+ dn[4] = tmp[0];
+ dn[5] = tmp[6];
+ dn[6] = tmp[7];
+ break;
+ }
+ dn[0] = tmp[new_loc];
+
+ return ;
+}
+
+/* 3/28/01, find minimal of dn[9] */
+
+Int FindMin(Int dn[])
+{
+ Int min, i;
+ Int dmin;
+
+ dmin = dn[1];
+ min = 1;
+ for (i = 2; i < 9; i++)
+ {
+ if (dn[i] < dmin)
+ {
+ dmin = dn[i];
+ min = i;
+ }
+ }
+
+ return min;
+}
+
+
+