[XviD-devel] _real_ adaptive quantization

skal xvid-devel@xvid.org
01 Oct 2002 11:27:33 +0200


--=-YcrnYp2o675MwQwD40YZ
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


	Hi Christoph,

On Mon, 2002-09-30 at 21:04, Christoph Lampert wrote:
> Hi,
> 
> I found my bug and now I can tell you about the very first results of 
> "non-heuristic adaptive quantization". In my extensive tests with the huge
> data set of full 10 frames of the foreman sequence in QCIF (176x144),
> I achieved the immense quality improvement of 0.0002 in PSNR 
> (from 37.57531 to 37.57551) when at the same time REDUCING bitrate by 
> incredible .0517% (from 1934 bytes to 1933 bytes). 
> 
> Well... maybe not _too_ impressive so far, but at least it works now. 
> 
	bwehehe...

	How to you decide the q vs q+1 quant? Do you call a round
	of quant(q)/dequant(q)/quant(q+1)/dequant(q+1)/choose best ?

	If so, I have something in store that I didn't have the
	chance to test, yet. It computes the SAD implied by
	the H263 quant/dequant process, for a given q, with
	use of 2 tables access to hash the input coeff, thanks to
	something like:

	  (a*256 + b)%q  = ( (a*256)%q + b%q ) % q. = (b+Offset(a))%q

	(quant error is not exactly (a%q), but that's the idea)

	The term (a*256)%q is tabulated as an offset added to 'b'.
	(It's very like the rule to guess whether a number is
	divisible by 3: sum up its numbers, and check if its
	a multiple of 3...).

	It also extend to directly computing the difference
	between q & q+1 in one shot, but only for quantizer
	less than Q=8 so far I've seen (afterward, tables are
	growing too huge).

	I have no clue how it can be extended to MPEG4-quantization,
	because quantizer range is (256 times) bigger...

	I attach my test proggy that scans all the input range...
	If you have time to plug this into your code, I'd really
	like to know how it behaves (within your ruthless testsuite:)

	bye!

		Skal


--=-YcrnYp2o675MwQwD40YZ
Content-Disposition: attachment; filename=quant_err.c
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c; name=quant_err.c; charset=ISO-8859-1

// Quant tests
//////////////////////////////////////////////////////////

#define ABS(C) ((C)<0 ? -(C) : (C))
#define DIV(num,den,bias)  ( ((num) + (bias) ) / (den) )

  // Normalized H263/MPEG4 dequantization
#define DEQUANT_H263(c,q)  ( c*(q<<1) + ((q&1)? q : q-1) )

static int H263_Intra(int Co, int q) // H263-inter way of quantizing
{
  int c =3D DIV(Co,q<<1,0);
  return DEQUANT_H263(c,q);
}
static int H263_Inter(int Co, int q) // H263-inter way of quantizing
{
  int c =3D DIV(Co,q<<1,-(q>>1));   // bias: -q/2
  return DEQUANT_H263(c,q);
}

//////////////////////////////////////////////////////////

static int QUANT_ERR(int C, int q) {
  C =3D ABS(C);
  C =3D C - H263_Intra(C ,q);
//  C =3D C - H263_Inter(C ,q);
  return ABS(C);
}

void Test_Quant3()
{
  unsigned int q;
  int N;

#define LO  128
#define SHFT 7
#define HI (2048>>SHFT)
#define MAX_OFF 74    // Max Offset: H263-Intra: 60,   H263-Inter: 74

  static signed char Tab_D1[HI+1][32];
  static signed char Tab_D0[LO+MAX_OFF+1][32];  // ~6k

  for(q=3D1; q<=3D31; ++q)
  {
    int Max_Off =3D 0;
    for(N=3D0; N<=3DLO+MAX_OFF; ++N)
      Tab_D0[N][q] =3D QUANT_ERR(N, q);

    for(N=3D0; N<=3DHI; ++N) {
      int Off, x;
      for(Off=3D0; Off<=3DMAX_OFF; ++Off) {
        for(x=3D0; x<LO; ++x) {
          int H =3D N*LO+x;
          int Err =3D QUANT_ERR(H, q);
          if (Err!=3DTab_D0[Off+x][q])=20
            break;
        }
        if (x=3D=3DLO) break;
      }
      if (Off>MAX_OFF) { printf( "Problem with MAX_OFF (<%d)!!\n", Off ); r=
eturn; }
      Tab_D1[N][q] =3D Off;
      if (Off>Max_Off) Max_Off =3D Off;
    }
//    printf( "Q=3D%d Max_Off=3D%d\n", q, Max_Off );
  }

  for(N=3D-2048; N<=3D2047; ++N)
  {
    for(q=3D1; q<=3D31; ++q)
    {
      int Ro, R;
      Ro =3D QUANT_ERR(N, q);
      R =3D (int)Tab_D0[ (ABS(N)&(LO-1)) + (int)Tab_D1[(ABS(N)>>SHFT)][q] ]=
[q];
      if (R!=3DRo) { printf( "!!!%d %d -> %d/%d\n", N, q, Ro, R); return; }
    }
  }
  printf( "QuantErr(q) OK.\n" );

#undef HI
#undef MAX_OFF
#undef LO
#undef SHFT
}

//////////////////////////////////////////////////////////

static int QUANT_ERR2(int C, int q) {
  int C0, C1;
  C =3D ABS(C);
//  C0 =3D C - H263_Intra(C ,q);
  C0 =3D C - H263_Inter(C ,q);
//  C1 =3D C - H263_Intra(C ,q+1);
  C1 =3D C - H263_Inter(C ,q+1);
  return C1-C0;
}

void Test_Quant4()
{
  unsigned int q;
  int N;

#define LO  128
#define SHFT 7
#define HI (2048>>SHFT)
#define MAX_OFF 112       // H263-Intra: 96,   H263-Inter:112
#define MAX_Q 7

  static signed char Tab_D1[HI+1][MAX_Q+1];
  static signed char Tab_D0[LO+MAX_OFF+1][MAX_Q+1];  // ~6k

  for(q=3D1; q<=3DMAX_Q; ++q)
  {
    int Max_Off =3D 0;
    for(N=3D0; N<=3DLO+MAX_OFF; ++N)
      Tab_D0[N][q] =3D QUANT_ERR2(N, q);

    for(N=3D0; N<=3DHI; ++N) {
      int Off, x;
      for(Off=3D0; Off<=3DMAX_OFF; ++Off) {
        for(x=3D0; x<LO; ++x) {
          int H =3D N*LO+x;
          int Err =3D QUANT_ERR2(H, q);
          if (Err!=3DTab_D0[Off+x][q])=20
            break;
        }
        if (x=3D=3DLO) break;
      }
      if (Off>MAX_OFF) { printf( "Problem with MAX_OFF (<%d)!!\n", Off ); r=
eturn; }
      Tab_D1[N][q] =3D Off;
      if (Off>Max_Off) Max_Off =3D Off;
    }
//    printf( "Q=3D%d Max_Off=3D%d\n", q, Max_Off );
  }

  for(N=3D-2048; N<=3D2047; ++N)
  {
    for(q=3D1; q<=3DMAX_Q; ++q)
    {
      int Ro, R;
      Ro =3D QUANT_ERR2(N, q);
      R =3D (int)Tab_D0[ (ABS(N)&(LO-1)) + (int)Tab_D1[(ABS(N)>>SHFT)][q] ]=
[q];
      if (R!=3DRo) { printf( "!!! %d %d -> %d/%d\n", N, q, Ro, R); return; =
}
    }
  }
  printf( "|QuantErr(q)-QuantErr(q+1)| OK.\n" );
#undef MAX_Q
#undef HI
#undef MAX_OFF
#undef LO
#undef SHFT
#undef ABS
#undef QUANT_ERR
}

//////////////////////////////////////////////////////////

int main() {
  Test_Quant3();
  Test_Quant4();
  return 0;
}

--=-YcrnYp2o675MwQwD40YZ--