| /* Copyright (c) 2001-2011 Timothy B. Terriberry |
| Copyright (c) 2008-2009 Xiph.Org Foundation */ |
| /* |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| - Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| - Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
| CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <stddef.h> |
| #include "os_support.h" |
| #include "arch.h" |
| #include "entdec.h" |
| #include "mfrngcod.h" |
| |
| |
| |
| /*A range decoder. |
| This is an entropy decoder based upon \cite{Mar79}, which is itself a |
| rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. |
| It is very similar to arithmetic encoding, except that encoding is done with |
| digits in any base, instead of with bits, and so it is faster when using |
| larger bases (i.e.: a byte). |
| The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ |
| is the base, longer than the theoretical optimum, but to my knowledge there |
| is no published justification for this claim. |
| This only seems true when using near-infinite precision arithmetic so that |
| the process is carried out with no rounding errors. |
| |
| IBM (the author's employer) never sought to patent the idea, and to my |
| knowledge the algorithm is unencumbered by any patents, though its |
| performance is very competitive with proprietary arithmetic coding. |
| The two are based on very similar ideas, however. |
| An excellent description of implementation details is available at |
| http://www.arturocampos.com/ac_range.html |
| A recent work \cite{MNW98} which proposes several changes to arithmetic |
| encoding for efficiency actually re-discovers many of the principles |
| behind range encoding, and presents a good theoretical analysis of them. |
| |
| End of stream is handled by writing out the smallest number of bits that |
| ensures that the stream will be correctly decoded regardless of the value of |
| any subsequent bits. |
| ec_tell() can be used to determine how many bits were needed to decode |
| all the symbols thus far; other data can be packed in the remaining bits of |
| the input buffer. |
| @PHDTHESIS{Pas76, |
| author="Richard Clark Pasco", |
| title="Source coding algorithms for fast data compression", |
| school="Dept. of Electrical Engineering, Stanford University", |
| address="Stanford, CA", |
| month=May, |
| year=1976 |
| } |
| @INPROCEEDINGS{Mar79, |
| author="Martin, G.N.N.", |
| title="Range encoding: an algorithm for removing redundancy from a digitised |
| message", |
| booktitle="Video & Data Recording Conference", |
| year=1979, |
| address="Southampton", |
| month=Jul |
| } |
| @ARTICLE{MNW98, |
| author="Alistair Moffat and Radford Neal and Ian H. Witten", |
| title="Arithmetic Coding Revisited", |
| journal="{ACM} Transactions on Information Systems", |
| year=1998, |
| volume=16, |
| number=3, |
| pages="256--294", |
| month=Jul, |
| URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" |
| }*/ |
| |
| |
| |
| static int ec_read_byte(ec_dec *_this){ |
| return _this->offs<_this->storage?_this->buf[_this->offs++]:0; |
| } |
| |
| static int ec_read_byte_from_end(ec_dec *_this){ |
| return _this->end_offs<_this->storage? |
| _this->buf[_this->storage-++(_this->end_offs)]:0; |
| } |
| |
| |
| /*Normalizes the contents of val and rng so that rng lies entirely in the |
| high-order symbol.*/ |
| static void ec_dec_normalize(ec_dec *_this){ |
| /*If the range is too small, rescale it and input some bits.*/ |
| while(_this->rng<=EC_CODE_BOT){ |
| int sym; |
| _this->nbits_total+=EC_SYM_BITS; |
| _this->rng<<=EC_SYM_BITS; |
| /*Use up the remaining bits from our last symbol.*/ |
| sym=_this->rem; |
| /*Read the next value from the input.*/ |
| _this->rem=ec_read_byte(_this); |
| /*Take the rest of the bits we need from this new symbol.*/ |
| sym=(sym<<EC_SYM_BITS|_this->rem)>>EC_SYM_BITS-EC_CODE_EXTRA; |
| /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ |
| _this->val=(_this->val<<EC_SYM_BITS)+(EC_SYM_MAX&~sym)&EC_CODE_TOP-1; |
| } |
| } |
| |
| void ec_dec_init(ec_dec *_this,unsigned char *_buf,celt_uint32 _storage){ |
| _this->buf=_buf; |
| _this->storage=_storage; |
| _this->end_offs=0; |
| _this->end_window=0; |
| _this->nend_bits=0; |
| _this->offs=0; |
| _this->rng=1U<<EC_CODE_EXTRA; |
| _this->rem=ec_read_byte(_this); |
| _this->val=_this->rng-1-(_this->rem>>EC_SYM_BITS-EC_CODE_EXTRA); |
| _this->error=0; |
| /*Normalize the interval.*/ |
| ec_dec_normalize(_this); |
| /*This is the offset from which ec_tell() will subtract partial bits. |
| This must be after the initial ec_dec_normalize(), or you will have to |
| compensate for the bits that are read there.*/ |
| _this->nbits_total=EC_CODE_BITS+1; |
| } |
| |
| |
| unsigned ec_decode(ec_dec *_this,unsigned _ft){ |
| unsigned s; |
| _this->ext=_this->rng/_ft; |
| s=(unsigned)(_this->val/_this->ext); |
| return _ft-EC_MINI(s+1,_ft); |
| } |
| |
| unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ |
| unsigned s; |
| _this->ext=_this->rng>>_bits; |
| s=(unsigned)(_this->val/_this->ext); |
| return (1<<_bits)-EC_MINI(s+1,1<<_bits); |
| } |
| |
| void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ |
| celt_uint32 s; |
| s=IMUL32(_this->ext,_ft-_fh); |
| _this->val-=s; |
| _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; |
| ec_dec_normalize(_this); |
| } |
| |
| /*The probability of having a "one" is 1/(1<<_logp).*/ |
| int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ |
| celt_uint32 r; |
| celt_uint32 d; |
| celt_uint32 s; |
| int ret; |
| r=_this->rng; |
| d=_this->val; |
| s=r>>_logp; |
| ret=d<s; |
| if(!ret)_this->val=d-s; |
| _this->rng=ret?s:r-s; |
| ec_dec_normalize(_this); |
| return ret; |
| } |
| |
| int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ |
| celt_uint32 r; |
| celt_uint32 d; |
| celt_uint32 s; |
| celt_uint32 t; |
| int ret; |
| s=_this->rng; |
| d=_this->val; |
| r=s>>_ftb; |
| ret=-1; |
| do{ |
| t=s; |
| s=IMUL32(r,_icdf[++ret]); |
| } |
| while(d<s); |
| _this->val=d-s; |
| _this->rng=t-s; |
| ec_dec_normalize(_this); |
| return ret; |
| } |
| |
| celt_uint32 ec_dec_uint(ec_dec *_this,celt_uint32 _ft){ |
| unsigned ft; |
| unsigned s; |
| int ftb; |
| /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ |
| celt_assert(_ft>1); |
| _ft--; |
| ftb=EC_ILOG(_ft); |
| if(ftb>EC_UINT_BITS){ |
| celt_uint32 t; |
| ftb-=EC_UINT_BITS; |
| ft=(unsigned)(_ft>>ftb)+1; |
| s=ec_decode(_this,ft); |
| ec_dec_update(_this,s,s+1,ft); |
| t=(celt_uint32)s<<ftb|ec_dec_bits(_this,ftb); |
| if(t<=_ft)return t; |
| _this->error=1; |
| return _ft; |
| } |
| else{ |
| _ft++; |
| s=ec_decode(_this,(unsigned)_ft); |
| ec_dec_update(_this,s,s+1,(unsigned)_ft); |
| return s; |
| } |
| } |
| |
| celt_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ |
| ec_window window; |
| int available; |
| celt_uint32 ret; |
| window=_this->end_window; |
| available=_this->nend_bits; |
| if(available<_bits){ |
| do{ |
| window|=(ec_window)ec_read_byte_from_end(_this)<<available; |
| available+=EC_SYM_BITS; |
| } |
| while(available<=EC_WINDOW_SIZE-EC_SYM_BITS); |
| } |
| ret=(celt_uint32)window&((celt_uint32)1<<_bits)-1; |
| window>>=_bits; |
| available-=_bits; |
| _this->end_window=window; |
| _this->nend_bits=available; |
| _this->nbits_total+=_bits; |
| return ret; |
| } |