diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
commit | 1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch) | |
tree | 64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/ppm/ppmtompeg/postdct.c | |
download | netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip |
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/ppm/ppmtompeg/postdct.c')
-rw-r--r-- | converter/ppm/ppmtompeg/postdct.c | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/converter/ppm/ppmtompeg/postdct.c b/converter/ppm/ppmtompeg/postdct.c new file mode 100644 index 00000000..56a23de9 --- /dev/null +++ b/converter/ppm/ppmtompeg/postdct.c @@ -0,0 +1,626 @@ +/*===========================================================================* + * postdct.c * + * * + * Procedures concerned with MPEG post-DCT processing: * + * quantization and RLE Huffman encoding * + * * + * EXPORTED PROCEDURES: * + * Mpost_QuantZigBlock * + * Mpost_RLEHuffIBlock * + * Mpost_RLEHuffPBlock * + * Mpost_UnQuantZigBlock * + * * + *===========================================================================*/ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * $Header: /n/picasso/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/postdct.c,v 1.12 1995/06/21 18:26:39 smoot Exp $ + * $Log: postdct.c,v $ + * Revision 1.12 1995/06/21 18:26:39 smoot + * added length estimator for P-blocks + * + * Revision 1.11 1995/04/23 23:22:59 eyhung + * nothing changed + * + * Revision 1.10 1995/04/14 23:10:46 smoot + * Added overflow detection to MPOST_DCT so it will adjust Qscales (above) + * + * Revision 1.9 1995/02/15 23:15:32 smoot + * killed useless asserts + * + * Revision 1.8 1995/02/01 21:48:41 smoot + * assure out is set properly, short circuit 0 revquant + * + * Revision 1.7 1995/01/30 19:56:37 smoot + * Killed a <0 shift + * + * Revision 1.6 1995/01/25 23:07:33 smoot + * Better DBG_PRINTs, multiply/divide instead of shifts + * + * Revision 1.5 1995/01/19 23:09:10 eyhung + * Changed copyrights + * + * Revision 1.4 1995/01/16 08:17:08 eyhung + * added realQuiet + * + * Revision 1.3 1994/11/12 02:11:58 keving + * nothing + * + * Revision 1.2 1994/03/15 00:27:11 keving + * nothing + * + * Revision 1.2 1994/03/15 00:27:11 keving + * nothing + * + * Revision 1.1 1993/12/22 19:19:01 keving + * nothing + * + * Revision 1.11 1993/07/22 22:23:43 keving + * nothing + * + * Revision 1.10 1993/06/30 20:06:09 keving + * nothing + * + * Revision 1.9 1993/06/03 21:08:08 keving + * nothing + * + * Revision 1.8 1993/02/24 18:57:19 keving + * nothing + * + * Revision 1.7 1993/02/23 22:58:36 keving + * nothing + * + * Revision 1.6 1993/02/23 22:54:56 keving + * nothing + * + * Revision 1.5 1993/02/17 23:18:20 dwallach + * checkin prior to keving's joining the project + * + * Revision 1.4 1993/01/18 10:20:02 dwallach + * *** empty log message *** + * + * Revision 1.3 1993/01/18 10:17:29 dwallach + * RCS headers installed, code indented uniformly + * + * Revision 1.3 1993/01/18 10:17:29 dwallach + * RCS headers installed, code indented uniformly + * + */ + + +/*==============* + * HEADER FILES * + *==============*/ + +#include <assert.h> +#include "all.h" +#include "mtypes.h" +#include "bitio.h" +#include "huff.h" +#include "postdct.h" +#include "opts.h" + +/*==================* + * STATIC VARIABLES * + *==================*/ + +/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */ +int ZAG[] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +/* + * possible optimization: reorder the qtable in the correct zigzag order, to + * reduce the number of necessary lookups + * + * this table comes from the MPEG draft, p. D-16, Fig. 2-D.15. + */ +int32 qtable[] = { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +}; + +int32 niqtable[] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16 +}; + +int32 *customQtable = NULL; +int32 *customNIQtable = NULL; + +/*==================* + * GLOBAL VARIABLES * + *==================*/ + +extern boolean realQuiet; + +/*=====================* + * EXPORTED PROCEDURES * + *=====================*/ + +/*===========================================================================* + * + * Mpost_UnQuantZigBlock + * + * unquantize and zig-zag (decode) a single block + * see section 2.4.4.1 of MPEG standard + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +void +Mpost_UnQuantZigBlock(in, out, qscale, iblock) + FlatBlock in; + Block out; + int qscale; + boolean iblock; +{ + register int index; + int start; + int position; + register int qentry; + int level, coeff; + + if ( iblock ) { + /* qtable[0] must be 8 */ + out[0][0] = (int16)(in[0] * 8); + + /* don't need to do anything fancy here, because we saved orig + value, not encoded dc value */ + start = 1; + } else { + start = 0; + } + + for ( index = start; index < DCTSIZE_SQ; index++ ) { + position = ZAG[index]; + level = in[index]; + + if (level == 0) { + ((int16 *)out)[position] = 0; + continue; + } + + + if ( iblock ) { + qentry = qtable[position] * qscale; + coeff = (level*qentry)/8; + if ( (coeff & 1) == 0 ) { + if ( coeff < 0 ) { + coeff++; + } else if ( coeff > 0 ) { + coeff--; + } + } + } else { + qentry = niqtable[position] * qscale; + if ( level == 0 ) { + coeff = 0; + } else if ( level < 0 ) { + coeff = (((2*level)-1)*qentry) / 16; + if ( (coeff & 1) == 0 ) { + coeff++; + } + } else { + coeff = (((2*level)+1)*qentry) >> 4; + if ( (coeff & 1) == 0 ) { + coeff--; + } + } + + if ( coeff > 2047 ) { + coeff = 2047; + } else if ( coeff < -2048 ) { + coeff = -2048; + } + } + + ((int16 *)out)[position] = coeff; + } +} + + +/*===========================================================================* + * + * Mpost_QuantZigBlock + * + * quantize and zigzags a block + * + * RETURNS: MPOST_OVERFLOW if a generated value is outside |255| + * MPOST_ZERO if all coeffs are zero + * MPOST_NON_ZERO otherwisw + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +int +Mpost_QuantZigBlock(in, out, qscale, iblock) + Block in; + FlatBlock out; + register int qscale; + int iblock; +{ + register int i; + register int16 temp; + register int qentry; + register int position; + boolean nonZero = FALSE; + boolean overflow = FALSE; + + DBG_PRINT(("Mpost_QuantZigBlock...\n")); + if (iblock) { + /* + * the DC coefficient is handled specially -- it's not + * sensitive to qscale, but everything else is + */ + temp = ((int16 *) in)[ZAG[0]]; + qentry = qtable[ZAG[0]]; + + if (temp < 0) { + temp = -temp; + temp += (qentry >> 1); + temp /= qentry; + temp = -temp; + } else { + temp += (qentry >> 1); + temp /= qentry; + } + if ( temp != 0 ) { + nonZero = TRUE; + } + out[0] = temp; + + for (i = 1; i < DCTSIZE_SQ; i++) { + position = ZAG[i]; + temp = ((int16 *) in)[position]; + qentry = qtable[position] * qscale; + + /* see 1993 MPEG doc, section D.6.3.4 */ + if (temp < 0) { + temp = -temp; + temp = (temp << 3); /* temp > 0 */ + temp += (qentry >> 1); + temp /= qentry; + temp = -temp; + } else { + temp = (temp << 3); /* temp > 0 */ + temp += (qentry >> 1); + temp /= qentry; + } + + if ( temp != 0 ) { + nonZero = TRUE; + out[i] = temp; + if (temp < -255) { + temp = -255; + overflow = TRUE; + } else if (temp > 255) { + temp = 255; + overflow = TRUE; + } + } else out[i]=0; + } + } else { + for (i = 0; i < DCTSIZE_SQ; i++) { + position = ZAG[i]; + temp = ((int16 *) in)[position]; + + /* multiply by non-intra qtable */ + qentry = qscale * niqtable[position]; + + /* see 1993 MPEG doc, D.6.4.5 */ + temp *= 8; + temp /= qentry; /* truncation toward 0 -- correct */ + + if ( temp != 0 ) { + nonZero = TRUE; + out[i] = temp; + if (temp < -255) { + temp = -255; + overflow = TRUE; + } else if (temp > 255) { + temp = 255; + overflow = TRUE; + } + + } else out[i]=0; + } + } + + if (overflow) return MPOST_OVERFLOW; + if (nonZero) return MPOST_NON_ZERO; + return MPOST_ZERO; +} + + + +/*===========================================================================* + * + * Mpost_RLEHuffIBlock + * + * generate the huffman bits from an I-block + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +void +Mpost_RLEHuffIBlock(in, out) + FlatBlock in; + BitBucket *out; +{ + register int i; + register int nzeros = 0; + register int16 cur; + register int16 acur; + register uint32 code; + register int nbits; + + /* + * yes, Virginia, we start at 1. The DC coefficient is handled + * specially, elsewhere. Not here. + */ + for (i = 1; i < DCTSIZE_SQ; i++) { + cur = in[i]; + acur = ABS(cur); + if (cur) { + if ( (nzeros < HUFF_MAXRUN) && (acur < huff_maxlevel[nzeros])) { + /* + * encode using the Huffman tables + */ + + DBG_PRINT(("rle_huff %02d.%02d: Run %02d, Level %4d\n", i, ZAG[i], nzeros, cur)); + code = (huff_table[nzeros])[acur]; + nbits = (huff_bits[nzeros])[acur]; + + if (cur < 0) { + code |= 1; /* the sign bit */ + } + Bitio_Write(out, code, nbits); + } else { + /* + * encode using the escape code + */ + DBG_PRINT(("Escape\n")); + Bitio_Write(out, 0x1, 6); /* ESCAPE */ + DBG_PRINT(("Run Length\n")); + Bitio_Write(out, nzeros, 6); /* Run-Length */ + + /* + * this shouldn't happen, but the other + * choice is to bomb out and dump core... + * Hmmm, seems to happen with small Qtable entries (1) -srs + */ + if (cur < -255) { + cur = -255; + } else if (cur > 255) { + cur = 255; + } + + DBG_PRINT(("Level\n")); + if (acur < 128) { + Bitio_Write(out, cur, 8); + } else { + if (cur < 0) { + Bitio_Write(out, 0x8001 + cur + 255, 16); + } else { + Bitio_Write(out, cur, 16); + } + } + } + nzeros = 0; + } else { + nzeros++; + } + } + DBG_PRINT(("End of block\n")); + Bitio_Write(out, 0x2, 2); /* end of block marker */ +} + + +/*===========================================================================* + * + * Mpost_RLEHuffPBlock + * + * generate the huffman bits from an P-block + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +void +Mpost_RLEHuffPBlock(in, out) + FlatBlock in; + BitBucket *out; +{ + register int i; + register int nzeros = 0; + register int16 cur; + register int16 acur; + register uint32 code; + register int nbits; + boolean first_dct = TRUE; + + /* + * yes, Virginia, we start at 0. + */ + for (i = 0; i < DCTSIZE_SQ; i++) { + cur = in[i]; + acur = ABS(cur); + if (cur) { + if ((nzeros < HUFF_MAXRUN) && (acur < huff_maxlevel[nzeros])) { + /* + * encode using the Huffman tables + */ + + DBG_PRINT(("rle_huff %02d.%02d: Run %02d, Level %4d\n", i, ZAG[i], nzeros, cur)); + if ( first_dct && (nzeros == 0) && (acur == 1) ) { + /* actually, only needs = 0x2 */ + code = (cur == 1) ? 0x2 : 0x3; + nbits = 2; + } else { + code = (huff_table[nzeros])[acur]; + nbits = (huff_bits[nzeros])[acur]; + } + + assert(nbits); + + if (cur < 0) { + code |= 1; /* the sign bit */ + } + Bitio_Write(out, code, nbits); + first_dct = FALSE; + } else { + /* + * encode using the escape code + */ + DBG_PRINT(("Escape\n")); + Bitio_Write(out, 0x1, 6); /* ESCAPE */ + DBG_PRINT(("Run Length\n")); + Bitio_Write(out, nzeros, 6); /* Run-Length */ + + /* + * this shouldn't happen, but the other + * choice is to bomb out and dump core... + * Hmmm, seems to happen with small Qtable entries (1) -srs + */ + if (cur < -255) { + cur = -255; + } else if (cur > 255) { + cur = 255; + } + + DBG_PRINT(("Level\n")); + if (acur < 128) { + Bitio_Write(out, cur, 8); + } else { + if (cur < 0) { + Bitio_Write(out, 0x8001 + cur + 255, 16); + } else { + Bitio_Write(out, cur, 16); + } + } + + first_dct = FALSE; + } + nzeros = 0; + } else { + nzeros++; + } + } + + /* actually, should REALLY return FALSE and not use this! */ + + if ( first_dct ) { /* have to give a first_dct even if all 0's */ + fprintf(stderr, "HUFF called with all-zero coefficients\n"); + fprintf(stderr, "exiting...\n"); + exit(1); + } + + DBG_PRINT(("End of block\n")); + Bitio_Write(out, 0x2, 2); /* end of block marker */ +} + + +/*===========================================================================* + * + * CalcRLEHuffLength + * + * count the huffman bits for an P-block + * + * RETURNS: number of bits + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +int +CalcRLEHuffLength(in) + FlatBlock in; +{ + register int i; + register int nzeros = 0; + register int16 cur; + register int16 acur; + register int nbits; + register int countbits=0; + boolean first_dct = TRUE; + + for (i = 0; i < DCTSIZE_SQ; i++) { + cur = in[i]; + acur = ABS(cur); + if (cur) { + if ((nzeros < HUFF_MAXRUN) && (acur < huff_maxlevel[nzeros])) { + /* + * encode using the Huffman tables + */ + + if ( first_dct && (nzeros == 0) && (acur == 1) ) { + nbits = 2; + } else { + nbits = (huff_bits[nzeros])[acur]; + } + countbits += nbits; + first_dct = FALSE; + } else { + countbits += 12; /* ESCAPE + runlength */ + + if (acur < 128) { + countbits += 8; + } else { + countbits += 16; + } + + first_dct = FALSE; + } + nzeros = 0; + } else { + nzeros++; + } + } + + countbits += 2; /* end of block marker */ + return countbits; +} |