[XviD-devel] GMC rc3 - TODO

skal xvid-devel@xvid.org
15 Jan 2003 16:05:41 +0100


--=-UdkVIwU0UdFhVLul/4Ck
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


	Hi,


On Wed, 2003-01-15 at 14:22, Christoph Lampert wrote:
> On 14 Jan 2003, skal wrote:
> > 	here's a test-bed (a la xvid_bench.c) for future tests on GMC.
> > 	I've also quickly hacked a fixed-point incremental version,
> > 	just to be sure I still can beat a linux compiler :)
> > 
	oops, the evaluation of the average MV was missing an
	(x,y) offset! Here is a corrected version. I've also
	simplified the calculation of the gradients (gee...how 
	twisted-minded the ISO is!!) and sped the interpolation
	a little bit more. Moreover, weird sizes (not power of 2)
	where not tested...


> thank you, for this and all, but why are you leaving? Did we annoy you too
> much?

	well, I like to switch context on a regular basis, so I think
	I'm gonna (randomly?) pick a new subject of interest for the
	next 6 months ;)

	take care

		Skal


--=-UdkVIwU0UdFhVLul/4Ck
Content-Disposition: attachment; filename=xvid_gmc.c
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c; name=xvid_gmc.c; charset=ISO-8859-1

/**************************************************************************
 *
 *      XVID MPEG-4 VIDEO CODEC - Unit tests and benches for GMC
 *
 *      This program is free software; you can redistribute it and/or modif=
y
 *      it under the terms of the GNU General Public License as published b=
y
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *************************************************************************/

/************************************************************************
 *                           =20
 *  History:
 *
 *  01.04.2003  alt impl. w/ 4b fixed-point      - Skal -
 *
 *************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>  // for gettimeofday
#include <string.h>    // for memset
#include <assert.h>

#include "xvid.h"
#include "portab.h"
#include "global.h"

// inner guts
#include "image/image.h"
#include "utils/mbfunctions.h"
#include "motion/motion.h"
#include "utils/mem_transfer.h"
#include "utils/emms.h"
#include "utils/timer.h"

#include <math.h>
const int speed_ref =3D 50;

/*********************************************************************
 * misc
 *********************************************************************/

 /* returns time in micro-s*/
double gettime_usec()
{   =20
  struct timeval  tv;
  gettimeofday(&tv, 0);
  return tv.tv_sec*1.0e6 + tv.tv_usec;
}

void write_pgm(int w, int h, int BpS, int BpSc, IMAGE *I)
{
	static int nb =3D 0;
  int i;
	FILE *f;
	char name[64];

	sprintf( name, "dec%.5d.pgm", nb++ );
	f =3D fopen(name, "wb");
	if (!f) return;

  fprintf(f, "P5\n\n%d %d 255\n", w, h*3/2);
  for(i=3D0; i<h; ++i)
    fwrite(I->y + i*BpS, w, 1, f);
  for(i=3D0; i<h/2; ++i) {
    fwrite(I->u + i*BpSc, w/2,1, f);
    fwrite(I->v + i*BpSc, w/2,1, f);
  }
  fclose(f);
}

/* Pseudo-random generator specified by IEEE 1180 */

static long ieee_seed =3D 1;
static void ieee_reseed(long s) {
  ieee_seed =3D s;
}
static long ieee_rand(int Min, int Max)
{
  static double z =3D (double) 0x7fffffff;

  long i,j;
  double x;

  ieee_seed =3D (ieee_seed * 1103515245) + 12345;
  i =3D ieee_seed & 0x7ffffffe;
  x =3D ((double) i) / z;
  x *=3D (Max-Min+1);
  j =3D (long)x;
  j =3D j + Min;
  assert(j>=3DMin && j<=3DMax);
  return (short)j;
}

/*********************************************************************
 * GMC decoding test
 *********************************************************************/

typedef void (*GMC_Param_Func)( const int num_wp, const int res,
                                const WARPPOINTS *const warp,
                                const int width, const int height,
                                GMC_DATA *const gmc );

typedef VECTOR (*GMC_MB_Func)( const GMC_DATA *const gmc_data,
                               const IMAGE *const pRef,
                               const int mi, const int mj,
                               const int stride,
                               const int stride2,
                               const int quarterpel,
                               const int rounding,
                               IMAGE *const pGMC);


void test_GMC(GMC_Param_Func PFunc, GMC_MB_Func MFunc )
{
  double t;
  const int nb_tests =3D speed_ref;
  const int W =3D 256, H =3D 256;
  const int EW =3D ((W+15)&~15) + 2*EDGE_SIZE;    // <=3D> stride
  const int EH =3D ((H+15)&~15) + 2*EDGE_SIZE;
  const int YSize =3D EW*EH;
  const int UVSize =3D (EW/2)*(EH/2);
  const int offset  =3D EDGE_SIZE  + EDGE_SIZE*EW;
  const int offset2 =3D EDGE_SIZE/2+(EDGE_SIZE/2)*(EW/2);
  uint8_t Bits[2][YSize+2*UVSize];

  IMAGE Src, Dst;

  int res, nb_warp, i, n, x, y;
  int qpel, rounding;
  WARPPOINTS warps;
  GMC_DATA data;


  Src.y =3D Bits[0]       +offset;
  Src.u =3D Bits[0]+YSize +offset2;
  Src.v =3D Src.u + UVSize;
  Dst.y =3D Bits[1]       +offset;
  Dst.u =3D Bits[1]+YSize +offset2;
  Dst.v =3D Dst.u + UVSize;

  printf( "\n =3D=3D=3D=3D=3D  test GMC =3D=3D=3D=3D=3D\n" );
  for(res=3D2; res<=3D16; res<<=3D1) {
    int32_t crc =3D 0;
    printf( "res=3D%d ... ", res );
    t =3D -gettime_usec();
    for(qpel=3D0; qpel<=3D1; ++qpel) {
      for(rounding=3D0; rounding<=3D1; ++rounding) {
        for(nb_warp=3D0; nb_warp<=3D2; ++nb_warp) {
          printf( "[%d]", nb_warp );
          ieee_reseed(13*nb_warp+37*rounding+qpel+53*res);
          for(n=3D0; n<nb_tests; ++n) {
            int w,h;
            w =3D ieee_rand(16, W-1);
            h =3D ieee_rand(16, H-1);
            for(i=3D0; i<3;++i) {
              warps.duv[i].x =3D ieee_rand(-32*res,32*res-1);
              warps.duv[i].y =3D ieee_rand(-32*res,32*res-1);
            }
            PFunc( nb_warp, res, &warps, w, h, &data );

            for(x=3D0; x<YSize+2*UVSize; ++x) Bits[0][x] =3D x&0xff;
//            write_pgm(w,h,EW,EW/2,&Src);

            for(x=3D0; x<YSize+2*UVSize; ++x) Bits[1][x] =3D 0;
            for(y=3D0; y<h/16; y++) {
              for(x=3D0; x<w/16; ++x) {
                VECTOR AMv;
                AMv =3D MFunc(&data, &Src, x, y, EW, EW/2, qpel, rounding, =
&Dst);
//                printf( "%d %d\n", AMv.x, AMv.y );
                crc +=3D (AMv.y^AMv.x) - 3*AMv.x;  // pitiful CRC'ing
              }
            }
//            write_pgm(w,h,EW,EW/2,&Dst);
            for(x=3D0; x<YSize+2*UVSize; ++x)
              crc =3D ((crc>>2)^(Bits[1][x]<<2)) + ((crc^Bits[1][x])&0xffff=
);
          }
        }
      }
    }
    t +=3D gettime_usec();
    printf( " ... crc=3D0x%x  time=3D%.3lf sec\n", crc, t/1000000. );
  }
}

/*********************************************************************
 * alt implementation
 *********************************************************************/

  /* let's use some (forbidden) statics until they make it into GMC_DATA */

static int32_t dxF, dyF, dxG, dyG;
static int32_t Fo, Go;
static int32_t cFo, cGo;

#ifndef RSHIFT
#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-=
1))-1)>>(b))
#endif

/* assume b>0 */
#ifndef RDIV
#define RDIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
#endif

static uint32_t __inline
log2bin(uint32_t value)
{
  int n =3D 0;
  while (value) {
    value >>=3D 1;
    n++;
  }
  return n;
}

void my_GMCparameters( const int num_wp, const int res,
                       const WARPPOINTS *const warp,
                       const int width, const int height,
                       GMC_DATA *const gmc)
{
  const int du0 =3D warp->duv[0].x;
  const int dv0 =3D warp->duv[0].y;
  const int du1 =3D warp->duv[1].x;
  const int dv1 =3D warp->duv[1].y;
  const int du2 =3D warp->duv[2].x;
  const int dv2 =3D warp->duv[2].y;
  int Ws;

  gmc->W =3D width;
  gmc->H =3D height;

  gmc->rho =3D 4 - log2bin(res-1);  // =3D {3,2,1,0} for res=3D{2,4,8,16}

  gmc->alpha =3D log2bin(gmc->W-1);
  Ws =3D (1 << gmc->alpha);=20
 =20
  dxF =3D 16*Ws + RDIV( 8*Ws*du1, gmc->W );
  dxG =3D         RDIV( 8*Ws*dv1, gmc->W );
  Fo  =3D (res*du0 + 1) << (gmc->alpha+gmc->rho-1);
  Go  =3D (res*dv0 + 1) << (gmc->alpha+gmc->rho-1);

  if (num_wp=3D=3D2) {
    dyF =3D -dxG;
    dyG =3D  dxF;
  }
  else if (num_wp=3D=3D3) {
    int beta =3D log2bin(gmc->H-1);
    int Hs =3D (1 << beta);=20
    dyF =3D         RDIV( 8*Hs*du2, gmc->H );
    dyG =3D 16*Hs + RDIV( 8*Hs*dv2, gmc->H );
    if (beta>gmc->alpha) {
      dxF <<=3D (beta-gmc->alpha);
      dxG <<=3D (beta-gmc->alpha);
      gmc->alpha =3D beta;
      Ws =3D 1<<beta;
    }
    else {
      dyF <<=3D gmc->alpha-beta;
      dyG <<=3D gmc->alpha-beta;
    }
  }

  cFo =3D dxF + dyF + (1 << (gmc->alpha+gmc->rho+1));
  cFo +=3D 16*Ws*(du0-1);

  cGo =3D dxG + dyG + (1 << (gmc->alpha+gmc->rho+1));
  cGo +=3D 16*Ws*(dv0-1);
}

#define MLT(i)  (((16-(i))<<16) + (i))
static const uint32_t MTab[16] =3D {
  MLT( 0), MLT( 1), MLT( 2), MLT( 3), MLT( 4), MLT( 5), MLT( 6), MLT(7),
  MLT( 8), MLT( 9), MLT(10), MLT(11), MLT(12), MLT(13), MLT(14), MLT(15)
};
#undef MLT

VECTOR my_GMCimageMB( const GMC_DATA *const gmc_data,
                      const IMAGE *const pRef,
                      const int mi, const int mj,
                      const int stride,
                      const int stride2,
                      const int quarterpel,
                      const int rounding,
                      IMAGE *const pGMC)
{
  const int W =3D gmc_data->W;
  const int H =3D gmc_data->H;

  const int rho =3D gmc_data->rho;=20
  const int alpha =3D gmc_data->alpha;=20

  const int rounder =3D ( 128 - (rounding<<(rho+rho)) ) << 16;

  uint8_t *dstY, *dstU, *dstV;

  int I,J;
  VECTOR avgMV =3D {0,0};

  int32_t Fj, Gj;

  dstY =3D &pGMC->y[(mj*16)*stride+mi*16] + 16;

  Fj =3D Fo + dyF*mj*16 + dxF*mi*16;
  Gj =3D Go + dyG*mj*16 + dxG*mi*16;
  for (J=3D16; J>0; --J)
  {
    int32_t Fi, Gi;
   =20
    Fi =3D Fj; Fj +=3D dyF;
    Gi =3D Gj; Gj +=3D dyG;
    for (I=3D-16; I<0; ++I)
    {
      int32_t F, G;
      uint32_t ri, rj;

      F =3D ( Fi >> (alpha+rho) ) << rho; Fi +=3D dxF;
      G =3D ( Gi >> (alpha+rho) ) << rho; Gi +=3D dxG;

      avgMV.x +=3D F;
      avgMV.y +=3D G;

      ri =3D MTab[F&15];
      rj =3D MTab[G&15];

      F >>=3D 4;
      G >>=3D 4;

      if (F< -1) F=3D-1;
      else if (F>W) F=3DW;
      if (G< -1) G=3D-1;
      else if (G>H) G=3DH;

      {     // MMX-like bilinear...
        const int offset =3D G*stride + F;
        uint32_t f0, f1;
        f0  =3D pRef->y[ offset +0 ];
        f0 |=3D pRef->y[ offset +1 ] << 16;
        f1  =3D pRef->y[ offset+stride +0 ];
        f1 |=3D pRef->y[ offset+stride +1 ] << 16;
        f0 =3D (ri*f0)>>16;
        f1 =3D (ri*f1) & 0x0fff0000;
        f0 |=3D f1;=20
        f0 =3D ( rj*f0 + rounder ) >> 24;

        dstY[I] =3D (uint8_t)f0;
      }
    }
    dstY +=3D stride;
  }

  dstU =3D &pGMC->u[(mj*8)*stride2+mi*8] + 8;
  dstV =3D &pGMC->v[(mj*8)*stride2+mi*8] + 8;

  Fj =3D cFo + dyF*4 *mj*8 + dxF*4 *mi*8;
  Gj =3D cGo + dyG*4 *mj*8 + dxG*4 *mi*8;
  for (J=3D8; J>0; --J)
  {
    int32_t Fi, Gi;
    Fi =3D Fj; Fj +=3D 4*dyF;=20
    Gi =3D Gj; Gj +=3D 4*dyG;

    for (I=3D-8; I<0; ++I)
    {
      int32_t F, G;
      uint32_t ri, rj;

      F =3D ( Fi >> (alpha+rho+2) ) << rho; Fi +=3D 4*dxF;
      G =3D ( Gi >> (alpha+rho+2) ) << rho; Gi +=3D 4*dxG;

      ri =3D MTab[F&15];
      rj =3D MTab[G&15];

      F >>=3D 4;
      G >>=3D 4;

      if (F< -1) F=3D-1;
      else if (F>=3DW/2) F=3DW/2;
      if (G< -1) G=3D-1;
      else if (G>=3DH/2) G=3DH/2;

      {
        const int offset =3D G*stride2 + F;
        uint32_t f0, f1;

        f0  =3D pRef->u[ offset         +0 ];
        f0 |=3D pRef->u[ offset         +1 ] << 16;
        f1  =3D pRef->u[ offset+stride2 +0 ];
        f1 |=3D pRef->u[ offset+stride2 +1 ] << 16;
        f0 =3D (ri*f0)>>16;
        f1 =3D (ri*f1) & 0x0fff0000;
        f0 |=3D f1;=20
        f0 =3D ( rj*f0 + rounder ) >> 24;

        dstU[I] =3D (uint8_t)f0;


        f0  =3D pRef->v[ offset         +0 ];
        f0 |=3D pRef->v[ offset         +1 ] << 16;
        f1  =3D pRef->v[ offset+stride2 +0 ];
        f1 |=3D pRef->v[ offset+stride2 +1 ] << 16;
        f0 =3D (ri*f0)>>16;
        f1 =3D (ri*f1) & 0x0fff0000;
        f0 |=3D f1;=20
        f0 =3D ( rj*f0 + rounder ) >> 24;

        dstV[I] =3D (uint8_t)f0;   =20
      }
    }
    dstU +=3D stride2;
    dstV +=3D stride2;
  }


  avgMV.x -=3D 16*((256*mi+120)<<4);    // 120 =3D 15*16/2
  avgMV.y -=3D 16*((256*mj+120)<<4);

  avgMV.x =3D RSHIFT( avgMV.x, (4+7-quarterpel) );
  avgMV.y =3D RSHIFT( avgMV.y, (4+7-quarterpel) );

  return avgMV;
}


/*********************************************************************
 * main
 *********************************************************************/

int main(int argc, char *argv[])
{
  int what =3D 0;
  if (argc>1) what =3D atoi(argv[1]);

  if (what=3D=3D0 || what=3D=3D1)
    test_GMC(generate_GMCparameters, generate_GMCimageMB);
  if (what=3D=3D0 || what=3D=3D2)
    test_GMC(my_GMCparameters, my_GMCimageMB);
  return 0;
}

/*********************************************************************/


--=-UdkVIwU0UdFhVLul/4Ck--