helper.cpp
#include <stdio.h>
#include <vector>
using namespace std;
// Variable length codes helper:
typedef struct
{
unsigned short int code;
unsigned char length;
unsigned char zeroRunLength;
unsigned char level;
} FullVLCTableEntry;
// Coded block pattern structure.
typedef struct
{
unsigned short int code;
unsigned char length;
unsigned char index;
} CodedBlockPatternEntry;
// Macroblock address increment structure.
typedef struct
{
unsigned short int code;
unsigned char length;
unsigned char increment;
} MacroblockAddressIncrementEntry;
#define VLC_ENTRY_COUNT 111
#define MAX_ZERO_RUN_LENGTH 32 // NB. One added for indexing.
#define MAX_PATTERN_LENGTH 18 // NB. One added for indexing.
#define LAST_ZRL_FOR_OWN_TABLE 6
#define MAX_PATTERN_ENTRIES_AT_ANY_LENGTH 16
#define FIRST_PATTERN_LENGTH_WITH_ENTRIES 3
// There are always 64 elements in the coded block pattern table. The bit patterns code
// indices which indicate which blocks within a macroblock are encoded.
#define MAX_CBP_LENGTH 9
#define MIN_CBP_LENGTH 3
#define MAX_CBPS_IN_LENGTH_CATEGORY 28
// Macroblock address increment information.
#define MAX_MAI_LENGTH 11
#define MIN_MAI_LENGTH 1
#define MAI_COUNT 33
#define MAX_MAIS_IN_LENGTH_CATEGORY 12
static const FullVLCTableEntry vlcTables[VLC_ENTRY_COUNT] =
{
{0x03, 3, 0, 1},
{0x04, 5, 0, 2},
{0x05, 6, 0, 3},
{0x06, 8, 0, 4},
{0x26, 9, 0, 5},
{0x21, 9, 0, 6},
{0x0A, 11, 0, 7},
{0x1D, 13, 0, 8},
{0x18, 13, 0, 9},
{0x13, 13, 0, 10},
{0x10, 13, 0, 11},
{0x1A, 14, 0, 12},
{0x19, 14, 0, 13},
{0x18, 14, 0, 14},
{0x17, 14, 0, 15},
{0x1F, 15, 0, 16},
{0x1E, 15, 0, 17},
{0x1D, 15, 0, 18},
{0x1C, 15, 0, 19},
{0x1B, 15, 0, 20},
{0x1A, 15, 0, 21},
{0x19, 15, 0, 22},
{0x18, 15, 0, 23},
{0x17, 15, 0, 24},
{0x16, 15, 0, 25},
{0x15, 15, 0, 26},
{0x14, 15, 0, 27},
{0x13, 15, 0, 28},
{0x12, 15, 0, 29},
{0x11, 15, 0, 30},
{0x10, 15, 0, 31},
{0x18, 16, 0, 32},
{0x17, 16, 0, 33},
{0x16, 16, 0, 34},
{0x15, 16, 0, 35},
{0x14, 16, 0, 36},
{0x13, 16, 0, 37},
{0x12, 16, 0, 38},
{0x11, 16, 0, 39},
{0x10, 16, 0, 40},
{0x03, 4, 1, 1},
{0x06, 7, 1, 2},
{0x25, 9, 1, 3},
{0x0C, 11, 1, 4},
{0x1B, 13, 1, 5},
{0x16, 14, 1, 6},
{0x15, 14, 1, 7},
{0x1F, 16, 1, 8},
{0x1E, 16, 1, 9},
{0x1D, 16, 1, 10},
{0x1C, 16, 1, 11},
{0x1B, 16, 1, 12},
{0x1A, 16, 1, 13},
{0x19, 16, 1, 14},
{0x13, 17, 1, 15},
{0x12, 17, 1, 16},
{0x11, 17, 1, 17},
{0x10, 17, 1, 18},
{0x05, 5, 2, 1},
{0x04, 8, 2, 2},
{0x0B, 11, 2, 3},
{0x14, 13, 2, 4},
{0x14, 14, 2, 5},
{0x07, 6, 3, 1},
{0x24, 9, 3, 2},
{0x1C, 13, 3, 3},
{0x13, 14, 3, 4},
{0x06, 6, 4, 1},
{0x0F, 11, 4, 2},
{0x12, 13, 4, 3},
{0x07, 7, 5, 1},
{0x09, 11, 5, 2},
{0x12, 14, 5, 3},
{0x05, 7, 6, 1},
{0x1E, 13, 6, 2},
{0x14, 17, 6, 3},
{0x04, 7, 7, 1},
{0x15, 13, 7, 2},
{0x07, 8, 8, 1},
{0x11, 13, 8, 2},
{0x05, 8, 9, 1},
{0x11, 14, 9, 2},
{0x27, 9, 10, 1},
{0x10, 14, 10, 2},
{0x23, 9, 11, 1},
{0x1A, 17, 11, 2},
{0x22, 9, 12, 1},
{0x19, 17, 12, 2},
{0x20, 9, 13, 1},
{0x18, 17, 13, 2},
{0x0E, 11, 14, 1},
{0x17, 17, 14, 2},
{0x0D, 11, 15, 1},
{0x16, 17, 15, 2},
{0x08, 11, 16, 1},
{0x15, 17, 16, 2},
{0x1F, 13, 17, 1},
{0x1A, 13, 18, 1},
{0x19, 13, 19, 1},
{0x17, 13, 20, 1},
{0x16, 13, 21, 1},
{0x1F, 14, 22, 1},
{0x1E, 14, 23, 1},
{0x1D, 14, 24, 1},
{0x1C, 14, 25, 1},
{0x1B, 14, 26, 1},
{0x1F, 17, 27, 1},
{0x1E, 17, 28, 1},
{0x1D, 17, 29, 1},
{0x1C, 17, 30, 1},
{0x1B, 17, 31, 1}
};
static const CodedBlockPatternEntry cbpTable[63] =
{
// {Code, length, index}.
{0x0B, 5, 1},
{0x09, 5, 2},
{0x0D, 6, 3},
{0x0D, 4, 4},
{0x17, 7, 5},
{0x13, 7, 6},
{0x1F, 8, 7},
{0x0C, 4, 8},
{0x16, 7, 9},
{0x12, 7, 10},
{0x1E, 8, 11},
{0x13, 5, 12},
{0x1B, 8, 13},
{0x17, 8, 14},
{0x13, 8, 15},
{0x0B, 4, 16},
{0x15, 7, 17},
{0x11, 7, 18},
{0x1D, 8, 19},
{0x11, 5, 20},
{0x19, 8, 21},
{0x15, 8, 22},
{0x11, 8, 23},
{0x0F, 6, 24},
{0x0F, 8, 25},
{0x0D, 8, 26},
{0x03, 9, 27},
{0x0F, 5, 28},
{0x0B, 8, 29},
{0x07, 8, 30},
{0x07, 9, 31},
{0x0A, 4, 32},
{0x14, 7, 33},
{0x10, 7, 34},
{0x1C, 8, 35},
{0x0E, 6, 36},
{0x0E, 8, 37},
{0x0C, 8, 38},
{0x02, 9, 39},
{0x10, 5, 40},
{0x18, 8, 41},
{0x14, 8, 42},
{0x10, 8, 43},
{0x0E, 5, 44},
{0x0A, 8, 45},
{0x06, 8, 46},
{0x06, 9, 47},
{0x12, 5, 48},
{0x1A, 8, 49},
{0x16, 8, 50},
{0x12, 8, 51},
{0x0D, 5, 52},
{0x09, 8, 53},
{0x05, 8, 54},
{0x05, 9, 55},
{0x0C, 5, 56},
{0x08, 8, 57},
{0x04, 8, 58},
{0x04, 9, 59},
{0x07, 3, 60},
{0x0A, 5, 61},
{0x08, 5, 62},
{0x0C, 6, 63}
};
static const MacroblockAddressIncrementEntry maiTable[MAI_COUNT] =
{
{0x01, 1, 1},
{0x03, 3, 2},
{0x02, 3, 3},
{0x03, 4, 4},
{0x02, 4, 5},
{0x03, 5, 6},
{0x02, 5, 7},
{0x07, 7, 8},
{0x06, 7, 9},
{0x0B, 8, 10},
{0x0A, 8, 11},
{0x09, 8, 12},
{0x08, 8, 13},
{0x07, 8, 14},
{0x06, 8, 15},
{0x17, 10, 16},
{0x16, 10, 17},
{0x15, 10, 18},
{0x14, 10, 19},
{0x13, 10, 20},
{0x12, 10, 21},
{0x23, 11, 22},
{0x22, 11, 23},
{0x21, 11, 24},
{0x20, 11, 25},
{0x1F, 11, 26},
{0x1E, 11, 27},
{0x1D, 11, 28},
{0x1C, 11, 29},
{0x1B, 11, 30},
{0x1A, 11, 31},
{0x19, 11, 32},
{0x18, 11, 33},
};
static const char* numbers[7] = {"zero", "one", "two", "three", "four", "five", "six"};
char hexChar(short int value)
{
if (value < 10)
return '0' + value;
else
return 'A' + (value - 10);
}
void displayVLCTables()
{
// TODO: Tables above can be verified by break point here and putting view in binary mode.
vector<FullVLCTableEntry>** zRLEntries = new vector<FullVLCTableEntry>*[MAX_ZERO_RUN_LENGTH];
vector<FullVLCTableEntry>** pLEntries = new vector<FullVLCTableEntry>*[MAX_PATTERN_LENGTH];
// For CBPs, we output the encode table verbatim (omitting index), and also output a table
// ordered by code length for the decoder.
vector<CodedBlockPatternEntry>** cbpEntries = new vector<CodedBlockPatternEntry>*[MAX_CBP_LENGTH - MIN_CBP_LENGTH + 1];
// For MAIs, we output the encode table verbatim (omitting increment), and also output a table
// ordered by code length for the decoder.
vector<MacroblockAddressIncrementEntry>** maiEntries = new vector<MacroblockAddressIncrementEntry>*[MAX_MAI_LENGTH - MIN_MAI_LENGTH + 1];
unsigned int i;
unsigned int j;
for (i = 0; i < MAX_ZERO_RUN_LENGTH; i++)
zRLEntries[i] = new vector<FullVLCTableEntry>();
for (i = 0; i < MAX_PATTERN_LENGTH; i++)
pLEntries[i] = new vector<FullVLCTableEntry>();
for (i = 0; i < MAX_CBP_LENGTH - MIN_CBP_LENGTH + 1; i++)
cbpEntries[i] = new vector<CodedBlockPatternEntry>();
for (i = 0; i < MAX_MAI_LENGTH - MIN_MAI_LENGTH + 1; i++)
maiEntries[i] = new vector<MacroblockAddressIncrementEntry>();
// Insert the MAI entries ordered by length.
for (j = 0; j < MAI_COUNT; j++)
maiEntries[maiTable[j].length - MIN_MAI_LENGTH]->insert(
maiEntries[maiTable[j].length - MIN_MAI_LENGTH]->end(),
maiTable[j]);
// Insert CBP entries ordered by length.
for (j = 0; j < 63; j++)
cbpEntries[cbpTable[j].length - MIN_CBP_LENGTH]->insert(
cbpEntries[cbpTable[j].length - MIN_CBP_LENGTH]->end(),
cbpTable[j]);
// The CBP tables are now populated. Output both the normal table and the decoder's table.
printf("// CBP for block pattern indexed i is at codedBlockPatterns[i - 1]. Index zero should be encoded with the macroblock address increment.\n");
printf("static const EncoderCBP codedBlockPatterns[63] = \n{\n");
for (i = 0; i < 63; i++)
printf(" {0x%c%c, %d}%c\n", hexChar((cbpTable[i].code & 0x00F0) >> 4),
hexChar(cbpTable[i].code & 0x000F),
cbpTable[i].length, i == 62 ? ' ' : ',');
printf("};\n\n");
printf("// Increasing length tables for coded block patterns. Table index i contains codes with bit length i + %d.\n", MIN_CBP_LENGTH);
printf("static const DecoderCBP cbpsByLength[%d][%d] = \n{\n", MAX_CBP_LENGTH - MIN_CBP_LENGTH + 1, MAX_CBPS_IN_LENGTH_CATEGORY);
for (i = 0; i < MAX_CBP_LENGTH - MIN_CBP_LENGTH + 1; i++)
{
printf(" {\n");
for (j = 0; j < MAX_CBPS_IN_LENGTH_CATEGORY; j++)
{
if (j < cbpEntries[i]->size())
{
printf(" {0x%c%c, %d}%c\n", hexChar(((cbpEntries[i]->at(j).code) & 0x00F0) >> 4),
hexChar((cbpEntries[i]->at(j).code) & 0x000F), cbpEntries[i]->at(j).index,
j == MAX_CBPS_IN_LENGTH_CATEGORY - 1 ? ' ' : ',');
}
else
{
// Put in a constant invalid CBP value as a sentinel on the size of this element of the table.
printf(" nullCBP%c\n",
j == MAX_CBPS_IN_LENGTH_CATEGORY - 1 ? ' ' : ',');
}
}
printf(" }%c\n", i == MAX_CBP_LENGTH - MIN_CBP_LENGTH ? ' ' : ',');
}
printf("};\n\n");
// The MAI tables are now populated. Output both the normal table and the decoder's table.
printf("// Macroblock address increment codes for an increment value of i are at index i - 1.\n");
printf("static const EncoderMAI macroblockAddressIncrement[%d] = \n{\n", MAI_COUNT);
for (i = 0; i < MAI_COUNT; i++)
printf(" {0x%c%c, %d}%c\n", hexChar((maiTable[i].code & 0x00F0) >> 4),
hexChar(maiTable[i].code & 0x000F),
maiTable[i].length, i == MAI_COUNT - 1 ? ' ' : ',');
printf("};\n\n");
printf("// Increasing length tables for macroblock address increment codes. Table index i contains codes with bit length i + %d.\n", MIN_MAI_LENGTH);
printf("static const DecoderMAI maisByLength[%d][%d] = \n{\n", MAX_MAI_LENGTH - MIN_MAI_LENGTH + 1, MAX_MAIS_IN_LENGTH_CATEGORY);
for (i = 0; i < MAX_MAI_LENGTH - MIN_MAI_LENGTH + 1; i++)
{
printf(" {\n");
for (j = 0; j < MAX_MAIS_IN_LENGTH_CATEGORY; j++)
{
if (j < maiEntries[i]->size())
{
printf(" {0x%c%c, %d}%c\n", hexChar(((maiEntries[i]->at(j).code) & 0x00F0) >> 4),
hexChar((maiEntries[i]->at(j).code) & 0x000F), maiEntries[i]->at(j).increment,
j == MAX_MAIS_IN_LENGTH_CATEGORY - 1 ? ' ' : ',');
}
else
{
printf(" nullMAI%c\n",
j == MAX_MAIS_IN_LENGTH_CATEGORY - 1 ? ' ' : ',');
}
}
printf(" }%c\n", i == MAX_MAI_LENGTH - MIN_MAI_LENGTH ? ' ' : ',');
}
printf("};\n\n");
// Insert the entries to be classified by zero run length.
for (i = 0; i < VLC_ENTRY_COUNT; i++)
{
zRLEntries[vlcTables[i].zeroRunLength]->insert(zRLEntries[vlcTables[i].zeroRunLength]->end(), vlcTables[i]);
pLEntries[vlcTables[i].length]->insert(pLEntries[vlcTables[i].length]->end(), vlcTables[i]);
}
// The table entries have now been classified into both zero run length groupings and bit pattern length groupings.
// Write out the code for these tables to STDOUT.
for (i = 0; i < LAST_ZRL_FOR_OWN_TABLE + 1; i++)
{
printf("// Run/level %d/l is at %sZeroRunVLCTable[l - 1]\n", i, numbers[i]);
printf("static const VLCTableEntry %sZeroRunVLCTable[%d] = \n{\n", numbers[i], (int)zRLEntries[i]->size());
for (j = 0; j < zRLEntries[i]->size(); j++)
printf(" {0x%c%c, %d}%c\n", hexChar((zRLEntries[i]->at(j).code & 0x00F0) >> 4), hexChar(zRLEntries[i]->at(j).code & 0x000F),
zRLEntries[i]->at(j).length, j == zRLEntries[i]->size() - 1 ? ' ' : ',');
printf("};\n\n");
}
unsigned int pairsCount = 0;
for (i = LAST_ZRL_FOR_OWN_TABLE + 1; ; i++, pairsCount++)
if (zRLEntries[i]->size() != 2)
break;
// Table for pairs.
printf("// Run/level r/l for %d < r < %d is at pairsZeroRunVLCTable[r - %d][l].\n", LAST_ZRL_FOR_OWN_TABLE, LAST_ZRL_FOR_OWN_TABLE + pairsCount + 1, LAST_ZRL_FOR_OWN_TABLE + 1);
printf("static const VLCTableEntry pairsZeroRunVLCTable[%d][2] = \n{\n", pairsCount);
for (i = LAST_ZRL_FOR_OWN_TABLE + 1; i < LAST_ZRL_FOR_OWN_TABLE + pairsCount + 1; i++)
{
printf(" {\n ");
printf("{0x%c%c, %d}, {0x%c%c, %d}\n",
hexChar((zRLEntries[i]->at(0).code & 0x00F0) >> 4),
hexChar(zRLEntries[i]->at(0).code & 0x000F),
zRLEntries[i]->at(0).length,
hexChar((zRLEntries[i]->at(1).code & 0x00F0) >> 4),
hexChar(zRLEntries[i]->at(1).code & 0x000F),
zRLEntries[i]->at(1).length);
printf(" }%c\n", i == LAST_ZRL_FOR_OWN_TABLE + pairsCount ? ' ' : ',');
}
printf("};\n\n");
// Final table for the rest of the values.
printf("// Run/level r/l for r > %d is at singlesZeroRunVLCTable[r - %d].\n", LAST_ZRL_FOR_OWN_TABLE + pairsCount, LAST_ZRL_FOR_OWN_TABLE + pairsCount + 1);
printf("static const VLCTableEntry singlesZeroRunVLCTable[%d] = \n{\n", MAX_ZERO_RUN_LENGTH - (LAST_ZRL_FOR_OWN_TABLE + pairsCount));
for (i = LAST_ZRL_FOR_OWN_TABLE + pairsCount + 1; i < MAX_ZERO_RUN_LENGTH; i++)
{
printf(" {0x%c%c, %d}%c\n",
hexChar((zRLEntries[i]->at(0).code & 0x00F0) >> 4),
hexChar(zRLEntries[i]->at(0).code & 0x000F),
zRLEntries[i]->at(0).length,
i == MAX_ZERO_RUN_LENGTH - 1 ? ' ' : ',');
}
printf("};\n\n");
printf("// The decoder needs a table based on bit pattern length as index.\n");
printf("static const DecoderVLCEntry patternLengthVLCTable[%d][%d] = \n{\n", MAX_PATTERN_LENGTH - FIRST_PATTERN_LENGTH_WITH_ENTRIES, MAX_PATTERN_ENTRIES_AT_ANY_LENGTH);
for (i = FIRST_PATTERN_LENGTH_WITH_ENTRIES; i < MAX_PATTERN_LENGTH; i++)
{
printf(" {\n");
for (j = 0; j < MAX_PATTERN_ENTRIES_AT_ANY_LENGTH; j++)
{
if (j < pLEntries[i]->size())
{
printf(" {0x%c%c, %d, %d}%c\n",
hexChar((pLEntries[i]->at(j).code & 0x00F0) >> 4),
hexChar(pLEntries[i]->at(j).code & 0x000F),
pLEntries[i]->at(j).zeroRunLength,
pLEntries[i]->at(j).level,
j == MAX_PATTERN_ENTRIES_AT_ANY_LENGTH - 1 ? ' ' : ',');
}
else
{
// Put in a constant invalid VLC value as a sentinel on the size of this element of the table.
printf(" nullDecoderVLC%c\n",
j == MAX_PATTERN_ENTRIES_AT_ANY_LENGTH - 1 ? ' ' : ',');
}
}
printf(" }%c\n", i == MAX_PATTERN_LENGTH - 1 ? ' ' : ',');
}
printf("};\n");
for (i = 0; i < MAX_ZERO_RUN_LENGTH; i++)
delete zRLEntries[i];
for (i = 0; i < MAX_PATTERN_LENGTH; i++)
delete pLEntries[i];
delete[] zRLEntries;
delete[] pLEntries;
delete cbpEntries;
}