[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--