Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

arithcodec.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002     arithcodec.cpp  -  Definitions of ArithCodec methods
00003                              -------------------
00004     begin                : June 21 2002
00005     copyright            : (C) 2003 by Vojtìch Toman
00006     email                : vtoman@lit.cz
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 /* Based on code by:                                                       */
00019 
00020 /***************************************************************************
00021 Authors:        John Carpinelli   (johnfc@ecr.mu.oz.au)
00022                 Wayne Salamonsen  (wbs@mundil.cs.mu.oz.au)
00023                 Lang Stuiver      (langs@cs.mu.oz.au)
00024                 Radford Neal      (radford@ai.toronto.edu)
00025 
00026 Purpose:        Data compression using a revised arithmetic coding method.
00027 
00028 Based on:       A. Moffat, R. Neal, I.H. Witten, "Arithmetic Coding Revisted",
00029                 Proc. IEEE Data Compression Conference, Snowbird, Utah, 
00030                 March 1995.
00031 
00032                 Low-Precision Arithmetic Coding Implementation by 
00033                 Radford M. Neal
00034 
00035 
00036 
00037 Copyright 1995 John Carpinelli and Wayne Salamonsen, All Rights Reserved.
00038 Copyright 1996 Lang Stuiver, All Rights Reserved.
00039 
00040 These programs are supplied free of charge for research purposes only,
00041 and may not sold or incorporated into any commercial product.  There is
00042 ABSOLUTELY NO WARRANTY of any sort, nor any undertaking that they are
00043 fit for ANY PURPOSE WHATSOEVER.  Use them at your own risk.  If you do
00044 happen to find a bug, or have modifications to suggest, please report
00045 the same to Alistair Moffat, alistair@cs.mu.oz.au.  The copyright
00046 notice above and this statement of conditions must remain an integral
00047 part of each and every copy made of these files.
00048 ****************************************************************************/
00049 
00050 
00059 #ifdef __GNUG__
00060 #pragma implementation
00061 #endif
00062 
00063 #include "arithcodec.h"
00064 
00065 
00073 #define OUTPUT_BIT(b)                   \
00074 {                                       \
00075   outBuffer <<= 1;                      \
00076   if (b)                                \
00077     outBuffer |= 1;                     \
00078   outBitsToGo--;                        \
00079   if (outBitsToGo == 0)                 \
00080     {                                   \
00081       outputDevice->putChar(outBuffer); \
00082       numberOfBytes++;                  \
00083       outBitsToGo = BYTE_SIZE;          \
00084       outBuffer = 0;                    \
00085     }                                   \
00086 }                                               
00087 
00088 
00089 
00097 #define UNGET_BIT(b)                    \
00098 {                                       \
00099   inBitPtr <<= 1;                       \
00100                                         \
00101   if (inBitPtr == 0)                    \
00102     inBitPtr = 1;                       \
00103                                         \
00104   /* Only keep bits still to be read */ \
00105   inBuffer = inBuffer & (inBitPtr - 1); \
00106   if (b)                                \
00107     /* Replace bit */                   \
00108     inBuffer |= inBitPtr;               \
00109 }
00110 
00111 
00112 
00121 #define ADD_NEXT_INPUT_BIT(v, garbageBits)                              \
00122 {                                                                       \
00123   if (inBitPtr == 0)                                                    \
00124     {                                                                   \
00125       if (inputDevice->getChar(&inBuffer) == EndOfFile)                 \
00126         {                                                               \
00127           inGarbage++;                                                  \
00128           if ((FreqValue)((inGarbage-1)*8) >= garbageBits)              \
00129             FATAL("Bad input file - attempted read past end of file."); \
00130         }                                                               \
00131       inBitPtr = (1<<(BYTE_SIZE-1));                                    \
00132     }                                                                   \
00133     v <<= 1;                                                            \
00134                                                                         \
00135   if (inBuffer & inBitPtr)                                              \
00136     v++;                                                                \
00137                                                                         \
00138   inBitPtr >>= 1;                                                       \
00139 }
00140 
00141 
00142 
00148 #define ORIG_BIT_PLUS_FOLLOW(b)         \
00149 {                                       \
00150   OUTPUT_BIT(b);                        \
00151                                         \
00152   while (outBitsOutstanding > 0)        \
00153     {                                   \
00154       OUTPUT_BIT(!b);                   \
00155       outBitsOutstanding--;             \
00156     }                                   \
00157 }
00158 
00159 
00160 #ifdef FRUGAL_BITS
00161 
00166 # define BIT_PLUS_FOLLOW(x)                     \
00167    {                                            \
00168      if (ignoreFirstBit)                        \
00169        ignoreFirstBit = 0;                      \
00170      else                                       \
00171        ORIG_BIT_PLUS_FOLLOW(x);                 \
00172    }
00173 
00174 #else
00175 
00181 # define BIT_PLUS_FOLLOW(x)             ORIG_BIT_PLUS_FOLLOW(x)
00182 
00183 #endif
00184 
00188 #define ENCODE_RENORMALISE              \
00189 {                                       \
00190   while (out_R <= Quarter)              \
00191     {                                   \
00192       if (out_L >= Half)                \
00193         {                               \
00194           BIT_PLUS_FOLLOW(1);           \
00195           out_L -= Half;                \
00196         }                               \
00197       else                              \
00198         if (out_L+out_R <= Half)        \
00199           {                             \
00200             BIT_PLUS_FOLLOW(0);         \
00201           }                             \
00202         else                            \
00203           {                             \
00204             outBitsOutstanding++;       \
00205             out_L -= Quarter;           \
00206           }                             \
00207       out_L <<= 1;                      \
00208       out_R <<= 1;                      \
00209   }                                     \
00210 }
00211 
00212 
00213 #ifdef FRUGAL_BITS
00214 
00218 # define DECODE_RENORMALISE                     \
00219    {                                            \
00220      while (in_R <= Quarter)                    \
00221        {                                        \
00222          in_R <<= 1;                            \
00223          in_V <<= 1;                            \
00224          ADD_NEXT_INPUT_BIT(in_D,B_BITS);       \
00225          if (in_D & 1)                          \
00226            in_V++;                              \
00227        }                                        \
00228    }
00229 
00230 #else
00231 
00235 # define DECODE_RENORMALISE             \
00236    {                                    \
00237      while (in_R <= Quarter)            \
00238        {                                \
00239          in_R <<= 1;                    \
00240          ADD_NEXT_INPUT_BIT(in_D,0);    \
00241        }                                \
00242    }
00243 
00244 #endif
00245 
00246 
00247 
00251 ArithCodec::ArithCodec(void)
00252   : ArithCodecBase()
00253 {
00254   outputDevice = 0;
00255 
00256 
00257 #ifdef FRUGAL_BITS
00258   ignoreFirstBit = 1;
00259   firstMessage = 1;
00260 #endif
00261 
00262   numberOfBytes = 0;    //number of output bytes
00263 
00264   inBuffer = 0;         //I/O buffer
00265   inBitPtr = 0;         //bits left in buffer
00266   inGarbage = 0;        //bytes read beyond eof
00267   
00268   outBuffer = 0;        //I/O buffer
00269   outBitsToGo = 0;      //bits to fill buffer
00270 }
00271 
00272 
00273 
00274 
00278 void ArithCodec::startOutputtingBits(void)
00279 {
00280   outBuffer = 0;
00281   outBitsToGo = BYTE_SIZE;
00282 }
00283 
00287 void ArithCodec::startInputtingBits(void)
00288 {
00289   inGarbage = 0;        //Number of bytes read past end of file
00290   inBitPtr = 0;         //No valid bits yet in input buffer
00291 }
00292 
00293 
00294 
00298 void ArithCodec::doneOutputtingBits(void)
00299 {
00300   if (outBitsToGo != BYTE_SIZE)
00301     {
00302       outputDevice->putChar(outBuffer << outBitsToGo);
00303       numberOfBytes++;
00304     }
00305   outBitsToGo = BYTE_SIZE;
00306 }
00307 
00311 void ArithCodec::doneInputtingBits(void)
00312 {
00313   inBitPtr = 0;         //"Wipe" buffer (in case more input follows)
00314 }
00315 
00316 
00317 
00318 //  /*!
00319 //    Sets output device for the encoder.
00320 
00321 //    \param od Output device.
00322 //   */
00323 //  void ArithCodec::setOutputDevice(IODevice *od)
00324 //  {
00325 //    if (outputDevice)
00326 //      {
00327 //        WRN("ArithCodec: Output device already specified, ommiting new.");
00328 //      }
00329 //    else
00330 //      outputDevice = od;
00331 //  }
00332 
00333 
00334 
00335 //  /*!
00336 //    Sets input device for the decoder.
00337 
00338 //    \param id Input device.
00339 //   */
00340 //  void ArithCodec::setInputDevice(IODevice *id)
00341 //  {
00342 //    if (inputDevice)
00343 //      {
00344 //        WRN("ArithCodec: Input device already specified, ommiting new.");
00345 //      }
00346 //    else
00347 //      inputDevice = id;
00348 //  }
00349 
00350 
00351 
00377 void ArithCodec::arithmeticEncode(FreqValue low, FreqValue high, FreqValue total)
00378 { 
00379   CodeValue temp; 
00380 
00381 #ifdef MULT_DIV
00382   {
00383     DivValue out_r;                     
00384     out_r = out_R/total;        //Calc range:freq ratio
00385     temp = out_r*low;           //Calc low increment
00386     out_L += temp;              //Increase L
00387     if (high < total)
00388       out_R = out_r*(high-low); //Restrict R
00389     else
00390       out_R -= temp;            //If at end of freq range
00391 
00392     //Give symbol excess code range
00393   }
00394 #else
00395   {
00396     CodeValue A, M;             //A = numerator, M = denominator
00397     CodeValue temp2;
00398 
00399     
00400     //calculate r = R/total, temp = r*low and temp2 = r*high
00401     //using shifts and adds  (r need not be stored as it is implicit in the loop)
00402 
00403     A = out_R;
00404     temp = 0;
00405     temp2 = 0;
00406 
00407     M = total << (B_BITS - F_BITS - 1);
00408     if (A >= M) { A -= M; temp += low; temp2 += high; }
00409 
00410 #define UNROLL_NUM      B_BITS - F_BITS - 1
00411 #define UNROLL_CODE                             \
00412     A <<= 1; temp <<= 1; temp2 <<= 1;           \
00413     if (A >= M)                                 \
00414       {                                         \
00415         A -= M; temp += low; temp2 += high;     \
00416       }
00417 
00418 #include "unroll.h"             //unroll the above code
00419 
00420     out_L += temp;
00421     if (high < total)
00422       out_R = temp2 - temp;
00423     else
00424       out_R -= temp;
00425   }
00426 #endif
00427 
00428   ENCODE_RENORMALISE;
00429 
00430   if (outBitsOutstanding > MAX_BITS_OUTSTANDING)
00431     //For MAX_BITS_OUTSTANDING to be exceeded is extremely improbable, but
00432     //it is possible. For this to occur the COMPRESSED file would need to
00433     //contain a sequence MAX_BITS_OUTSTANDING bits long (eg: 2^31 bits, or
00434     //256 megabytes) of all 1 bits or all 0 bits. This possibility is
00435     //extremely remote (especially with an adaptive model), and can only
00436     //occur if the compressed file is greater than MAX_BITS_OUTSTANDING
00437     //long. Assuming the compressed file is effectively random,
00438     //the probability for any 256 megabyte section causing an overflow
00439     //would be 1 in 2^(2^31). This is a number approximately 600 million
00440     //digits long (decimal).
00441     FATAL("Bits_outstanding limit reached - File too large!");
00442 }
00443 
00444 
00445 
00471 FreqValue ArithCodec::arithmeticDecodeTarget(FreqValue total)
00472 {
00473   FreqValue target;
00474     
00475 #ifdef MULT_DIV
00476   in_r = in_R/total;
00477   target = (in_D)/in_r;
00478 #else 
00479   {     
00480     CodeValue A, M;     //A = numerator, M = denominator
00481 
00482     //divide r = R/total using shifts and adds
00483     A = in_R;
00484     in_r = 0;
00485 
00486     M = total << ( B_BITS - F_BITS - 1 );
00487     if (A >= M) { A -= M; in_r++; }
00488 
00489 #define UNROLL_NUM      B_BITS - F_BITS - 1
00490 #define UNROLL_CODE                     \
00491     A <<= 1; in_r <<= 1;                \
00492     if (A >= M)                         \
00493       {                                 \
00494         A -= M; in_r++;                 \
00495       }
00496 
00497 #include "unroll.h"
00498 
00499     A = in_D;
00500     target = 0;
00501     if (in_r < (1 << (B_BITS - F_BITS - 1)))
00502       { M = in_r << F_BITS; 
00503       if (A >= M) { A -= M; target++; } 
00504       A <<= 1; target <<= 1;            
00505       }
00506     else
00507       {
00508         M = in_r << (F_BITS - 1);
00509       }
00510 
00511     if (A >= M) { A -= M; target++; }
00512 
00513 
00514 #define UNROLL_NUM      F_BITS - 1
00515 #define UNROLL_CODE                     \
00516     A <<= 1; target <<= 1;              \
00517     if (A >= M)                         \
00518       {                                 \
00519         A -= M; target++;               \
00520       } 
00521 
00522 #include "unroll.h"
00523 
00524   }
00525 #endif //shifts vs multiply
00526 
00527   return (target >= total ? total-1 : target);
00528 }
00529 
00530 
00531 
00551 void ArithCodec::arithmeticDecode(FreqValue low, FreqValue high, FreqValue total)
00552 {     
00553   CodeValue temp;
00554 
00555 #ifdef MULT_DIV
00556   //assume r has been set by decode_target
00557   temp = in_r*low;
00558   in_D -= temp;
00559   if (high < total)
00560     in_R = in_r*(high-low);
00561   else
00562     in_R -= temp;
00563 #else
00564   {
00565     CodeValue temp2, M;
00566     
00567     //calculate r*low and r*high using shifts and adds
00568     temp = 0;
00569     temp2 = 0;
00570 
00571     M = in_r << F_BITS;
00572 
00573     if (M & Half) { temp += low; temp2 += high; }
00574 
00575 #define UNROLL_NUM  B_BITS - F_BITS - 1
00576 #define UNROLL_CODE                             \
00577     M <<= 1; temp <<= 1; temp2 <<= 1;           \
00578     if (M & Half)                               \
00579       {                                         \
00580         temp += low; temp2 += high;             \
00581       }
00582 
00583 #include "unroll.h"
00584 
00585 
00586     in_D -= temp;
00587     if (high < total)
00588       in_R = temp2 - temp;
00589     else
00590       in_R -= temp;
00591   }
00592 #endif //shifts vs multiply
00593 
00594   DECODE_RENORMALISE;
00595 }
00596 
00597 
00598 
00602 void ArithCodec::startEncode(void)
00603 {
00604   out_L = 0;                    //Set initial coding range to
00605   out_R = Half;                 //[0,Half)
00606   outBitsOutstanding = 0;
00607 #ifdef FRUGAL_BITS
00608   ignoreFirstBit = 1;           //Don't ouput the leading 0
00609 #endif
00610 }
00611 
00612 
00613 
00614 #ifdef FRUGAL_BITS
00615 
00620 void ArithCodec::finishEncode(void)
00621 {
00622   unsigned int nbits, i;
00623   CodeValue roundup, bits, value;
00624 
00625   bits = 0;
00626   nbits = 0;
00627 
00628   for (nbits = 1; nbits <= B_BITS; nbits++)
00629     {
00630       roundup = (1 << (B_BITS - nbits)) - 1;
00631       bits = (out_L + roundup) >> (B_BITS - nbits);
00632       value = bits << (B_BITS - nbits);
00633       if (out_L <= value && value + roundup <= (out_L + (out_R - 1)) )
00634         break;
00635     }
00636   for (i = 1; i <= nbits; i++)
00637     //output the nbits integer bits
00638     BIT_PLUS_FOLLOW(((bits >> (nbits-i)) & 1));
00639 }
00640 #else
00641 
00642 
00647 void ArithCodec::finishEncode(void)
00648 {
00649   int nbits, i;
00650   CodeValue bits;
00651   
00652   nbits = B_BITS;
00653   bits  = out_L;
00654   for (i = 1; i <= nbits; i++)
00655     //output the nbits integer bits
00656     BIT_PLUS_FOLLOW(((bits >> (nbits-i)) & 1));
00657 }
00658 #endif
00659 
00660 
00668 void ArithCodec::startDecode(void)
00669 {
00670   unsigned int i;
00671   
00672   in_D = 0;             //Initial offset in range is 0
00673   in_R = Half;          //Range = Half
00674   
00675 #ifdef FRUGAL_BITS
00676   {
00677     
00678     if (firstMessage)
00679       {
00680         for (i = 0; i < B_BITS-1; i++)
00681           ADD_NEXT_INPUT_BIT(in_D, B_BITS);
00682       }
00683     else
00684       {
00685         in_D = retrieveExcessInputBits();
00686         UNGET_BIT(in_D & 1);
00687         in_D >>=1;
00688       }
00689     
00690     firstMessage = 0;
00691     in_V = in_D;
00692   }
00693 #else
00694   for (i = 0; i<B_BITS; i++)    //Fill D
00695     ADD_NEXT_INPUT_BIT(in_D, 0);
00696 #endif
00697 
00698   if (in_D >= Half)
00699     FATAL("Corrupt input file.");
00700 }
00701 
00702 #ifdef FRUGAL_BITS
00703 
00708 void ArithCodec::finishDecode(void)
00709 {
00710   unsigned int nbits, i;
00711   CodeValue roundup, bits, value;
00712   CodeValue in_L;
00713   
00714   //This gets us either the real L, or L + Half.  Either way, we can work
00715   //out the number of bit emitted by the encoder
00716   in_L = (in_V & (Half-1))+ Half - in_D;
00717   
00718   for (nbits = 1; nbits <= B_BITS; nbits++)
00719     {
00720       roundup = (1 << (B_BITS - nbits)) - 1;
00721       bits = (in_L + roundup) >> (B_BITS - nbits);
00722       value = bits << (B_BITS - nbits);
00723       if (in_L <= value && value + roundup <= (in_L + (in_R - 1)) )
00724         break;
00725     }
00726 
00727   //No bits to consume
00728   if (nbits > B_BITS)
00729     return;
00730   else
00731     for (i = 1; i <= nbits; i++)
00732       {
00733         ADD_NEXT_INPUT_BIT(in_V, B_BITS);
00734       }
00735 }
00736 
00742 CodeValue ArithCodec::retrieveExcessInputBits(void)
00743 {
00744   return (in_V & (Half + (Half-1)) );
00745 }
00746 
00747 #else
00748 
00752 void ArithCodec::finishDecode(void)
00753 {
00754   //No action
00755 }
00756 #endif
00757 
00758 size_t ArithCodec::numberOfOutputBytes(void)
00759 {
00760   return numberOfBytes;
00761 }

Generated on Wed Feb 5 10:43:01 2003 for Exalt by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002