/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. (See .) This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. // MP3 internal implementation details (Huffman encoding) // Implementation #include "MP3InternalsHuffman.hh" #include #include #include MP3HuffmanEncodingInfo ::MP3HuffmanEncodingInfo(Boolean includeDecodedValues) { if (includeDecodedValues) { decodedValues = new unsigned[(SBLIMIT*SSLIMIT + 1)*4]; } else { decodedValues = NULL; } } MP3HuffmanEncodingInfo::~MP3HuffmanEncodingInfo() { delete[] decodedValues; } // This is crufty old code that needs to be cleaned up ##### static unsigned debugCount = 0; /* for debugging */ #define TRUNC_FAVORa void updateSideInfoForHuffman(MP3SideInfo& sideInfo, Boolean isMPEG2, unsigned char const* mainDataPtr, unsigned p23L0, unsigned p23L1, unsigned& part23Length0a, unsigned& part23Length0aTruncation, unsigned& part23Length0b, unsigned& part23Length0bTruncation, unsigned& part23Length1a, unsigned& part23Length1aTruncation, unsigned& part23Length1b, unsigned& part23Length1bTruncation) { int i, j; unsigned sfLength, origTotABsize, adjustment; MP3SideInfo::gr_info_s_t* gr; /* First, Huffman-decode each part of the segment's main data, to see at which bit-boundaries the samples appear: */ MP3HuffmanEncodingInfo hei; ++debugCount; #ifdef DEBUG fprintf(stderr, "usifh-start: p23L0: %d, p23L1: %d\n", p23L0, p23L1); #endif /* Process granule 0 */ { gr = &(sideInfo.ch[0].gr[0]); origTotABsize = gr->part2_3_length; MP3HuffmanDecode(gr, isMPEG2, mainDataPtr, 0, origTotABsize, sfLength, hei); /* Begin by computing new sizes for parts a & b (& their truncations) */ #ifdef DEBUG fprintf(stderr, "usifh-0: %d, %d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", hei.numSamples, sfLength/8, sfLength%8, hei.reg1Start/8, hei.reg1Start%8, hei.reg2Start/8, hei.reg2Start%8, hei.bigvalStart/8, hei.bigvalStart%8, origTotABsize/8, origTotABsize%8); #endif if (p23L0 < sfLength) { /* We can't use this, so give it all to the next granule: */ p23L1 += p23L0; p23L0 = 0; } part23Length0a = hei.bigvalStart; part23Length0b = origTotABsize - hei.bigvalStart; part23Length0aTruncation = part23Length0bTruncation = 0; if (origTotABsize > p23L0) { /* We need to shorten one or both of fields a & b */ unsigned truncation = origTotABsize - p23L0; #ifdef TRUNC_FAIRLY part23Length0aTruncation = (truncation*(part23Length0a-sfLength)) /(origTotABsize-sfLength); part23Length0bTruncation = truncation - part23Length0aTruncation; #endif #ifdef TRUNC_FAVORa part23Length0bTruncation = (truncation > part23Length0b) ? part23Length0b : truncation; part23Length0aTruncation = truncation - part23Length0bTruncation; #endif #ifdef TRUNC_FAVORb part23Length0aTruncation = (truncation > part23Length0a-sfLength) ? (part23Length0a-sfLength) : truncation; part23Length0bTruncation = truncation - part23Length0aTruncation; #endif } /* ASSERT: part23Length0xTruncation <= part23Length0x */ part23Length0a -= part23Length0aTruncation; part23Length0b -= part23Length0bTruncation; #ifdef DEBUG fprintf(stderr, "usifh-0: interim sizes: %d (%d), %d (%d)\n", part23Length0a, part23Length0aTruncation, part23Length0b, part23Length0bTruncation); #endif /* Adjust these new lengths so they end on sample bit boundaries: */ for (i = 0; i < (int)hei.numSamples; ++i) { if (hei.allBitOffsets[i] == part23Length0a) break; else if (hei.allBitOffsets[i] > part23Length0a) {--i; break;} } if (i < 0) { /* should happen only if we couldn't fit sfLength */ i = 0; adjustment = 0; } else { adjustment = part23Length0a - hei.allBitOffsets[i]; } #ifdef DEBUG fprintf(stderr, "%d usifh-0: adjustment 1: %d\n", debugCount, adjustment); #endif part23Length0a -= adjustment; part23Length0aTruncation += adjustment; /* Assign the bits we just shaved to field b and granule 1: */ if (part23Length0bTruncation < adjustment) { p23L1 += (adjustment - part23Length0bTruncation); adjustment = part23Length0bTruncation; } part23Length0b += adjustment; part23Length0bTruncation -= adjustment; for (j = i; j < (int)hei.numSamples; ++j) { if (hei.allBitOffsets[j] == part23Length0a + part23Length0aTruncation + part23Length0b) break; else if (hei.allBitOffsets[j] > part23Length0a + part23Length0aTruncation + part23Length0b) {--j; break;} } if (j < 0) { /* should happen only if we couldn't fit sfLength */ j = 0; adjustment = 0; } else { adjustment = part23Length0a+part23Length0aTruncation+part23Length0b - hei.allBitOffsets[j]; } #ifdef DEBUG fprintf(stderr, "%d usifh-0: adjustment 2: %d\n", debugCount, adjustment); #endif if (adjustment > part23Length0b) adjustment = part23Length0b; /*sanity*/ part23Length0b -= adjustment; part23Length0bTruncation += adjustment; /* Assign the bits we just shaved to granule 1 */ p23L1 += adjustment; if (part23Length0aTruncation > 0) { /* Change the granule's 'big_values' field to reflect the truncation */ gr->big_values = i; } } /* Process granule 1 (MPEG-1 only) */ if (isMPEG2) { part23Length1a = part23Length1b = 0; part23Length1aTruncation = part23Length1bTruncation = 0; } else { unsigned granule1Offset = origTotABsize + sideInfo.ch[1].gr[0].part2_3_length; gr = &(sideInfo.ch[0].gr[1]); origTotABsize = gr->part2_3_length; MP3HuffmanDecode(gr, isMPEG2, mainDataPtr, granule1Offset, origTotABsize, sfLength, hei); /* Begin by computing new sizes for parts a & b (& their truncations) */ #ifdef DEBUG fprintf(stderr, "usifh-1: %d, %d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", hei.numSamples, sfLength/8, sfLength%8, hei.reg1Start/8, hei.reg1Start%8, hei.reg2Start/8, hei.reg2Start%8, hei.bigvalStart/8, hei.bigvalStart%8, origTotABsize/8, origTotABsize%8); #endif if (p23L1 < sfLength) { /* We can't use this, so give up on this granule: */ p23L1 = 0; } part23Length1a = hei.bigvalStart; part23Length1b = origTotABsize - hei.bigvalStart; part23Length1aTruncation = part23Length1bTruncation = 0; if (origTotABsize > p23L1) { /* We need to shorten one or both of fields a & b */ unsigned truncation = origTotABsize - p23L1; #ifdef TRUNC_FAIRLY part23Length1aTruncation = (truncation*(part23Length1a-sfLength)) /(origTotABsize-sfLength); part23Length1bTruncation = truncation - part23Length1aTruncation; #endif #ifdef TRUNC_FAVORa part23Length1bTruncation = (truncation > part23Length1b) ? part23Length1b : truncation; part23Length1aTruncation = truncation - part23Length1bTruncation; #endif #ifdef TRUNC_FAVORb part23Length1aTruncation = (truncation > part23Length1a-sfLength) ? (part23Length1a-sfLength) : truncation; part23Length1bTruncation = truncation - part23Length1aTruncation; #endif } /* ASSERT: part23Length1xTruncation <= part23Length1x */ part23Length1a -= part23Length1aTruncation; part23Length1b -= part23Length1bTruncation; #ifdef DEBUG fprintf(stderr, "usifh-1: interim sizes: %d (%d), %d (%d)\n", part23Length1a, part23Length1aTruncation, part23Length1b, part23Length1bTruncation); #endif /* Adjust these new lengths so they end on sample bit boundaries: */ for (i = 0; i < (int)hei.numSamples; ++i) { if (hei.allBitOffsets[i] == part23Length1a) break; else if (hei.allBitOffsets[i] > part23Length1a) {--i; break;} } if (i < 0) { /* should happen only if we couldn't fit sfLength */ i = 0; adjustment = 0; } else { adjustment = part23Length1a - hei.allBitOffsets[i]; } #ifdef DEBUG fprintf(stderr, "%d usifh-1: adjustment 0: %d\n", debugCount, adjustment); #endif part23Length1a -= adjustment; part23Length1aTruncation += adjustment; /* Assign the bits we just shaved to field b: */ if (part23Length1bTruncation < adjustment) { adjustment = part23Length1bTruncation; } part23Length1b += adjustment; part23Length1bTruncation -= adjustment; for (j = i; j < (int)hei.numSamples; ++j) { if (hei.allBitOffsets[j] == part23Length1a + part23Length1aTruncation + part23Length1b) break; else if (hei.allBitOffsets[j] > part23Length1a + part23Length1aTruncation + part23Length1b) {--j; break;} } if (j < 0) { /* should happen only if we couldn't fit sfLength */ j = 0; adjustment = 0; } else { adjustment = part23Length1a+part23Length1aTruncation+part23Length1b - hei.allBitOffsets[j]; } #ifdef DEBUG fprintf(stderr, "%d usifh-1: adjustment 1: %d\n", debugCount, adjustment); #endif if (adjustment > part23Length1b) adjustment = part23Length1b; /*sanity*/ part23Length1b -= adjustment; part23Length1bTruncation += adjustment; if (part23Length1aTruncation > 0) { /* Change the granule's 'big_values' field to reflect the truncation */ gr->big_values = i; } } #ifdef DEBUG fprintf(stderr, "usifh-end, new vals: %d (%d), %d (%d), %d (%d), %d (%d)\n", part23Length0a, part23Length0aTruncation, part23Length0b, part23Length0bTruncation, part23Length1a, part23Length1aTruncation, part23Length1b, part23Length1bTruncation); #endif } static void rsf_getline(char* line, unsigned max, unsigned char**fi) { unsigned i; for (i = 0; i < max; ++i) { line[i] = *(*fi)++; if (line[i] == '\n') { line[i++] = '\0'; return; } } line[i] = '\0'; } static void rsfscanf(unsigned char **fi, unsigned int* v) { while (sscanf((char*)*fi, "%x", v) == 0) { /* skip past the next '\0' */ while (*(*fi)++ != '\0') {} } /* skip past any white-space before the value: */ while (*(*fi) <= ' ') ++(*fi); /* skip past the value: */ while (*(*fi) > ' ') ++(*fi); } #define HUFFBITS unsigned long int #define SIZEOF_HUFFBITS 4 #define HTN 34 #define MXOFF 250 struct huffcodetab { char tablename[3]; /*string, containing table_description */ unsigned int xlen; /*max. x-index+ */ unsigned int ylen; /*max. y-index+ */ unsigned int linbits; /*number of linbits */ unsigned int linmax; /*max number to be stored in linbits */ int ref; /*a positive value indicates a reference*/ HUFFBITS *table; /*pointer to array[xlen][ylen] */ unsigned char *hlen; /*pointer to array[xlen][ylen] */ unsigned char(*val)[2];/*decoder tree */ unsigned int treelen; /*length of decoder tree */ }; static struct huffcodetab rsf_ht[HTN]; // array of all huffcodetable headers /* 0..31 Huffman code table 0..31 */ /* 32,33 count1-tables */ /* read the huffman decoder table */ static int read_decoder_table(unsigned char* fi) { int n,i,nn,t; unsigned int v0,v1; char command[100],line[100]; for (n=0;nscalefac_compress]; int num1 = slen[1][gr_info->scalefac_compress]; if (gr_info->block_type == 2) { numbits = (num0 + num1) * 18; if (gr_info->mixed_block_flag) { numbits -= num0; /* num0 * 17 + num1 * 18 */ } } else { int scfsi = gr_info->scfsi; if(scfsi < 0) { /* scfsi < 0 => granule == 0 */ numbits = (num0 + num1) * 10 + num0; } else { numbits = 0; if(!(scfsi & 0x8)) { numbits += num0 * 6; } else { } if(!(scfsi & 0x4)) { numbits += num0 * 5; } else { } if(!(scfsi & 0x2)) { numbits += num1 * 5; } else { } if(!(scfsi & 0x1)) { numbits += num1 * 5; } else { } } } return numbits; } extern unsigned n_slen2[]; extern unsigned i_slen2[]; static unsigned rsf_get_scale_factors_2(MP3SideInfo::gr_info_s_t *gr_info) { unsigned char const* pnt; int i; unsigned int slen; int n = 0; int numbits = 0; slen = n_slen2[gr_info->scalefac_compress]; gr_info->preflag = (slen>>15) & 0x1; n = 0; if( gr_info->block_type == 2 ) { n++; if(gr_info->mixed_block_flag) n++; } pnt = stab[n][(slen>>12)&0x7]; for(i=0;i<4;i++) { int num = slen & 0x7; slen >>= 3; numbits += pnt[i] * num; } return numbits; } static unsigned getScaleFactorsLength(MP3SideInfo::gr_info_s_t* gr, Boolean isMPEG2) { return isMPEG2 ? rsf_get_scale_factors_2(gr) : rsf_get_scale_factors_1(gr); } static int rsf_huffman_decoder(BitVector& bv, struct huffcodetab const* h, int* x, int* y, int* v, int* w); // forward void MP3HuffmanDecode(MP3SideInfo::gr_info_s_t* gr, Boolean isMPEG2, unsigned char const* fromBasePtr, unsigned fromBitOffset, unsigned fromLength, unsigned& scaleFactorsLength, MP3HuffmanEncodingInfo& hei) { unsigned i; int x, y, v, w; struct huffcodetab *h; BitVector bv((unsigned char*)fromBasePtr, fromBitOffset, fromLength); /* Compute the size of the scale factors (& also advance bv): */ scaleFactorsLength = getScaleFactorsLength(gr, isMPEG2); bv.skipBits(scaleFactorsLength); initialize_huffman(); hei.reg1Start = hei.reg2Start = hei.numSamples = 0; /* Read bigvalues area. */ if (gr->big_values < gr->region1start + gr->region2start) { gr->big_values = gr->region1start + gr->region2start; /* sanity check */ } for (i = 0; i < gr->big_values; ++i) { if (i < gr->region1start) { /* in region 0 */ h = &rsf_ht[gr->table_select[0]]; } else if (i < gr->region2start) { /* in region 1 */ h = &rsf_ht[gr->table_select[1]]; if (hei.reg1Start == 0) { hei.reg1Start = bv.curBitIndex(); } } else { /* in region 2 */ h = &rsf_ht[gr->table_select[2]]; if (hei.reg2Start == 0) { hei.reg2Start = bv.curBitIndex(); } } hei.allBitOffsets[i] = bv.curBitIndex(); rsf_huffman_decoder(bv, h, &x, &y, &v, &w); if (hei.decodedValues != NULL) { // Record the decoded values: unsigned* ptr = &hei.decodedValues[4*i]; ptr[0] = x; ptr[1] = y; ptr[2] = v; ptr[3] = w; } } hei.bigvalStart = bv.curBitIndex(); /* Read count1 area. */ h = &rsf_ht[gr->count1table_select+32]; while (bv.curBitIndex() < bv.totNumBits() && i < SSLIMIT*SBLIMIT) { hei.allBitOffsets[i] = bv.curBitIndex(); rsf_huffman_decoder(bv, h, &x, &y, &v, &w); if (hei.decodedValues != NULL) { // Record the decoded values: unsigned* ptr = &hei.decodedValues[4*i]; ptr[0] = x; ptr[1] = y; ptr[2] = v; ptr[3] = w; } ++i; } hei.allBitOffsets[i] = bv.curBitIndex(); hei.numSamples = i; } HUFFBITS dmask = 1 << (SIZEOF_HUFFBITS*8-1); unsigned int hs = SIZEOF_HUFFBITS*8; /* do the huffman-decoding */ static int rsf_huffman_decoder(BitVector& bv, struct huffcodetab const* h, // ptr to huffman code record /* unsigned */ int *x, // returns decoded x value /* unsigned */ int *y, // returns decoded y value int* v, int* w) { HUFFBITS level; unsigned point = 0; int error = 1; level = dmask; *x = *y = *v = *w = 0; if (h->val == NULL) return 2; /* table 0 needs no bits */ if (h->treelen == 0) return 0; /* Lookup in Huffman table. */ do { if (h->val[point][0]==0) { /*end of tree*/ *x = h->val[point][1] >> 4; *y = h->val[point][1] & 0xf; error = 0; break; } if (bv.get1Bit()) { while (h->val[point][1] >= MXOFF) point += h->val[point][1]; point += h->val[point][1]; } else { while (h->val[point][0] >= MXOFF) point += h->val[point][0]; point += h->val[point][0]; } level >>= 1; } while (level || (point < h->treelen) ); ///// } while (level || (point < rsf_ht->treelen) ); /* Check for error. */ if (error) { /* set x and y to a medium value as a simple concealment */ printf("Illegal Huffman code in data.\n"); *x = ((h->xlen-1) << 1); *y = ((h->ylen-1) << 1); } /* Process sign encodings for quadruples tables. */ if (h->tablename[0] == '3' && (h->tablename[1] == '2' || h->tablename[1] == '3')) { *v = (*y>>3) & 1; *w = (*y>>2) & 1; *x = (*y>>1) & 1; *y = *y & 1; if (*v) if (bv.get1Bit() == 1) *v = -*v; if (*w) if (bv.get1Bit() == 1) *w = -*w; if (*x) if (bv.get1Bit() == 1) *x = -*x; if (*y) if (bv.get1Bit() == 1) *y = -*y; } /* Process sign and escape encodings for dual tables. */ else { if (h->linbits) if ((h->xlen-1) == (unsigned)*x) *x += bv.getBits(h->linbits); if (*x) if (bv.get1Bit() == 1) *x = -*x; if (h->linbits) if ((h->ylen-1) == (unsigned)*y) *y += bv.getBits(h->linbits); if (*y) if (bv.get1Bit() == 1) *y = -*y; } return error; } #ifdef DO_HUFFMAN_ENCODING inline int getNextSample(unsigned char const*& fromPtr) { int sample #ifdef FOUR_BYTE_SAMPLES = (fromPtr[0]<<24) | (fromPtr[1]<<16) | (fromPtr[2]<<8) | fromPtr[3]; #else #ifdef TWO_BYTE_SAMPLES = (fromPtr[0]<<8) | fromPtr[1]; #else // ONE_BYTE_SAMPLES = fromPtr[0]; #endif #endif fromPtr += BYTES_PER_SAMPLE_VALUE; return sample; } static void rsf_huffman_encoder(BitVector& bv, struct huffcodetab* h, int x, int y, int v, int w); // forward unsigned MP3HuffmanEncode(MP3SideInfo::gr_info_s_t const* gr, unsigned char const* fromPtr, unsigned char* toPtr, unsigned toBitOffset, unsigned numHuffBits) { unsigned i; struct huffcodetab *h; int x, y, v, w; BitVector bv(toPtr, toBitOffset, numHuffBits); initialize_huffman(); // Encode big_values area: unsigned big_values = gr->big_values; if (big_values < gr->region1start + gr->region2start) { big_values = gr->region1start + gr->region2start; /* sanity check */ } for (i = 0; i < big_values; ++i) { if (i < gr->region1start) { /* in region 0 */ h = &rsf_ht[gr->table_select[0]]; } else if (i < gr->region2start) { /* in region 1 */ h = &rsf_ht[gr->table_select[1]]; } else { /* in region 2 */ h = &rsf_ht[gr->table_select[2]]; } x = getNextSample(fromPtr); y = getNextSample(fromPtr); v = getNextSample(fromPtr); w = getNextSample(fromPtr); rsf_huffman_encoder(bv, h, x, y, v, w); } // Encode count1 area: h = &rsf_ht[gr->count1table_select+32]; while (bv.curBitIndex() < bv.totNumBits() && i < SSLIMIT*SBLIMIT) { x = getNextSample(fromPtr); y = getNextSample(fromPtr); v = getNextSample(fromPtr); w = getNextSample(fromPtr); rsf_huffman_encoder(bv, h, x, y, v, w); ++i; } return i; } static Boolean lookupHuffmanTableEntry(struct huffcodetab const* h, HUFFBITS bits, unsigned bitsLength, unsigned char& xy) { unsigned point = 0; unsigned mask = 1; unsigned numBitsTestedSoFar = 0; do { if (h->val[point][0]==0) { // end of tree xy = h->val[point][1]; if (h->hlen[xy] == 0) { // this entry hasn't already been used h->table[xy] = bits; h->hlen[xy] = bitsLength; return True; } else { // this entry has already been seen return False; } } if (numBitsTestedSoFar++ == bitsLength) { // We don't yet have enough bits for this prefix return False; } if (bits&mask) { while (h->val[point][1] >= MXOFF) point += h->val[point][1]; point += h->val[point][1]; } else { while (h->val[point][0] >= MXOFF) point += h->val[point][0]; point += h->val[point][0]; } mask <<= 1; } while (mask || (point < h->treelen)); return False; } static void buildHuffmanEncodingTable(struct huffcodetab* h) { h->table = new unsigned long[256]; h->hlen = new unsigned char[256]; if (h->table == NULL || h->hlen == NULL) { h->table = NULL; return; } for (unsigned i = 0; i < 256; ++i) { h->table[i] = 0; h->hlen[i] = 0; } // Look up entries for each possible bit sequence length: unsigned maxNumEntries = h->xlen * h->ylen; unsigned numEntries = 0; unsigned powerOf2 = 1; for (unsigned bitsLength = 1; bitsLength <= 8*SIZEOF_HUFFBITS; ++bitsLength) { powerOf2 *= 2; for (HUFFBITS bits = 0; bits < powerOf2; ++bits) { // Find the table value - if any - for 'bits' (length 'bitsLength'): unsigned char xy; if (lookupHuffmanTableEntry(h, bits, bitsLength, xy)) { ++numEntries; if (numEntries == maxNumEntries) return; // we're done } } } #ifdef DEBUG fprintf(stderr, "Didn't find enough entries!\n"); // shouldn't happen #endif } static void lookupXYandPutBits(BitVector& bv, struct huffcodetab const* h, unsigned char xy) { HUFFBITS bits = h->table[xy]; unsigned bitsLength = h->hlen[xy]; // Note that "bits" is in reverse order, so read them from right-to-left: while (bitsLength-- > 0) { bv.put1Bit(bits&0x00000001); bits >>= 1; } } static void putLinbits(BitVector& bv, struct huffcodetab const* h, HUFFBITS bits) { bv.putBits(bits, h->linbits); } static void rsf_huffman_encoder(BitVector& bv, struct huffcodetab* h, int x, int y, int v, int w) { if (h->val == NULL) return; /* table 0 produces no bits */ if (h->treelen == 0) return; if (h->table == NULL) { // We haven't yet built the encoding array for this table; do it now: buildHuffmanEncodingTable(h); if (h->table == NULL) return; } Boolean xIsNeg = False, yIsNeg = False, vIsNeg = False, wIsNeg = False; unsigned char xy; #ifdef FOUR_BYTE_SAMPLES #else #ifdef TWO_BYTE_SAMPLES // Convert 2-byte negative numbers to their 4-byte equivalents: if (x&0x8000) x |= 0xFFFF0000; if (y&0x8000) y |= 0xFFFF0000; if (v&0x8000) v |= 0xFFFF0000; if (w&0x8000) w |= 0xFFFF0000; #else // ONE_BYTE_SAMPLES // Convert 1-byte negative numbers to their 4-byte equivalents: if (x&0x80) x |= 0xFFFFFF00; if (y&0x80) y |= 0xFFFFFF00; if (v&0x80) v |= 0xFFFFFF00; if (w&0x80) w |= 0xFFFFFF00; #endif #endif if (h->tablename[0] == '3' && (h->tablename[1] == '2' || h->tablename[1] == '3')) {// quad tables if (x < 0) { xIsNeg = True; x = -x; } if (y < 0) { yIsNeg = True; y = -y; } if (v < 0) { vIsNeg = True; v = -v; } if (w < 0) { wIsNeg = True; w = -w; } // Sanity check: x,y,v,w must all be 0 or 1: if (x>1 || y>1 || v>1 || w>1) { #ifdef DEBUG fprintf(stderr, "rsf_huffman_encoder quad sanity check fails: %x,%x,%x,%x\n", x, y, v, w); #endif } xy = (v<<3)|(w<<2)|(x<<1)|y; lookupXYandPutBits(bv, h, xy); if (v) bv.put1Bit(vIsNeg); if (w) bv.put1Bit(wIsNeg); if (x) bv.put1Bit(xIsNeg); if (y) bv.put1Bit(yIsNeg); } else { // dual tables // Sanity check: v and w must be 0: if (v != 0 || w != 0) { #ifdef DEBUG fprintf(stderr, "rsf_huffman_encoder dual sanity check 1 fails: %x,%x,%x,%x\n", x, y, v, w); #endif } if (x < 0) { xIsNeg = True; x = -x; } if (y < 0) { yIsNeg = True; y = -y; } // Sanity check: x and y must be <= 255: if (x > 255 || y > 255) { #ifdef DEBUG fprintf(stderr, "rsf_huffman_encoder dual sanity check 2 fails: %x,%x,%x,%x\n", x, y, v, w); #endif } int xl1 = h->xlen-1; int yl1 = h->ylen-1; unsigned linbitsX = 0; unsigned linbitsY = 0; if (((x < xl1) || (xl1 == 0)) && (y < yl1)) { // normal case xy = (x<<4)|y; lookupXYandPutBits(bv, h, xy); if (x) bv.put1Bit(xIsNeg); if (y) bv.put1Bit(yIsNeg); } else if (x >= xl1) { linbitsX = (unsigned)(x - xl1); if (linbitsX > h->linmax) { #ifdef DEBUG fprintf(stderr,"warning: Huffman X table overflow\n"); #endif linbitsX = h->linmax; }; if (y >= yl1) { xy = (xl1<<4)|yl1; lookupXYandPutBits(bv, h, xy); linbitsY = (unsigned)(y - yl1); if (linbitsY > h->linmax) { #ifdef DEBUG fprintf(stderr,"warning: Huffman Y table overflow\n"); #endif linbitsY = h->linmax; }; if (h->linbits) putLinbits(bv, h, linbitsX); if (x) bv.put1Bit(xIsNeg); if (h->linbits) putLinbits(bv, h, linbitsY); if (y) bv.put1Bit(yIsNeg); } else { /* x >= h->xlen, y < h->ylen */ xy = (xl1<<4)|y; lookupXYandPutBits(bv, h, xy); if (h->linbits) putLinbits(bv, h, linbitsX); if (x) bv.put1Bit(xIsNeg); if (y) bv.put1Bit(yIsNeg); } } else { /* ((x < h->xlen) && (y >= h->ylen)) */ xy = (x<<4)|yl1; lookupXYandPutBits(bv, h, xy); linbitsY = y-yl1; if (linbitsY > h->linmax) { #ifdef DEBUG fprintf(stderr,"warning: Huffman Y table overflow\n"); #endif linbitsY = h->linmax; }; if (x) bv.put1Bit(xIsNeg); if (h->linbits) putLinbits(bv, h, linbitsY); if (y) bv.put1Bit(yIsNeg); } } } #endif