Main Page | Class List | File List | Class Members | File Members

vid_mot_est.c

Go to the documentation of this file.
00001 /************************************************************************
00002  *
00003  *  vid_mot_est.c, part of tmn (TMN encoder)
00004  *  Copyright (C) 1995, 1996  Telenor R&D, Norway
00005  *        Karl Olav Lillevold <Karl.Lillevold@nta.no>
00006  *  
00007  *  Contacts: 
00008  *  Karl Olav Lillevold               <Karl.Lillevold@nta.no>, or
00009  *  Robert Danielsen                  <Robert.Danielsen@nta.no>
00010  *
00011  *  Telenor Research and Development  http://www.nta.no/brukere/DVC/
00012  *  P.O.Box 83                        tel.:   +47 63 84 84 00
00013  *  N-2007 Kjeller, Norway            fax.:   +47 63 81 00 76
00014  *  
00015  ************************************************************************/
00016 
00017 /*
00018  * Disclaimer of Warranty
00019  *
00020  * These software programs are available to the user without any
00021  * license fee or royalty on an "as is" basis.  Telenor Research and
00022  * Development disclaims any and all warranties, whether express,
00023  * implied, or statuary, including any implied warranties or
00024  * merchantability or of fitness for a particular purpose.  In no
00025  * event shall the copyright-holder be liable for any incidental,
00026  * punitive, or consequential damages of any kind whatsoever arising
00027  * from the use of these programs.
00028  *
00029  * This disclaimer of warranty extends to the user of these programs
00030  * and user's customers, employees, agents, transferees, successors,
00031  * and assigns.
00032  *
00033  * Telenor Research and Development does not represent or warrant that
00034  * the programs furnished hereunder are free of infringement of any
00035  * third-party patents.
00036  *
00037  * Commercial implementations of H.263, including shareware, are
00038  * subject to royalty fees to patent holders.  Many of these patents
00039  * are general enough such that they are unavoidable regardless of
00040  * implementation design.
00041  * */
00042 
00043 
00044 #include"vid_sim.h"
00045 #include"video_codec.h"
00046 
00047 extern video_codec *VidSt;
00048 
00049 /**********************************************************************
00050  *
00051  *      Name:        MotionEstimation
00052  *      Description:    Estimate all motionvectors for one MB
00053  *      
00054  *      Input:        pointers to current an previous image,
00055  *        pointers to current slice and current MB
00056  *      Returns:        
00057  *      Side effects:   motion vector imformation in MB changed
00058  *
00059  *      Date: 930118    Author: Karl.Lillevold@nta.no
00060  *            940203    Mod. to use PGB's faster search 
00061  *            941208    Mod to use spiral search from mpeg2encode
00062  *            951001    Mod for extended motion vector range
00063  *           
00064  ***********************************************************************/
00065 
00066 
00067 void MotionEstimation(unsigned char *curr, unsigned char *prev, int x_curr,
00068               int y_curr, int xoff, int yoff, int seek_dist, 
00069               MotionVector *MV[6][MBR+1][MBC+2], int *SAD_0)
00070 
00071 {
00072 
00073   int Min_FRAME[5];
00074   MotionVector MV_FRAME[5];
00075   unsigned char *act_block,*aa,*ii;
00076   unsigned char *search_area, *adv_search_area = NULL, *zero_area = NULL;
00077   int sxy,i,k,j,l;
00078   int ihigh,ilow,jhigh,jlow,h_length,v_length;
00079   int adv_ihigh,adv_ilow,adv_jhigh,adv_jlow,adv_h_length,adv_v_length;
00080   int xmax,ymax,block,sad,lx;
00081   int adv_x_curr, adv_y_curr,xvec,yvec;
00082 
00083   xmax = (VidSt->pels);
00084   ymax = (VidSt->lines);
00085   sxy = seek_dist;
00086   if (!(VidSt->long_vectors)) {
00087     /* Maximum normal search range centered around _zero-vector_ */
00088     sxy = mmin(15, sxy);  
00089   }
00090   else {
00091     /* Maximum extended search range centered around _predictor_ */
00092     sxy = mmin(15 - (2*DEF_8X8_WIN+1), sxy);
00093 
00094     /* NB! */
00095 
00096     /* It is only possible to transmit motion vectors within
00097        a 15x15 window around the motion vector predictor
00098        for any 8x8 or 16x16 block */
00099 
00100     /* The reason for the search window's reduction above with
00101        2*DEF_8X8_WIN+1 is that the 8x8 search may change the MV
00102        predictor for some of the blocks within the macroblock. When we
00103        impose the limitation above, we are sure that any 8x8 vector we
00104        might find is possible to transmit */
00105 
00106     /* We have found that with OBMC, DEF_8X8_WIN should be quite small
00107        for two reasons: (i) a good filtering effect, and (ii) not too
00108        many bits used for transferring the vectors. As can be seen
00109        above this is also useful to avoid a large limitation on the MV
00110        search range */
00111 
00112     /* It is possible to make sure the motion vectors found are legal
00113        in other less limiting ways than above, but this would be more
00114        complicated as well as time-consuming. Any good suggestions for
00115        improvement is welcome, though */
00116 
00117     xoff = mmin(16,mmax(-16,xoff));
00118     yoff = mmin(16,mmax(-16,yoff));
00119 
00120     /* There is no need to check if (xoff + x_curr) points outside
00121        the picture, since the Extended Motion Vector Range is
00122        always used together with the Unrestricted MV mode */
00123   }
00124 
00125 
00126   lx = ((VidSt->mv_outside_frame) ? (VidSt->pels) + ((VidSt->long_vectors)?64:32) : (VidSt->pels));
00127 
00128   ilow = x_curr + xoff - sxy;
00129   ihigh = x_curr + xoff + sxy;
00130 
00131   jlow = y_curr + yoff - sxy;
00132   jhigh = y_curr + yoff + sxy;
00133 
00134   if (!(VidSt->mv_outside_frame)) {
00135     if (ilow<0) ilow = 0;
00136     if (ihigh>xmax-16) ihigh = xmax-16;
00137     if (jlow<0) jlow = 0;
00138     if (jhigh>ymax-16) jhigh = ymax-16;
00139   }
00140 
00141   h_length = ihigh - ilow + 16;
00142   v_length = jhigh - jlow + 16;
00143   act_block = LoadArea(curr, x_curr, y_curr, 16, 16, (VidSt->pels));
00144   search_area = LoadArea(prev, ilow, jlow, h_length, v_length, lx);
00145 
00146   for (k = 0; k < 5; k++) {
00147     Min_FRAME[k] = INT_MAX;
00148     MV_FRAME[k].x = 0;
00149     MV_FRAME[k].y = 0;
00150     MV_FRAME[k].x_half = 0;
00151     MV_FRAME[k].y_half = 0;
00152   }
00153 
00154 
00155   /* Zero vector search*/
00156   if (x_curr-ilow         < 0        || y_curr-jlow         < 0        ||
00157       x_curr-ilow+MB_SIZE > h_length || y_curr-jlow+MB_SIZE > v_length) {
00158     /* in case the zero vector is outside the loaded area in search_area */
00159     zero_area = LoadArea(prev, x_curr, y_curr, 16, 16, lx);
00160     *SAD_0 = SAD_Macroblock(zero_area, act_block, 16, Min_FRAME[0]) -
00161        PREF_NULL_VEC;
00162     free(zero_area);
00163   }
00164   else {
00165     /* the zero vector is within search_area */
00166     ii = search_area + (x_curr-ilow) + (y_curr-jlow)*h_length;
00167     *SAD_0 = SAD_Macroblock(ii, act_block, h_length, Min_FRAME[0]) -
00168        PREF_NULL_VEC;
00169   }
00170 
00171   if (xoff == 0 && yoff == 0) {
00172     Min_FRAME[0] = *SAD_0;
00173     MV_FRAME[0].x = 0;
00174     MV_FRAME[0].y = 0;
00175   }
00176   else {
00177     ii = search_area + (x_curr+xoff-ilow) + (y_curr+yoff-jlow)*h_length;
00178     Min_FRAME[0] = SAD_Macroblock(ii, act_block, h_length, Min_FRAME[0]);
00179     MV_FRAME[0].x = xoff;
00180     MV_FRAME[0].y = yoff;
00181   }
00182   /* NB: if xoff or yoff != 0, the Extended MV Range is used. If we
00183      allow the zero vector to be chosen prior to the half pel search
00184      in this case, the half pel search might lead to a
00185      non-transmittable vector (on the wrong side of zero). If SAD_0
00186      turns out to be the best SAD, the zero-vector will be chosen
00187      after half pel search instead.  The zero-vector can be
00188      transmitted in all modes, no matter what the MV predictor is */
00189 
00190   /* Spiral search */
00191   for (l = 1; l <= sxy; l++) {
00192     i = x_curr + xoff - l;
00193     j = y_curr + yoff - l;
00194     for (k = 0; k < 8*l; k++) {
00195       if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) {
00196 
00197         /* 16x16 integer pel MV */
00198         ii = search_area + (i-ilow) + (j-jlow)*h_length;
00199         sad = SAD_Macroblock(ii, act_block, h_length, Min_FRAME[0]);
00200         if (sad < Min_FRAME[0]) {
00201           MV_FRAME[0].x = i - x_curr;
00202           MV_FRAME[0].y = j - y_curr;
00203           Min_FRAME[0] = sad;
00204         }
00205 
00206       }
00207       if      (k<2*l) i++;
00208       else if (k<4*l) j++;
00209       else if (k<6*l) i--;
00210       else            j--;
00211     }      
00212   }
00213 
00214 
00215   if ((VidSt->advanced)) {
00216 
00217     /* Center the 8x8 search around the 16x16 vector.  This is
00218        different than in TMN5 where the 8x8 search is also a full
00219        search. The reasons for this is: (i) it is faster, and (ii) it
00220        generally gives better results because of a better OBMC
00221        filtering effect and less bits spent for vectors, and (iii) if
00222        the Extended MV Range is used, the search range around the
00223        motion vector predictor will be less limited */
00224 
00225     xvec = MV_FRAME[0].x;
00226     yvec = MV_FRAME[0].y;
00227     
00228     if (!(VidSt->long_vectors)) {
00229       if (xvec > 15 - DEF_8X8_WIN) { xvec =  15 - DEF_8X8_WIN ;}
00230       if (yvec > 15 - DEF_8X8_WIN) { yvec =  15 - DEF_8X8_WIN ;}
00231 
00232       if (xvec < -15 + DEF_8X8_WIN) { xvec =  -15 + DEF_8X8_WIN ;}
00233       if (yvec < -15 + DEF_8X8_WIN) { yvec =  -15 + DEF_8X8_WIN ;}
00234     }
00235 
00236     adv_x_curr = x_curr  + xvec;
00237     adv_y_curr = y_curr  + yvec;
00238 
00239     sxy = DEF_8X8_WIN;
00240 
00241     adv_ilow = adv_x_curr - sxy;
00242     adv_ihigh = adv_x_curr + sxy;
00243 
00244     adv_jlow = adv_y_curr - sxy;
00245     adv_jhigh = adv_y_curr + sxy;
00246 
00247     adv_h_length = adv_ihigh - adv_ilow + 16;
00248     adv_v_length = adv_jhigh - adv_jlow + 16;
00249 
00250     adv_search_area = LoadArea(prev, adv_ilow, adv_jlow, 
00251                adv_h_length, adv_v_length, lx);
00252 
00253     for (block = 0; block < 4; block++) {
00254       ii = adv_search_area + (adv_x_curr-adv_ilow) + ((block&1)<<3) + 
00255         (adv_y_curr-adv_jlow + ((block&2)<<2) )*adv_h_length;
00256       aa = act_block + ((block&1)<<3) + ((block&2)<<2)*16;
00257       Min_FRAME[block+1] = SAD_Block(ii,aa,adv_h_length,Min_FRAME[block+1]);
00258       MV_FRAME[block+1].x = MV_FRAME[0].x;
00259       MV_FRAME[block+1].y = MV_FRAME[0].y;
00260     }
00261 
00262     /* Spiral search */
00263     for (l = 1; l <= sxy; l++) {
00264       i = adv_x_curr - l;
00265       j = adv_y_curr - l;
00266       for (k = 0; k < 8*l; k++) {
00267         if (i>=adv_ilow && i<=adv_ihigh && j>=adv_jlow && j<=adv_jhigh) {
00268           
00269           /* 8x8 integer pel MVs */
00270           for (block = 0; block < 4; block++) {
00271             ii = adv_search_area + (i-adv_ilow) + ((block&1)<<3) + 
00272               (j-adv_jlow + ((block&2)<<2) )*adv_h_length;
00273             aa = act_block + ((block&1)<<3) + ((block&2)<<2)*16;
00274             sad = SAD_Block(ii, aa, adv_h_length, Min_FRAME[block+1]);
00275             if (sad < Min_FRAME[block+1]) {
00276               MV_FRAME[block+1].x = i - x_curr;
00277               MV_FRAME[block+1].y = j - y_curr;
00278               Min_FRAME[block+1] = sad;
00279             }
00280           }
00281           
00282         }
00283         if      (k<2*l) i++;
00284         else if (k<4*l) j++;
00285         else if (k<6*l) i--;
00286         else            j--;
00287       }      
00288     }
00289 
00290   }
00291 
00292   i = x_curr/MB_SIZE+1;
00293   j = y_curr/MB_SIZE+1;
00294 
00295   if (!(VidSt->advanced)) {
00296     MV[0][j][i]->x = MV_FRAME[0].x;
00297     MV[0][j][i]->y = MV_FRAME[0].y;
00298     MV[0][j][i]->min_error = Min_FRAME[0];
00299   }
00300   else {
00301     for (k = 0; k < 5; k++) {
00302       MV[k][j][i]->x = MV_FRAME[k].x;
00303       MV[k][j][i]->y = MV_FRAME[k].y;
00304       MV[k][j][i]->min_error = Min_FRAME[k];
00305     }
00306   }
00307 
00308   free(act_block);
00309   free(search_area);
00310   if ((VidSt->advanced))
00311     free(adv_search_area);
00312   return;
00313 }
00314 
00315 /**********************************************************************
00316  *
00317  *      Name:        LoadArea
00318  *      Description:    fills array with a square of image-data
00319  *      
00320  *      Input:         pointer to image and position, x and y size
00321  *      Returns:       pointer to area
00322  *      Side effects:  memory allocated to array
00323  *
00324  *      Date: 940203    Author: PGB
00325  *                      Mod: KOL
00326  *
00327  ***********************************************************************/
00328 
00329 
00330 unsigned char *LoadArea(unsigned char *im, int x, int y, 
00331         int x_size, int y_size, int lx)
00332 {
00333   unsigned char *res = (unsigned char *)malloc(sizeof(char)*x_size*y_size);
00334   unsigned char *in;
00335   unsigned char *out;
00336   int i = x_size;
00337   int j = y_size;
00338 
00339   in = im + (y*lx) + x;
00340   out = res;
00341 
00342   while (j--) {
00343     while (i--)
00344       *out++ = *in++;
00345     i = x_size;
00346     in += lx - x_size;
00347   };
00348   return res;
00349 }
00350 
00351 /**********************************************************************
00352  *
00353  *      Name:        SAD_Macroblock
00354  *      Description:    fast way to find the SAD of one vector
00355  *      
00356  *      Input:          pointers to search_area and current block,
00357  *                      Min_F1/F2/FR
00358  *      Returns:        sad_f1/f2
00359  *      Side effects:
00360  *
00361  *      Date: 940203        Author: PGB
00362  *                      Mod:    KOL
00363  *
00364  ***********************************************************************/
00365 
00366 
00367 int SAD_Macroblock(unsigned char *ii, unsigned char *act_block,
00368            int h_length, int Min_FRAME)
00369 {
00370   int i;
00371   int sad = 0;
00372   unsigned char *kk;
00373 
00374   kk = act_block;
00375   i = 16;
00376   while (i--) {
00377     sad += (abs(*ii     - *kk     ) +abs(*(ii+1 ) - *(kk+1) )
00378             +abs(*(ii+2) - *(kk+2) ) +abs(*(ii+3 ) - *(kk+3) )
00379             +abs(*(ii+4) - *(kk+4) ) +abs(*(ii+5 ) - *(kk+5) )
00380             +abs(*(ii+6) - *(kk+6) ) +abs(*(ii+7 ) - *(kk+7) )
00381             +abs(*(ii+8) - *(kk+8) ) +abs(*(ii+9 ) - *(kk+9) )
00382             +abs(*(ii+10)- *(kk+10)) +abs(*(ii+11) - *(kk+11))
00383             +abs(*(ii+12)- *(kk+12)) +abs(*(ii+13) - *(kk+13))
00384             +abs(*(ii+14)- *(kk+14)) +abs(*(ii+15) - *(kk+15)) );
00385 
00386     ii += h_length;
00387     kk += 16;
00388     if (sad > Min_FRAME)
00389       return INT_MAX;
00390   } 
00391   return sad;
00392 }
00393 
00394 int SAD_Block(unsigned char *ii, unsigned char *act_block,
00395               int h_length, int min_sofar)
00396 {
00397   int i;
00398   int sad = 0;
00399   unsigned char *kk;
00400 
00401   kk = act_block;
00402   i = 8;
00403   while (i--) {
00404     sad += (abs(*ii     - *kk     ) +abs(*(ii+1 ) - *(kk+1) )
00405             +abs(*(ii+2) - *(kk+2) ) +abs(*(ii+3 ) - *(kk+3) )
00406             +abs(*(ii+4) - *(kk+4) ) +abs(*(ii+5 ) - *(kk+5) )
00407             +abs(*(ii+6) - *(kk+6) ) +abs(*(ii+7 ) - *(kk+7) ));
00408 
00409     ii += h_length;
00410     kk += 16;
00411     if (sad > min_sofar)
00412       return INT_MAX;
00413   } 
00414   return sad;
00415 }
00416 
00417 int SAD_MB_Bidir(unsigned char *ii, unsigned char *aa, unsigned char *bb, 
00418          int width, int min_sofar)
00419 {
00420   int i, sad = 0;
00421   unsigned char *ll, *kk;
00422   kk = aa;
00423   ll = bb;
00424   i = 16;
00425   while (i--) {
00426     sad += (abs(*ii     - ((*kk    + *ll    )>>1)) +
00427             abs(*(ii+1) - ((*(kk+1)+ *(ll+1))>>1)) +
00428             abs(*(ii+2) - ((*(kk+2)+ *(ll+2))>>1)) +
00429             abs(*(ii+3) - ((*(kk+3)+ *(ll+3))>>1)) +
00430             abs(*(ii+4) - ((*(kk+4)+ *(ll+4))>>1)) +
00431             abs(*(ii+5) - ((*(kk+5)+ *(ll+5))>>1)) +
00432             abs(*(ii+6) - ((*(kk+6)+ *(ll+6))>>1)) +
00433             abs(*(ii+7) - ((*(kk+7)+ *(ll+7))>>1)) +
00434             abs(*(ii+8) - ((*(kk+8)+ *(ll+8))>>1)) +
00435             abs(*(ii+9) - ((*(kk+9)+ *(ll+9))>>1)) +
00436             abs(*(ii+10) - ((*(kk+10)+ *(ll+10))>>1)) +
00437             abs(*(ii+11) - ((*(kk+11)+ *(ll+11))>>1)) +
00438             abs(*(ii+12) - ((*(kk+12)+ *(ll+12))>>1)) +
00439             abs(*(ii+13) - ((*(kk+13)+ *(ll+13))>>1)) +
00440             abs(*(ii+14) - ((*(kk+14)+ *(ll+14))>>1)) +
00441             abs(*(ii+15) - ((*(kk+15)+ *(ll+15))>>1)));
00442 
00443     ii += width;
00444     kk += width;
00445     ll += width;
00446     if (sad > min_sofar)
00447       return INT_MAX;
00448   } 
00449   return sad;
00450 }
00451 
00452 int SAD_MB_integer(int *ii, int *act_block, int h_length, int min_sofar)
00453 {
00454   int i, sad = 0, *kk;
00455 
00456   kk = act_block;
00457   i = 16;
00458   while (i--) {
00459     sad += (abs(*ii     - *kk     ) +abs(*(ii+1 ) - *(kk+1) )
00460             +abs(*(ii+2) - *(kk+2) ) +abs(*(ii+3 ) - *(kk+3) )
00461             +abs(*(ii+4) - *(kk+4) ) +abs(*(ii+5 ) - *(kk+5) )
00462             +abs(*(ii+6) - *(kk+6) ) +abs(*(ii+7 ) - *(kk+7) )
00463             +abs(*(ii+8) - *(kk+8) ) +abs(*(ii+9 ) - *(kk+9) )
00464             +abs(*(ii+10)- *(kk+10)) +abs(*(ii+11) - *(kk+11))
00465             +abs(*(ii+12)- *(kk+12)) +abs(*(ii+13) - *(kk+13))
00466             +abs(*(ii+14)- *(kk+14)) +abs(*(ii+15) - *(kk+15)) );
00467 
00468     ii += h_length;
00469     kk += 16;
00470     if (sad > min_sofar)
00471       return INT_MAX;
00472   } 
00473   return sad;
00474 }
00475 
00476 /**********************************************************************
00477  *
00478  *      Name:        FindMB
00479  *      Description:    Picks out one MB from picture
00480  *      
00481  *      Input:        position of MB to pick out,
00482  *        pointer to frame data, empty 16x16 array      
00483  *      Returns:        
00484  *      Side effects:   fills array with MB data
00485  *
00486  *      Date: 930119    Author: Karl Olav Lillevold
00487  *
00488  ***********************************************************************/
00489 
00490 void FindMB(int x, int y, unsigned char *image, int MB[16][16])
00491 
00492 {
00493   int n;
00494   register int m;
00495 
00496   for (n = 0; n < MB_SIZE; n++)
00497     for (m = 0; m < MB_SIZE; m++)
00498       MB[n][m] = *(image + x+m + (y+n)*(VidSt->pels));
00499 }
00500 
00501 

Generated on Sun Jul 16 16:27:45 2006 by  doxygen 1.3.9.1