diff options
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.cpp | 1741 |
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; +} + + + |