[XviD-devel] api 3.0 branch

skal xvid-devel@xvid.org
23 Sep 2002 15:39:57 +0200


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


	Hi Michael and all,

	(back in town, too)

On Mon, 2002-09-23 at 12:39, Michael Militzer wrote:
> Also it's true that it would be nicer if the huge vlc runtime tables would
> be const, but obviously the speed gain from this wouldn't be really
> noticeable but instead the const introduces problems on some platforms
> (windows + MSVC). So I think it wasn't really needed to change this for CVS
> head (well, those users simply have to live with worse memory
> management...), whereas I of course have to admit that noone could have
> known that adding a static works with gcc and makes MSVC code crash...
> Additionally, dev-api-3 will sooner or later include Skal's smaller vlc
> tables anyway, so the insanely huge tables will be gone then as well as this
> whole ugly static problem...

	talking of which, here's the code I used to generate
	this big cryptic vlc tables full of hex. I didn't find
	time to clean all this mess, but I prefer posting
	it now, as is, instead of having some tables no-one
        knowns where it comes from hanging around.
	Btw, in this grown-up hack, there's funny things to be
	found: the '-d6' options will draw the layout of
	escape codes used, for instance. This pile of code
	can also be used  generate ln(ln(N)) search tables 
	for decoding... I've only included the four B16/B17
	tables, but if someone wants to play with the other
	norm tables (or MP3/MPEG2 ones, even), just tell
	me...


	bye,

		Skal

--=-SpEG8RUiDjZfwYkJCgWf
Content-Disposition: attachment; filename=genhufftab.h
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c-header; name=genhufftab.h; charset=ISO-8859-1

//
//  Huffman tables to encode in genhufftab.cpp
//
//////////////////////////////////////////////////////////

// Data format : Run, Length (0=3Dauto-compute), Level, Code

static ENTRY Tab_MP4_B16_Last0[] =3D { =20
    // last =3D 0
  {  0, 0, 1, "10" },
  {  0, 0, 3, "1111" },
  {  0, 0, 6, "010101" },
  {  0, 0, 9, "0010111" },
  {  0, 0,10, "00011111" },
  {  0, 0,13, "000100101" },
  {  0, 0,14, "000100100" },
  {  0, 0,17, "0000100001" },
  {  0, 0,18, "0000100000" },
  {  0, 0,21, "00000000111" },
  {  0, 0,22, "00000000110" },
  {  0, 0,23, "00000100000" },
  {  0, 0, 2, "110" },
  {  1, 0, 2, "010100" },
  {  0, 0,11, "00011110" },
  {  0, 0,19, "0000001111" },
  {  0, 0,24, "00000100001" },
  {  0, 0,25, "000001010000" },
  {  1, 0, 1, "1110" },
  {  0, 0,12, "00011101" },
  {  0, 0,20, "0000001110" },
  {  0, 0,26, "000001010001" },
  {  0, 0, 4, "01101" },
  {  0, 0,15, "000100011" },
  {  1, 0, 7, "0000001101" },
  {  0, 0, 5, "01100" },
  {  4, 0, 2, "000100010" },
  {  0, 0,27, "000001010010" },
  {  2, 0, 1, "01011" },
  {  2, 0, 4, "0000001100" },
  {  1, 0, 9, "000001010011" },
  {  0, 0, 7, "010011" },
  {  3, 0, 4, "0000001011" },
  { 11, 0, 1, "000011001" },
  {  5, 0, 1, "001101" },
  {  6, 0, 1, "0010010" },
  {  8, 0, 1, "00011001" },
  {  9, 0, 1, "00011000" },
  { 10, 0, 1, "00010111" },
  { 12, 0, 1, "000011000" },
  { 13, 0, 1, "0000000111" },
  {  6, 0, 3, "000001010100" },
  {  0, 0, 8, "010010" },
  {  4, 0, 3, "0000001010" },
  {  3, 0, 1, "010001" },
  {  8, 0, 2, "0000001001" },
  {  4, 0, 1, "010000" },
  {  5, 0, 3, "0000001000" },
  {  1, 0, 3, "0010110" },
  {  1, 0,10, "000001010101" },
  {  2, 0, 2, "0010101" },
  {  7, 0, 1, "0010100" },
  {  1, 0, 4, "00011100" },
  {  3, 0, 2, "00011011" },
  {  0, 0,16, "000100001" },
  {  1, 0, 5, "000100000" },
  {  1, 0, 6, "000011111" },
  {  2, 0, 3, "000011110" },
  {  3, 0, 3, "000011101" },
  {  5, 0, 2, "000011100" },
  {  6, 0, 2, "000011011" },
  {  7, 0, 2, "000011010" },
  {  1, 0, 8, "00000100010" },
  {  9, 0, 2, "00000100011" },
  {  2, 0, 5, "000001010110" },
  {  7, 0, 3, "000001010111" },
  { 14, 0, 1, "000001011000" },

  { 0,0,0} // End
};

static ENTRY Tab_MP4_B16_Last1[] =3D {  // Run, Len, Level, Code

    // last =3D 1
  {  0, 0, 1, "0111" },
  {  0, 0, 6, "00000000101" },
  {  1, 0, 1, "001111" },
  {  0, 0, 7, "00000000100" },
  {  2, 0, 1, "001110" },
  {  0, 0, 2, "001100" },
  {  5, 0, 1, "0010011" },
  {  3, 0, 1, "0010001" },
  {  4, 0, 1, "0010000" },
  {  9, 0, 1, "00011010" },
  {  0, 0, 3, "00010110" },
  {  6, 0, 1, "00010101" },
  {  7, 0, 1, "00010100" },
  {  8, 0, 1, "00010011" },
  {  0, 0, 4, "000010111" },
  {  1, 0, 2, "000010110" },
  { 10, 0, 1, "000010101" },
  { 11, 0, 1, "000010100" },
  { 12, 0, 1, "000010011" },
  { 13, 0, 1, "000010010" },
  { 14, 0, 1, "000010001" },
  {  0, 0, 5, "0000000110" },
  {  1, 0, 3, "0000000101" },
  {  2, 0, 2, "0000000100" },
  {  3, 0, 2, "00000100100" },
  {  4, 0, 2, "00000100101" },
  { 15, 0, 1, "00000100110" },
  { 16, 0, 1, "00000100111" },
  {  0, 0, 8, "000001011001" },
  {  5, 0, 2, "000001011010" },
  {  6, 0, 2, "000001011011" },
  { 17, 0, 1, "000001011100" },
  { 18, 0, 1, "000001011101" },
  { 19, 0, 1, "000001011110" },
  { 20, 0, 1, "000001011111" },

  { 0,0,0} // End
};

static ENTRY Tab_MP4_B17_Last0[] =3D {  // Value, Len, Level, Code
    // last=3D0
  {  0, 0, 1, "10" },
  {  0, 0, 2, "1111" },
  {  0, 0, 3, "010101" },
  {  0, 0, 4, "0010111" },
  {  0, 0, 5, "00011111" },
  {  0, 0, 6, "000100101" },
  {  0, 0, 7, "000100100" },
  {  0, 0, 8, "0000100001" },
  {  0, 0, 9, "0000100000" },
  {  0, 0,10, "00000000111" },
  {  0, 0,11, "00000000110" },
  {  0, 0,12, "00000100000" },
  {  1, 0, 1, "110" },
  {  1, 0, 2, "010100" },
  {  1, 0, 3, "00011110" },
  {  1, 0, 4, "0000001111" },
  {  1, 0, 5, "00000100001" },
  {  1, 0, 6, "000001010000" },
  {  2, 0, 1, "1110" },
  {  2, 0, 2, "00011101" },
  {  2, 0, 3, "0000001110" },
  {  2, 0, 4, "000001010001" },
  {  3, 0, 1, "01101" },
  {  3, 0, 2, "000100011" },
  {  3, 0, 3, "0000001101" },
  {  4, 0, 1, "01100" },
  {  4, 0, 2, "000100010" },
  {  4, 0, 3, "000001010010" },
  {  5, 0, 1, "01011" },
  {  5, 0, 2, "0000001100" },
  {  5, 0, 3, "000001010011" },
  {  6, 0, 1, "010011" },
  {  6, 0, 2, "0000001011" },
  {  6, 0, 3, "000001010100" },
  {  7, 0, 1, "010010" },
  {  7, 0, 2, "0000001010" },
  {  8, 0, 1, "010001" },
  {  8, 0, 2, "0000001001" },
  {  9, 0, 1, "010000" },
  {  9, 0, 2, "0000001000" },
  { 10, 0, 1, "0010110" },
  { 10, 0, 2, "000001010101" },
  { 11, 0, 1, "0010101" },
  { 12, 0, 1, "0010100" },
  { 13, 0, 1, "00011100" },
  { 14, 0, 1, "00011011" },
  { 15, 0, 1, "000100001" },
  { 16, 0, 1, "000100000" },
  { 17, 0, 1, "000011111" },
  { 18, 0, 1, "000011110" },
  { 19, 0, 1, "000011101" },
  { 20, 0, 1, "000011100" },
  { 21, 0, 1, "000011011" },
  { 22, 0, 1, "000011010" },
  { 23, 0, 1, "00000100010" },
  { 24, 0, 1, "00000100011" },
  { 25, 0, 1, "000001010110" },
  { 26, 0, 1, "000001010111" },

  { 0,0,0} // End
};

static ENTRY Tab_MP4_B17_Last1[] =3D {  // Value, Len, Level, Code
    // last=3D1
  {  0, 0, 1, "0111" },
  {  0, 0, 2, "000011001" },
  {  0, 0, 3, "00000000101" },
  {  1, 0, 1, "001111" },
  {  1, 0, 2, "00000000100" },
  {  2, 0, 1, "001110" },
  {  3, 0, 1, "001101" },
  {  4, 0, 1, "001100" },
  {  5, 0, 1, "0010011" },
  {  6, 0, 1, "0010010" },
  {  7, 0, 1, "0010001" },
  {  8, 0, 1, "0010000" },
  {  9, 0, 1, "00011010" },
  { 10, 0, 1, "00011001" },
  { 11, 0, 1, "00011000" },
  { 12, 0, 1, "00010111" },
  { 13, 0, 1, "00010110" },
  { 14, 0, 1, "00010101" },
  { 15, 0, 1, "00010100" },
  { 16, 0, 1, "00010011" },
  { 17, 0, 1, "000011000" },
  { 18, 0, 1, "000010111" },
  { 19, 0, 1, "000010110" },
  { 20, 0, 1, "000010101" },
  { 21, 0, 1, "000010100" },
  { 22, 0, 1, "000010011" },
  { 23, 0, 1, "000010010" },
  { 24, 0, 1, "000010001" },
  { 25, 0, 1, "0000000111" },
  { 26, 0, 1, "0000000110" },
  { 27, 0, 1, "0000000101" },
  { 28, 0, 1, "0000000100" },
  { 29, 0, 1, "00000100100" },
  { 30, 0, 1, "00000100101" },
  { 31, 0, 1, "00000100110" },
  { 32, 0, 1, "00000100111" },
  { 33, 0, 1, "000001011000" },
  { 34, 0, 1, "000001011001" },
  { 35, 0, 1, "000001011010" },
  { 36, 0, 1, "000001011011" },
  { 37, 0, 1, "000001011100" },
  { 38, 0, 1, "000001011101" },
  { 39, 0, 1, "000001011110" },
  { 40, 0, 1, "000001011111" },

  { 0,0,0,0 } // End
};

static TABLE Tables[] =3D {

  { Tab_MP4_B16_Last0, "Intra_B16_Last0", 2}, // genhufftab -n 0 -d5
  { Tab_MP4_B16_Last1, "Intra_B16_Last1", 2}, // genhufftab -n 1 -d5
  { Tab_MP4_B17_Last0, "Inter_B17_Last0", 2}, // genhufftab -n 2 -d5
  { Tab_MP4_B17_Last1, "Inter_B17_Last1", 2}, // genhufftab -n 3 -d5

  { 0,0,0 } // End
};
const int MAX_TABLE =3D sizeof(Tables) / sizeof(TABLE);

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

--=-SpEG8RUiDjZfwYkJCgWf
Content-Disposition: attachment; filename=genhufftab.cpp
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c++; name=genhufftab.cpp; charset=ISO-8859-1

/*
 *
 * Huffman Codes Massage II (the Return of the Son of the Revenge)
 * (a quick hack that grew up)
 *
 *  -Skal-   (@planet-d.net)
 *
 * for xvid, use something like:=20
 *  genhufftab -n 0 -d5
 *  genhufftab -n 1 -d5
 *  genhufftab -n 2 -d5
 *  genhufftab -n 3 -d5
 ***************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef unsigned long uint32_t;

static const int MAX_TAB =3D 20;
static const int MAX_LEN =3D 8192;
static int Verbose =3D 0;

struct VLC { int Value, Len, Level; };

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

struct CHUNK
{
  int Nb;
  int Shift, bLen;
  uint32_t Min, Max;
  uint32_t Min_Code, Max_Code;
  uint32_t Offset;
  VLC Vlc[MAX_LEN];
  char Name[128];

  int Size() const { return Max-Min; }
  int Is_Empty() const { return (Max=3D=3D0); }
  void Record(uint32_t Code, int Len);
  void Init_Codes() {
    for(int k=3D0; k<MAX_LEN; ++k) {
      Vlc[k].Value =3D 0;
      Vlc[k].Len   =3D -1;
      Vlc[k].Level =3D 0;
    }
  } =20
  void Print(int Format, int VLC_Format, int VLC_Transf) const;
  void Print_Infos() const { printf( "Shift=3D%d nbBits=3D%d", Shift, bLen =
); }
};

static CHUNK Tabs[MAX_TAB+1];

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

struct ENTRY
{
  int Value, Len;  // same as struct VLC
  int Level;       // <- for DCT_VLC
  const char *Str_Code;
  uint32_t Code;

  void Print() { printf( "Code=3D0x%x, val=3D%d, Len=3D%d, Level=3D%d, Code=
=3D\"%s\"", Code, Value, Len, Level, Str_Code ); }
  void String_To_Code();
  void Left_Justify(int bSize) { Code <<=3D bSize - Len; }
};

struct TABLE
{
  ENTRY *Entries;
  char *Name;
  int Format;
  int Shift_Output;
  int bSize;
  int Len;
  int Nb_Tab;
  int Init(); // returns Len
  void Init_Output();

     // Output_Type: 0=3Draw, 1=3D32b left justift,  2=3DC-code
     // VLC_Format:  0=3Dnormal, 1=3Dpacked
     // VLC_Transf: 0=3Dnormal, bit1: len+=3D1, etc...
  void Print(int Output_Type=3D0, int VLC_Format=3D0, int VLC_Transf=3D0) c=
onst;

  void Convert(uint32_t XOR_Mask=3D0);
  void Print_Code(uint32_t Code, int Shift,
                  const char * S=3D0, const char * S2=3D0) const;
  void Print_Raw_Code(uint32_t Code, int Shift,
                      const char * S=3D0, const char * S2=3D0) const;
  void Dump_Raw(int Mode, int VLC_Transf, int Packed) const;  // Mode=3D1: =
sorted, Mode=3D2: raw dump
};

#include "./genhufftab.h"

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

int ENTRY_Cmp(const void *a, const void *b) // sort by code
{
  ENTRY *A =3D (ENTRY*)a;
  ENTRY *B =3D (ENTRY*)b;
  if (A->Code<B->Code) return 1;
  else return -1;
}

int ENTRY_Cmp2(const void *a, const void *b)  // sort in decreasing length
{
  ENTRY *A =3D (ENTRY*)a;
  ENTRY *B =3D (ENTRY*)b;
  if (A->Len>B->Len) return 1;
  else return -1;
}

int ENTRY_Cmp3(const void *a, const void *b)  // sort in increasing value
{
  ENTRY *A =3D (ENTRY*)a;
  ENTRY *B =3D (ENTRY*)b;
  if (A->Value>B->Value) return 1;
  if (A->Value<B->Value) return -1;
  return ENTRY_Cmp2(a,b); // tie break: sort on code len
}

int ENTRY_Cmp4(const void *a, const void *b)  // sort in increasing run / l=
evel
{
  ENTRY *A =3D (ENTRY*)a;
  ENTRY *B =3D (ENTRY*)b;
  if (A->Value>B->Value) return 1;
  if (A->Value<B->Value) return -1;
  if (A->Level>B->Level) return 1;
  if (A->Level<B->Level) return -1;
  return 0;
}
int ENTRY_Cmp4Bis(const void *a, const void *b)  // sort in increasing leve=
l/run
{
  ENTRY *A =3D (ENTRY*)a;
  ENTRY *B =3D (ENTRY*)b;
  if (A->Level>B->Level) return 1;
  if (A->Level<B->Level) return -1;
  if (A->Value>B->Value) return 1;
  if (A->Value<B->Value) return -1;
  return 0;
}

void TABLE::Dump_Raw(int Mode, int VLC_Transf, int Packed) const
{
  if (Mode=3D=3D1) {
    qsort(Entries, Len, sizeof(ENTRY), ENTRY_Cmp2);
    printf( "static ENTRY %s[] =3D {\n", Name);
    for(int i=3D0; Entries[i].Str_Code!=3D0; ++i) {
      int Val =3D Entries[i].Value;
      int Level =3D (Format=3D=3D2) ? Entries[i].Level : 0;
      int Len =3D Entries[i].Len;

      if (VLC_Transf&1) Len++;
      if (VLC_Transf&2) Val =3D Val*2;
      if (VLC_Transf&4) Val =3D Val*2+1;
      if (VLC_Transf&8) Level =3D Level*2;

      printf( "  { %d, %d, %d, ", Val, Len, Level);
      Print_Raw_Code(Entries[i].Code, Entries[i].Len, "\t\"", "\" ");
      printf( "},\n" );
    }
    printf( "  { 0,0,0,0 } // End\n" );
    printf( "};\n" );
  }
  else if (Mode=3D=3D2) {
    qsort(Entries, Len, sizeof(ENTRY), ENTRY_Cmp3);
    printf( "static const SKL_VLC %s[%d] =3D {\n", Name, Len);
    ENTRY *Cur =3D Entries;
    int V =3D Entries[0].Value;
    int i =3D 0;
    while(Cur->Str_Code!=3D0) {
      int Level =3D 0, Len =3D 0;
      int Val =3D V;
      uint32_t Code=3D0;
      if (V =3D=3D Cur->Value) {
        if (Format=3D=3D2) Level =3D Cur->Level;
        Len =3D Cur->Len;
        Code =3D Cur->Code>>(bSize-Len);
        Cur++;
        if (Cur->Value=3D=3DV) {
          printf( "ERROR: Cannot index table by values! Some are redundant!=
\n" );
          return;
        }
      }

      if (VLC_Transf&1) { Len +=3D 1; Code <<=3D 1; }
      if (VLC_Transf&2) Val =3D Val*2;
      if (VLC_Transf&4) Val =3D Val*2+1;
      if (VLC_Transf&8) Level =3D Level*2;

      if (Verbose>0)
      //if ((i&15)=3D=3D0)
        printf( "    /* value=3D%d/%d... */\n", Val, Cur->Value);
      if (i) printf( ", " );
      else printf( "  " );

      if (Format=3D=3D2) printf( "{%d, %d, %d}", Code, Level, Len );
      else printf( "{%2d, %2d}", Code, Len);
      if ((i&7)=3D=3D7) printf( "\n" );
     =20
      V++; i++;
    }
    printf( "};\n" );
  }
  else if (Mode=3D=3D3) {    // special look-up for MPEG4 tables (old)
    if (Format!=3D2) {
      printf( "Bad table format for special dump!\n" );
      return;
    }
    qsort(Entries, Len, sizeof(ENTRY), ENTRY_Cmp4);
    printf( "struct SKL_ENC_VLC { char Run, Level, Code, Len; };\n" );
    printf( "static const SKL_ENC_VLC %s[%d] =3D {\n", Name, Len);
    for(int i=3D0; i<Len; ++i) {
      ENTRY *Cur =3D &Entries[i];
      int Level, Run, Len;
      uint32_t Code=3D0;
      Level =3D Cur->Level;
      Len =3D Cur->Len;
      Run =3D Cur->Value;
      Code =3D Cur->Code>>(bSize-Len);

      if (i) printf( ", " );
      else printf( "  " );

      printf( "{%2d, %2d, %2d, %2d}", Run, Level, Code, Len );
      //if ((i&3)=3D=3D3)=20
      printf( "\n" );

    }
    printf( "};\n" );
  }
  else if (Mode=3D=3D4) {    // another special look-up for MPEG4 tables
    int i, j;
    if (Format!=3D2) {
      printf( "Bad table format for special dump!\n" );
      return;
    }
    qsort(Entries, Len, sizeof(ENTRY), ENTRY_Cmp4);

    ENTRY Tab[64][100];
    for(j=3D0; j<64; ++j)
      for(i=3D0; i<100; ++i) {
        Tab[j][i].Code =3D 0;
        Tab[j][i].Len =3D 255;
      }
    int Max_Run[100];
    int Max_Level[64];
    for(i=3D0; i<Len; ++i) {
      int Run =3D Entries[i].Value;
      int Level =3D Entries[i].Level;
      if (2*Level>=3D100) { printf( "Problem! Recompile!\n" ); return; }
      int L =3D Entries[i].Len;
      Tab[Run][Level].Len  =3D L;
      Tab[Run][Level].Code =3D Entries[i].Code >> (bSize-L);
      Max_Run[Level] =3D Run + 1;
      Max_Level[Run] =3D Level;
    }
    if (Packed) printf( "typedef uint32_t SKL_ENC_VLC; /* Len:8bits, Code: =
24bits */\n" );
    else printf( "struct SKL_ENC_VLC { uint32_t Code; int Len; }; /* Code m=
ax: 30bits, Len max:5bits */\n" );

    int Max_Esc_L =3D 2*Max_Level[0];
    int Max_Esc_R =3D 2*Max_Run[1];
    if (Max_Esc_R>64) Max_Esc_R  =3D 64;
    int Last;
    if (!strcmp( Name, "Intra_B16_Last0") ||
        !strcmp( Name, "Inter_B17_Last0") )
      Last =3D 0;
    else
      Last =3D 1;

    printf( "static const SKL_ENC_VLC %s_Flat[] =3D { /*last=3D%d*/\n ", Na=
me, Last );
    int Pos[64] =3D {0};
    Pos[0] =3D 0;
    int Off =3D 0;
    int Max_B =3D 0;
    for(j=3D0; j<Max_Esc_R; ++j)
    {
      int L =3D Max_Level[j];
      int EL =3D 2*L;
      int f =3D 0;
      for(i=3D1; i<=3DMax_Esc_L; ++i)
      {
        int R =3D Max_Run[i];
        int ER =3D 2*R-1;
        if (ER>64) ER =3D 64;
        int e =3D 0;
        if (i<=3DL) e =3D 0;
        else if (i>EL && j>ER) e =3D 3;
        else {
          int L1 =3D Tab[j][i-L].Len + 7+1;
          int L2 =3D Tab[j-R][i].Len + 7+2;
          int L3 =3D 7+2+ 1+6+1+12+1;
          if (L3<L1 && L3<L2) e =3D 3;
          else if (L1<=3DL2) e =3D 1;
          else e =3D 2;
        }
        int Len;
        uint32_t Code;
        if (e=3D=3D0) {
          Code =3D Tab[j][i].Code;
          Len =3D Tab[j][i].Len;
        }
        else if (e=3D=3D1) {
          Code =3D Tab[j][i-L].Code;
          Len =3D Tab[j][i-L].Len;
          Code |=3D 0x6 << Len;     // 0000011b (ESC) + 0b
          Len +=3D 7+1;=20
        }
        else if (e=3D=3D2) {
          Code =3D Tab[j-R][i].Code;
          Len =3D Tab[j-R][i].Len;
          Code |=3D 0xe << Len;     // 0000011b (ESC) + 10b
          Len +=3D 7+2;=20
        }
        else /* if (e=3D=3D3) */ {
          Code =3D 0x1e02001 | (Last<<20) | (j<<14) | (i<<1);
          Len =3D 0;  // special encoding. should be 30
        }
        if (e!=3D3) {
          if (Len>Max_B) Max_B =3D Len;
          assert(Len<(1<<8) && Code<(1<<24));
          if (Packed) printf( "0x%.7x", ((Code&0xffffff)<<1) | ((Len+1)<<24=
) );
          else printf( "{0x%.8x,%2d}", Code, Len );
          if (j!=3DMax_Esc_R-1) printf( "," );
        }

        if (i=3D=3DMax_Esc_L || e=3D=3D3) {
          printf( "\n " );
          Pos[j+1] =3D Off+1;
          f =3D 0;
          break;
        }
        Off++;

        if (++f> (Packed? 8 : 4)) {
          printf( "\n  " );
          f =3D 0;
        }
      }
    }
    printf( "\n};\n" );

    printf( "static const SKL_ENC_VLC * const %s[64+1] =3D { /*max coded ru=
n=3D%d max bits %d*/\n", Name, Max_Esc_R, Max_B );
    for(j=3D0; j<Max_Esc_R; ++j) {
      printf( " %s_Flat-1 + %3d,  /*run=3D%d*/\n", Name, Pos[j], j );
    }
    printf( "    /*sentinels*/\n" );
    for(i=3Dj; i<=3D64; ++i)
      printf( " %s_Flat-1 + %3d%c\n", Name, Pos[j], i=3D=3D64 ? ' ' : ',');
    printf( "};\n" );
  }
  else if (Mode=3D=3D5) {    // another special look-up for MPEG4 tables
    int i, j;
    if (Format!=3D2) {
      printf( "Bad table format for special dump!\n" );
      return;
    }
    qsort(Entries, Len, sizeof(ENTRY), ENTRY_Cmp4);

    int Max_Run[65] =3D { 0 };
    int Max_Level[64] =3D { 0 };
    ENTRY Tab[64][2*64];
    for(j=3D0; j<64; ++j)
      for(i=3D0; i<2*64; ++i)=20
        Tab[j][i].Len =3D 255;

    for(i=3D0; i<Len; ++i) {
      int Run =3D Entries[i].Value;
      int Level =3D Entries[i].Level;
      if (2*Level>=3D64) { printf( "Problem! Recompile!\n" ); return; }
      int L =3D Entries[i].Len;
      Tab[Run][Level].Len  =3D L;
      Tab[Run][Level].Code =3D Entries[i].Code >> (bSize-L);
      Max_Run[Level] =3D Run + 1;
      Max_Level[Run] =3D Level;
    }

    uint32_t Code_Last =3D 0x1e02001;
    if (!strcmp( Name, "Intra_B16_Last1") ||
        !strcmp( Name, "Inter_B17_Last1") )
      Code_Last |=3D (1<<20);

    // printf( "static const uint32_t %s[128][64] =3D { /* index: [level+64=
][run] */\n", Name );
    printf( "static const uint32_t %s[64][128] =3D { /* index: [run][level+=
64] */\n", Name );
    for(int Run=3D0; Run<64; ++Run)
    {
      int f =3D 0;
      printf( " {" );
      for(int Lvl0=3D-64; Lvl0<64; ++Lvl0)

      {
        int e;
        int Lvl =3D (Lvl0<0) ? -Lvl0 : Lvl0;
        int Len;
        uint32_t Code;
        if (Lvl=3D=3D0) {=20
          Len=3D0;
          Code =3D Code_Last | (Run<<14);
          goto End;
        }
        if (Lvl<=3DMax_Level[Run]) e =3D 0;
        else if (Lvl>2*Max_Level[Run] && Run>2*Max_Run[Lvl]-1) e =3D 3;
        else {
          int L1 =3D Tab[Run][Lvl-Max_Level[Run]].Len + 7+1;
          int L2 =3D Tab[Run-Max_Run[Lvl]][Lvl].Len + 7+2;
          if (L1<=3DL2) e =3D 1;
          else e =3D 2;
        }

        if (e=3D=3D0) {
          Code =3D Tab[Run][Lvl].Code;
          Len  =3D Tab[Run][Lvl].Len;
        }
        else if (e=3D=3D1) {
          Code =3D Tab[Run][Lvl-Max_Level[Run]].Code;
          Len  =3D Tab[Run][Lvl-Max_Level[Run]].Len;
          Code |=3D 0x6 << Len;     // 0000011b (ESC) + 0b
          Len +=3D 7+1;
        }
        else if (e=3D=3D2) {
          Code =3D Tab[Run-Max_Run[Lvl]][Lvl].Code;
          Len  =3D Tab[Run-Max_Run[Lvl]][Lvl].Len;
          Code |=3D 0xe << Len;     // 0000011b (ESC) + 10b
          Len +=3D 7+2;=20
        }
        else /* if (e=3D=3D3) */ {
          Code =3D Code_Last | (Run<<14) | ((Lvl0&0xfff)<<1);
          Len =3D 0;  // special encoding. should be 30
          Code |=3D 0x80000000; // marker
        }
        if (e!=3D3) {
          Code <<=3D 1;
          if (Lvl0<0) Code |=3D 1;
          Len +=3D 1; // sign bit
        }
End:
//        printf( "0x%x", (Code&0xffffff) | (Len<<24) );
        if (Lvl=3D=3D0) printf( "0x%x", Code);
        else if (Len) printf( "0x%x", (Len<<24) | Code);
        else printf( "0x%x", Code );  // esc3 w/ bit31
        if (Lvl0!=3D63) printf( "," );

        if (++f>7) {
          printf( "\n   " );
          f =3D 0;
        }
      }
      printf( "}" );
      if (Run!=3D63) printf( "," );
      printf( "\n" );
    }
    printf( "\n};\n" );
  }
  else if (Mode=3D=3D6) {    // yet another dump for MPEG4 tables
    int i, j;
    if (Format!=3D2) {
      printf( "Bad table format for special dump!\n" );
      return;
    }
    qsort(Entries, Len, sizeof(ENTRY), ENTRY_Cmp4);

    ENTRY Tab[64][100];
    for(j=3D0; j<64; ++j)
      for(i=3D0; i<100; ++i) {
        Tab[j][i].Code =3D 0;
        Tab[j][i].Len =3D 255;
      }
    int Max_Run[100] =3D {0};
    int Max_Level[64] =3D {0};
    for(i=3D0; i<Len; ++i) {
      int Run =3D Entries[i].Value;
      int Level =3D Entries[i].Level;
      if (2*Level>=3D100) { printf( "Problem! Recompile!\n" ); return; }
      int L =3D Entries[i].Len;
      Tab[Run][Level].Len  =3D L;
      Tab[Run][Level].Code =3D Entries[i].Code >> (bSize-L);
      Max_Run[Level] =3D Run + 1;
      Max_Level[Run] =3D Level;
    }

    int Max_L =3D Max_Level[0];
    int Max_R =3D Max_Run[1];
    int Max_Esc_L =3D 2*Max_L;
    int Max_Esc_R =3D 2*Max_R;
    if (Max_Esc_R>64) Max_Esc_R  =3D 64;

    printf( "=3D=3D Coding Map for %s_Flat[] =3D=3D\n", Name );
    printf("lvl:|");
    for(i=3D1; i<=3DMax_Esc_L; ++i) printf( "%2d|", i);
    printf("\n");
    for(j=3D0; j<Max_Esc_R; ++j)
    {
      printf("%2d |", j);
      int L =3D Max_Level[j];
      int EL =3D 2*L;
      for(i=3D1; i<=3DMax_Esc_L; ++i)
      {
        int R =3D Max_Run[i];
        int ER =3D 2*R-1;
        if (ER>64) ER =3D 64;
        int e =3D 0;
        if (i<=3DL) e =3D 0;
        else if (i>EL && j>ER) e =3D 3;
        else {
          int L1 =3D Tab[j][i-L].Len + 7+1;
          int L2 =3D Tab[j-R][i].Len + 7+2;
          int L3 =3D 7+2+ 1+6+1+12+1;
          if (L3<L1 && L3<L2) e =3D 3;
          else if (L1<=3DL2) e =3D 1;
          else e =3D 2;
        }
        if (e=3D=3D0) printf( " %2d", Tab[j][i].Len );
        else if (e=3D=3D1) printf( " e1" );
        else if (e=3D=3D2) printf( " e2" );
        else           printf( " e3" );
      }
      printf( "\n" );
    }
    printf( "};\n" );
  }
}

void TABLE::Print(int Output_Type, int VLC_Format, int VLC_Transf) const
{
  int n, s=3D0;
  for(n=3D0; n<Nb_Tab; ++n) {
    if (Tabs[n].Is_Empty()) continue;
    printf( "  /* bLen=3D%d ", Tabs[n].bLen );
    Print_Code( Tabs[n].Min_Code, Tabs[n].Shift, "minCode=3Db", " " );
    Print_Code( Tabs[n].Max_Code, Tabs[n].Shift, "maxCode=3Db", " " );
    printf( "(0x%x/0x%x) */\n", Tabs[n].Min_Code, Tabs[n].Max_Code );
    sprintf(Tabs[n].Name, "%s_%d", Name, n);
    Tabs[n].Print(Format, VLC_Format, VLC_Transf);
    s +=3D Tabs[n].Size();
  }

  if (Output_Type!=3D2) {
    if (Format=3D=3D2) printf( "const SKL_DCT_CHUNK " );
    else printf( "const SKL_VLC_CHUNK ");
    printf( "%s[] =3D { /* bSize=3D%d  (total size=3D%d)*/\n", Name, bSize,=
 s );
    for(n=3D0; n<Nb_Tab; ++n) {
      if (Tabs[n].Is_Empty()) continue;
      printf( "  { %s_%d - 0x%x, ", Name, n, Tabs[n].Min );
      if (Output_Type=3D=3D1) {
        int s =3D 32-bSize;
        printf( "0x%.8x, %d },", Tabs[n].Offset<<s, Tabs[n].Shift+s);
      }
      else printf( "0x%x, %d },", Tabs[n].Offset, Tabs[n].Shift );
      printf( " /* nbBits:%d */\n", Tabs[n].bLen );
    }
    printf( "  {0,0}\n};\n" );
  }
  else {  // C-code
    printf( "const %s *Tab;\n", Format=3D=3D2 ? "SKL_DCT_VLC" : "SKL_VLC_TA=
B" );
    printf( "Bits->Check_Bits( %d );\nconst uint32_t Code =3D Bits->Bits;\n=
", bSize );
    printf( " /* bSize=3D%d  (total size=3D%d)*/\n", bSize, s );
    int t =3D 0;
    for(int n=3D0; n<Nb_Tab; ++n) {
      if (Tabs[n].Is_Empty()) continue;
      printf( "%sif (Code>=3D0x%.8x) Tab =3D %s_%d - %d + (Code>>(%d+%d));\=
n",
        t=3D=3D0 ? "" : "else ",
        Tabs[n].Offset << (32-bSize),
        Name, n, Tabs[n].Min, 32-bSize, Tabs[n].Shift );
      t++;
    }
    printf( "else break; /* error */\n" );
  }
}

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

void TABLE::Print_Code(uint32_t Code, int Shift,
                       const char * S, const char * S2) const
{
  if (S) printf(S);
//  printf("b");
  int l =3D bSize;
  while(l-->Shift) {
    if (Code&(1<<l)) printf("1");
    else printf("0");
  }
  while(0<=3Dl--) printf("x");
  if (S2) printf(S2);
}

void TABLE::Print_Raw_Code(uint32_t Code, int Len,
                           const char * S, const char * S2) const
{
  if (S) printf(S);
  int l =3D bSize;
  Len =3D bSize - Len;
  while(l-->Len) {
    if (Code&(1<<l)) printf("1");
    else printf("0");
  }
  if (S2) printf(S2);
}

void CHUNK::Record(uint32_t Code, int Len)
{
  uint32_t Tmp =3D Code | ((1<<Shift)-1);
  if ( Tmp>Max_Code) Max_Code =3D Tmp;
  if (Code<Min_Code) Min_Code =3D Code;
  if (Code<Offset) Offset =3D Code;
  Code >>=3D Shift;
  if ( Code<Min ) Min =3D Code;
  int Bits_To_Fill =3D bLen - Len;
  Code +=3D 1<<Bits_To_Fill;
  if ( Code>Max ) Max =3D Code;

  if (Verbose>1)
    printf( " m=3D%d M=3D%d mc=3D%d Mc=3D%d Shift=3D%d bFill=3D%d\n",
      Min, Max, Min_Code, Max_Code, Shift, Bits_To_Fill );
}

void CHUNK::Print(int Format, int VLC_Format, int VLC_Transf) const
{
  if (VLC_Format) printf( "static const uint32_t ");
  else {
    if (Format=3D=3D2) printf( "static const SKL_DCT_VLC ");
    else printf( "static const SKL_VLC ");
  }
  printf( "%s[%d] =3D {\n  ", Name, Size() );

  for(uint32_t i=3DMin; i<Max; ++i) {
    int Val =3D Vlc[i].Value;
    int Level =3D (Format=3D=3D2) ? Vlc[i].Level : 0;
    int Len =3D Vlc[i].Len;
    if (VLC_Transf&1) Len++;
    if (VLC_Transf&2) Val =3D Val*2;
    if (VLC_Transf&4) Val =3D Val*2+1;
    if (VLC_Transf&8) Level =3D Level*2;
    if (Val>=3D65536||Val<-65536) printf( "Packed VLC PROBLEM: Value (%d) t=
oo big!\n", Val );
    if (Level>=3D256) printf( "Packed VLC PROBLEM: level (%d) too big!\n", =
Level );
    if (Format=3D=3D2) {
      if (Len>256) printf( "Packed VLC PROBLEM: len (%d) too big!\n", Len )=
;
      }
    else {
      if (Len>=3D65536) printf( "Packed VLC PROBLEM: len (%d) too big!\n", =
Len );
    }

    if (VLC_Format) {
      uint32_t vlc;
      if (Format=3D=3D2) vlc =3D (Val<<16) | (Level<<8) | Len;
      else vlc =3D (Val<<16) | Len;
      printf( "0x%.8x", vlc );
    }
    else {   =20
      if (Format=3D=3D2) printf( "{%2d,%2d,%2d}", Val, Level, Len );
      else printf( "{%2d,%2d}", Val, Len );
      //else printf( "{0x%.2x,%2d}", Val, Len );
    }
    if (i!=3DMax-1) {
      if ((i&7)=3D=3D7) printf("\n, ");
      else printf(",");
    }
  }
  printf( "\n};\n" );
}


static CHUNK &Search_Tab(uint32_t Code, VLC &vlc)
{
  int n =3D 0;
  while(vlc.Len>Tabs[n].bLen) n++;

  if (Verbose>1) {
    if (Code<Tabs[n+1].Max_Code)
      printf( "\n =3D> Inversion! Jumping to next table...\n" );
  }
  while(Code<Tabs[n+1].Max_Code) n++;
  return Tabs[n];
}

static int Insert_Code(uint32_t Code, VLC &vlc)
{
  CHUNK &Chk =3D Search_Tab(Code, vlc);

  Chk.Record( Code, vlc.Len );

  Code =3D Code >> Chk.Shift;
  int Bits_To_Fill  =3D 1 << (Chk.bLen-vlc.Len);
  if (Verbose>2)
    printf( "Filling Chunk #%d from %d to %d\n", Chk.Nb, Code, Code+Bits_To=
_Fill);
  while(Bits_To_Fill-->0) {
    if ((int)Code>=3DMAX_LEN) {
      printf( "PROBLEM with MAX_LEN! Code=3D%d\n", Code);
      return 1;
    }
    if (Chk.Vlc[Code].Len!=3D-1) {
      printf( "PROBLEM: n=3D%d, c=3D%d\n", Chk.Nb, Code);
      return 1;  // Error!
    }
    Chk.Vlc[Code] =3D vlc;
    Code++;
  }

  return 0;
}

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

void ENTRY::String_To_Code()
{
  uint32_t v =3D 0;
  const char *Val =3D Str_Code;=20
  while(*Val) {
    v <<=3D 1;
    if (*Val=3D=3D'1') v |=3D 1;
    else if (*Val!=3D'0') {
      fprintf( stderr, "Non-valid code string: [%s]\n", Str_Code );
      throw 1;
    }
    Val++;
  }
  Code =3D v;
  if (Len<=3D0) Len =3D Val - Str_Code;
  else if (Len<Val-Str_Code) {
    if (Verbose>0)=20
      printf( "Incoherent size %d (got:%d) for string code [%s]\n", Val-Str=
_Code, Len, Str_Code );
  }
}

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

int TABLE::Init()
{
  bSize =3D 0;
  Len =3D 0;
  while(Entries[Len].Str_Code!=3D0) {
    Entries[Len].String_To_Code();
    if (Entries[Len].Len>bSize) bSize =3D Entries[Len].Len;
    Len++;
  }
    // left-justify codes
  for(int i=3D0; i<Len; ++i)
    Entries[i].Left_Justify(bSize);

  qsort(Entries, Len, sizeof(ENTRY), ENTRY_Cmp);
  return Len;
}

void TABLE::Init_Output()
{
  int i =3D 0;
  while(i<MAX_TAB) {
    int spl =3D Tabs[i].bLen;
    int Shift =3D bSize - spl;
    if (spl>bSize) { spl=3DbSize; Shift=3D0; Tabs[i].bLen =3D bSize; }
    else Tabs[i].bLen =3D spl;
    Tabs[i].Nb     =3D i;
    Tabs[i].Min    =3D 0x7fffffff;
    Tabs[i].Max    =3D 0;
    Tabs[i].Min_Code =3D 0xffffffff;
    Tabs[i].Max_Code =3D 0;
    Tabs[i].Offset =3D 0x7fffffff;
    Tabs[i].Shift  =3D Shift;
    Tabs[i].Init_Codes();
    i++;
    if (Shift=3D=3D0) break;
  }
  Nb_Tab =3D i;

  Tabs[Nb_Tab].Nb  =3D Nb_Tab;
  Tabs[Nb_Tab].Min =3D 0;
  Tabs[Nb_Tab].Max =3D 0;
  Tabs[Nb_Tab].Min_Code =3D 0;
  Tabs[Nb_Tab].Max_Code =3D 0;
  Tabs[Nb_Tab].Shift =3D 0;
  Tabs[Nb_Tab].bLen =3D 0;
  Tabs[Nb_Tab].Init_Codes();
}

void TABLE::Convert(uint32_t XOR_Mask)
{
  int Len =3D Init();
  Init_Output();
//  XOR_Mask <<=3D (32-bSize);
  for(int i=3D0; i<Len; ++i)
  {
    VLC vlc;

    vlc.Value =3D Entries[i].Value;
    vlc.Len   =3D Entries[i].Len;
    vlc.Level =3D Entries[i].Level;
    uint32_t Code =3D Entries[i].Code ^ XOR_Mask;

    if (Verbose>1) {
      Print_Code( Code, bSize-vlc.Len, "[Code:b", "] " );
      printf( "Val=3D%d", vlc.Value );
    }

    if (Insert_Code(Code, vlc)) {
      printf( "PROBLEM ENTRY #%d: ", i);
      Entries[i].Print();
      printf( "\n" );
    }
  }
}

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

void Help(const char *App)
{
  printf( "Usage: %s <options> bit_ranges\n", App );
  printf( "Options:\n" );
  printf( " -n <int> .... table to encode\n" );
  printf( " -s .......... left-shift CHUNK output codes\n" );
  printf( " -c .......... output search table as C-code\n" );
  printf( " -p .......... output packed VLC tables\n" );
  printf( " -b .......... switch bit-range input from full-value to delta\n=
" );
  printf( " -d .......... Dump sorted table (for VLC writing)\n" );
  printf( " -dd ......... simply dump the table\n" );
  printf( " -d3 ......... special dump for MPEG4 tables\n" );
  printf( " -d4/-d5/-d6.. very special dump for MPEG4 tables\n" );
  printf( " -x <0x...>... XOR mask to apply to input codes\n" );
  printf( " -v1 ......... transform final len as 'len=3Dlen+1'\n" );
  printf( " -v2 ......... transform final value as 'val=3D2*val'\n" );
  printf( " -v3 ......... transform final value as 'val=3D2*val+1'\n" );
  printf( " -v4 ......... transform final level as 'level=3D2*level'\n" );
  printf( " -h .......... this help\n" );
  printf( " -v .......... Verbose++\n" );
  printf( "\n" );
  printf( "example: genhufftab -n 0 -d5\n" );
  exit(0);
}

int main(int argc, const char *argv[])
{
  int s =3D 0;
  int Range =3D 0;
  int Range_Mode =3D 0; // 0=3Dvalue, 1=3Ddelta-value
  int Dump_Mode =3D 0;
  int T =3D -1;
  int Output_Code =3D 0;
  int VLC_Format =3D 0;
  int VLC_Transf =3D 0;
  uint32_t XOR_Mask =3D 0;
  Verbose =3D 0;
  if (argc=3D=3D1) Help(argv[0]);
  for(int c=3D1; c<argc; ++c) {
    if (!strcmp(argv[c], "-v")) Verbose++;
    else if (!strcmp(argv[c], "-h")) Help(argv[0]);
    else if (!strcmp(argv[c], "-n")) { T =3D atoi(argv[++c]) % MAX_TABLE; }
    else if (!strcmp(argv[c], "-s")) Output_Code =3D 1;
    else if (!strcmp(argv[c], "-c")) Output_Code =3D 2;
    else if (!strcmp(argv[c], "-p")) VLC_Format =3D 1;
    else if (!strcmp(argv[c], "-b")) Range_Mode =3D 1;
    else if (!strcmp(argv[c], "-dd")) Dump_Mode =3D 2;
    else if (!strcmp(argv[c], "-d3")) Dump_Mode =3D 3;
    else if (!strcmp(argv[c], "-d4")) Dump_Mode =3D 4;
    else if (!strcmp(argv[c], "-d5")) Dump_Mode =3D 5;
    else if (!strcmp(argv[c], "-d6")) Dump_Mode =3D 6;
    else if (!strcmp(argv[c], "-d")) Dump_Mode =3D 1;
    else if (!strcmp(argv[c], "-x")) sscanf(argv[++c], "0x%x", &XOR_Mask);
    else if (!strcmp(argv[c], "-v1")) VLC_Transf |=3D 1;
    else if (!strcmp(argv[c], "-v2")) VLC_Transf |=3D 2;
    else if (!strcmp(argv[c], "-v3")) VLC_Transf |=3D 4;
    else if (!strcmp(argv[c], "-v4")) VLC_Transf |=3D 8;
    else if (argv[c][0]=3D=3D'-') {
      fprintf( stderr, "Unknown option '%s'!\n", argv[c] );
      exit(1);
    }
    else {
      if (Range_Mode=3D=3D0) Range =3D atoi(argv[c]);
      else Range +=3D atoi(argv[c]);
      Tabs[s++].bLen =3D Range;
    }
  }
  while(s<MAX_TAB) Tabs[s++].bLen =3D (Range+=3D2);
 =20
  try {
    int n =3D 0;
    if (T>=3D0) n =3D T;
    while(Tables[n].Entries!=3D0) {
      Tables[n].Convert(XOR_Mask);
      if (Dump_Mode) Tables[n].Dump_Raw(Dump_Mode, VLC_Transf, VLC_Format);
      else Tables[n].Print(Output_Code, VLC_Format, VLC_Transf);
      printf( "//////////////////////////////////////////////////////////\n=
\n" );
      if (T>=3D0) break;
      else n++;
    }
  }
  catch(...) {
    fprintf( stderr, "\nOops. Exception thrown! Exiting. \n");
  }
  return 0;
}

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

--=-SpEG8RUiDjZfwYkJCgWf--