[XviD-devel] GMC rc3 - TODO
skal
xvid-devel@xvid.org
14 Jan 2003 19:27:43 +0100
--=-APBwBi9oN659GV+PbUMx
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Hi,
On Sun, 2003-01-12 at 13:51, Christoph Lampert wrote:
> Anyway, a first step would be to change these
>
> int F= i0s + ( ((-r*i0s+i1ss)*I + (r*j0s-j1ss)*J +(1<<(alpha+rho-1))) >> (alpha+rho) );
> int G= j0s + ( ((-r*j0s+j1ss)*I + (-r*i0s+i1ss)*J +(1<<(alpha+rho-1))) >> (alpha+rho) );
>
> difficult and wasteful calculations to a incremental approach, only add
> something every step instead of multiplying.
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 :)
this is most probably my last contribution to XVID. Farewell!
Skal
--=-APBwBi9oN659GV+PbUMx
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 64, H =3D 64;
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;
VECTOR AMv;
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);
for(n=3D0; n<nb_tests; ++n) {
for(i=3D0; i<3;++i) {
warps.duv[i].x =3D ieee_rand(-32*res,32*res);
warps.duv[i].y =3D ieee_rand(-32*res,32*res);
}
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) {
AMv =3D MFunc(&data, &Src, x, y, EW, EW/2, qpel, rounding, =
&Dst);
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. );
}
=20
}
/*********************************************************************
* alt implementation
*********************************************************************/
/* let's use some (forbidden) statics until they make it into GMC_DATA */
static int32_t Cos, Sin;
static int32_t Fo, Go;
static int32_t cCos, cSin;
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 __inline int gmc_sanitize(int value, int quarterpel, int fcode)
{
int length =3D 1 << (fcode+4);
// if (quarterpel) value *=3D 2;
if (value < -length)
return -length;
else if (value >=3D length)
return length-1;
else return value;
}
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)
{
int tmp;
int du0 =3D warp->duv[0].x;
int dv0 =3D warp->duv[0].y;
int du1 =3D warp->duv[1].x;
int dv1 =3D warp->duv[1].y;
gmc->num_wp =3D num_wp;
gmc->s =3D res; /* scaling parameters 2,4,8 or 16 */
gmc->sigma =3D log2bin(res-1); /* log2bin(15)=3D4, log2bin(16)=3D5, log2=
bin(17)=3D5 */
gmc->r =3D 16/res;=20
gmc->rho =3D 4 - gmc->sigma; /* =3D log2bin(r-1) */
gmc->W =3D width;
gmc->H =3D height; /* fixed reference coordinates */
gmc->alpha =3D log2bin(gmc->W-1);
gmc->Ws =3D 1<<gmc->alpha;=20
gmc->i0s =3D res/2 * ( du0 );
gmc->j0s =3D res/2 * ( dv0 );
gmc->i1s =3D res/2 * (2*width + du1 + du0 );
gmc->j1s =3D res/2 * ( dv1 + dv0 );
=20
tmp =3D (gmc->W-gmc->Ws)*(gmc->r*gmc->i0s);
tmp +=3D gmc->Ws*(gmc->r*gmc->i1s - 16*gmc->W);
gmc->i1ss =3D 16*gmc->Ws + RDIV(tmp,gmc->W);=20
tmp =3D (gmc->W - gmc->Ws)*(gmc->r*gmc->j0s);
tmp +=3D gmc->Ws*gmc->r*gmc->j1s;
gmc->j1ss =3D RDIV( tmp, gmc->W ); =20
Cos =3D gmc->i1ss - gmc->r*gmc->i0s;
Sin =3D gmc->j1ss - gmc->r*gmc->j0s;
Fo =3D (2*gmc->i0s + 1) << (gmc->alpha+gmc->rho-1);
Go =3D (2*gmc->j0s + 1) << (gmc->alpha+gmc->rho-1);
cCos =3D 4*Cos;
cSin =3D 4*Sin;
cFo =3D Cos - Sin + (1 << (gmc->alpha+gmc->rho+1));
cFo +=3D 2*gmc->Ws*gmc->r*gmc->i0s - 16*gmc->Ws;
cGo =3D Sin + Cos + (1 << (gmc->alpha+gmc->rho+1));
cGo +=3D 2*gmc->Ws*gmc->r*gmc->j0s - 16*gmc->Ws;
}
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));
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 - Sin*(mj*16) + Cos*(mi*16);
Gj =3D Go + Cos*(mj*16) + Sin*(mi*16);
for (J=3D16; J>0; --J)
{
int32_t Fi, Gi;
=20
Fi =3D Fj; Fj -=3D Sin;
Gi =3D Gj; Gj +=3D Cos;
for (I=3D-16; I<0; ++I)
{
int32_t F, G, ri, rj;
int Y00,Y01,Y10,Y11;
F =3D ( Fi >> (alpha+rho) ) << rho; Fi +=3D Cos;=20
G =3D ( Gi >> (alpha+rho) ) << rho; Gi +=3D Sin;
avgMV.x +=3D F;
avgMV.y +=3D G;
ri =3D F & 15;
rj =3D 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;
Y00 =3D pRef->y[ G*stride + F ];
Y01 =3D pRef->y[ G*stride + F+1 ];
Y10 =3D pRef->y[ G*stride + F + stride ];
Y11 =3D pRef->y[ G*stride + F+1 + stride ];
Y01 =3D (Y00<<4) + ri*(Y01-Y00);
Y11 =3D (Y10<<4) + ri*(Y11-Y10);
Y11 =3D (Y01<<4) + rj*(Y11-Y01);
Y00 =3D ( Y11 + rounder ) >> 8;
dstY[I] =3D (uint8_t)Y00;
}
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 - cSin*(mj*8) + cCos*(mi*8);
Gj =3D cGo + cCos*(mj*8) + cSin*(mi*8);
for (J=3D8; J>0; --J)
{
int32_t Fi, Gi;
Fi =3D Fj; Fj -=3D cSin;=20
Gi =3D Gj; Gj +=3D cCos;
for (I=3D-8; I<0; ++I)
{
int32_t F, G, ri, rj;
int C00,C01,C10,C11;
F =3D ( Fi >> (alpha+rho+2) ) << rho; Fi +=3D cCos;
G =3D ( Gi >> (alpha+rho+2) ) << rho; Gi +=3D cSin;
ri =3D F & 15;
rj =3D 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;
C00 =3D pRef->u[ G*stride2 + F ];
C01 =3D pRef->u[ G*stride2 + F+1 ];
C10 =3D pRef->u[ G*stride2 + F + stride2];
C11 =3D pRef->u[ G*stride2 + F+1 + stride2];
C01 =3D (C00<<4) + ri*(C01-C00);
C11 =3D (C10<<4) + ri*(C11-C10);
C11 =3D (C01<<4) + rj*(C11-C01);
C00 =3D ( C11 + rounder ) >> 8;
dstU[I] =3D (uint8_t)C00;
=20
C00 =3D pRef->v[ G*stride2 + F ];
C01 =3D pRef->v[ G*stride2 + F+1 ];
C10 =3D pRef->v[ G*stride2 + F + stride2];
C11 =3D pRef->v[ G*stride2 + F+1 + stride2];
C01 =3D (C00<<4) + ri*(C01-C00);
C11 =3D (C10<<4) + ri*(C11-C10);
C11 =3D (C01<<4) + rj*(C11-C01);
C00 =3D ( C11 + rounder ) >> 8;
dstV[I] =3D (uint8_t)C00;
}
dstU +=3D stride2;
dstV +=3D stride2;
}
avgMV.x -=3D 16*(120<<4); // 120 =3D 15*16/2
avgMV.y -=3D 16*(120<<4);
avgMV.x =3D RSHIFT( avgMV.x, (4+7-quarterpel) );
avgMV.y =3D RSHIFT( avgMV.y, (4+7-quarterpel) );
=20
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;
}
/*********************************************************************/
--=-APBwBi9oN659GV+PbUMx--