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; }