Chris@69: /* Copyright (c) 2001-2011 Timothy B. Terriberry Chris@69: Copyright (c) 2008-2009 Xiph.Org Foundation */ Chris@69: /* Chris@69: Redistribution and use in source and binary forms, with or without Chris@69: modification, are permitted provided that the following conditions Chris@69: are met: Chris@69: Chris@69: - Redistributions of source code must retain the above copyright Chris@69: notice, this list of conditions and the following disclaimer. Chris@69: Chris@69: - Redistributions in binary form must reproduce the above copyright Chris@69: notice, this list of conditions and the following disclaimer in the Chris@69: documentation and/or other materials provided with the distribution. Chris@69: Chris@69: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS Chris@69: ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT Chris@69: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR Chris@69: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER Chris@69: OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, Chris@69: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, Chris@69: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR Chris@69: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF Chris@69: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING Chris@69: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS Chris@69: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Chris@69: */ Chris@69: Chris@69: #if defined(HAVE_CONFIG_H) Chris@69: # include "config.h" Chris@69: #endif Chris@69: #include "os_support.h" Chris@69: #include "arch.h" Chris@69: #include "entenc.h" Chris@69: #include "mfrngcod.h" Chris@69: Chris@69: /*A range encoder. Chris@69: See entdec.c and the references for implementation details \cite{Mar79,MNW98}. Chris@69: Chris@69: @INPROCEEDINGS{Mar79, Chris@69: author="Martin, G.N.N.", Chris@69: title="Range encoding: an algorithm for removing redundancy from a digitised Chris@69: message", Chris@69: booktitle="Video \& Data Recording Conference", Chris@69: year=1979, Chris@69: address="Southampton", Chris@69: month=Jul Chris@69: } Chris@69: @ARTICLE{MNW98, Chris@69: author="Alistair Moffat and Radford Neal and Ian H. Witten", Chris@69: title="Arithmetic Coding Revisited", Chris@69: journal="{ACM} Transactions on Information Systems", Chris@69: year=1998, Chris@69: volume=16, Chris@69: number=3, Chris@69: pages="256--294", Chris@69: month=Jul, Chris@69: URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" Chris@69: }*/ Chris@69: Chris@69: static int ec_write_byte(ec_enc *_this,unsigned _value){ Chris@69: if(_this->offs+_this->end_offs>=_this->storage)return -1; Chris@69: _this->buf[_this->offs++]=(unsigned char)_value; Chris@69: return 0; Chris@69: } Chris@69: Chris@69: static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ Chris@69: if(_this->offs+_this->end_offs>=_this->storage)return -1; Chris@69: _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; Chris@69: return 0; Chris@69: } Chris@69: Chris@69: /*Outputs a symbol, with a carry bit. Chris@69: If there is a potential to propagate a carry over several symbols, they are Chris@69: buffered until it can be determined whether or not an actual carry will Chris@69: occur. Chris@69: If the counter for the buffered symbols overflows, then the stream becomes Chris@69: undecodable. Chris@69: This gives a theoretical limit of a few billion symbols in a single packet on Chris@69: 32-bit systems. Chris@69: The alternative is to truncate the range in order to force a carry, but Chris@69: requires similar carry tracking in the decoder, needlessly slowing it down.*/ Chris@69: static void ec_enc_carry_out(ec_enc *_this,int _c){ Chris@69: if(_c!=EC_SYM_MAX){ Chris@69: /*No further carry propagation possible, flush buffer.*/ Chris@69: int carry; Chris@69: carry=_c>>EC_SYM_BITS; Chris@69: /*Don't output a byte on the first write. Chris@69: This compare should be taken care of by branch-prediction thereafter.*/ Chris@69: if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); Chris@69: if(_this->ext>0){ Chris@69: unsigned sym; Chris@69: sym=(EC_SYM_MAX+carry)&EC_SYM_MAX; Chris@69: do _this->error|=ec_write_byte(_this,sym); Chris@69: while(--(_this->ext)>0); Chris@69: } Chris@69: _this->rem=_c&EC_SYM_MAX; Chris@69: } Chris@69: else _this->ext++; Chris@69: } Chris@69: Chris@69: static OPUS_INLINE void ec_enc_normalize(ec_enc *_this){ Chris@69: /*If the range is too small, output some bits and rescale it.*/ Chris@69: while(_this->rng<=EC_CODE_BOT){ Chris@69: ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); Chris@69: /*Move the next-to-high-order symbol into the high-order position.*/ Chris@69: _this->val=(_this->val<rng<<=EC_SYM_BITS; Chris@69: _this->nbits_total+=EC_SYM_BITS; Chris@69: } Chris@69: } Chris@69: Chris@69: void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){ Chris@69: _this->buf=_buf; Chris@69: _this->end_offs=0; Chris@69: _this->end_window=0; Chris@69: _this->nend_bits=0; Chris@69: /*This is the offset from which ec_tell() will subtract partial bits.*/ Chris@69: _this->nbits_total=EC_CODE_BITS+1; Chris@69: _this->offs=0; Chris@69: _this->rng=EC_CODE_TOP; Chris@69: _this->rem=-1; Chris@69: _this->val=0; Chris@69: _this->ext=0; Chris@69: _this->storage=_size; Chris@69: _this->error=0; Chris@69: } Chris@69: Chris@69: void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ Chris@69: opus_uint32 r; Chris@69: r=celt_udiv(_this->rng,_ft); Chris@69: if(_fl>0){ Chris@69: _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); Chris@69: _this->rng=IMUL32(r,(_fh-_fl)); Chris@69: } Chris@69: else _this->rng-=IMUL32(r,(_ft-_fh)); Chris@69: ec_enc_normalize(_this); Chris@69: } Chris@69: Chris@69: void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ Chris@69: opus_uint32 r; Chris@69: r=_this->rng>>_bits; Chris@69: if(_fl>0){ Chris@69: _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl)); Chris@69: _this->rng=IMUL32(r,(_fh-_fl)); Chris@69: } Chris@69: else _this->rng-=IMUL32(r,((1U<<_bits)-_fh)); Chris@69: ec_enc_normalize(_this); Chris@69: } Chris@69: Chris@69: /*The probability of having a "one" is 1/(1<<_logp).*/ Chris@69: void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ Chris@69: opus_uint32 r; Chris@69: opus_uint32 s; Chris@69: opus_uint32 l; Chris@69: r=_this->rng; Chris@69: l=_this->val; Chris@69: s=r>>_logp; Chris@69: r-=s; Chris@69: if(_val)_this->val=l+r; Chris@69: _this->rng=_val?s:r; Chris@69: ec_enc_normalize(_this); Chris@69: } Chris@69: Chris@69: void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ Chris@69: opus_uint32 r; Chris@69: r=_this->rng>>_ftb; Chris@69: if(_s>0){ Chris@69: _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); Chris@69: _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); Chris@69: } Chris@69: else _this->rng-=IMUL32(r,_icdf[_s]); Chris@69: ec_enc_normalize(_this); Chris@69: } Chris@69: Chris@69: void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){ Chris@69: unsigned ft; Chris@69: unsigned fl; Chris@69: int ftb; Chris@69: /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ Chris@69: celt_assert(_ft>1); Chris@69: _ft--; Chris@69: ftb=EC_ILOG(_ft); Chris@69: if(ftb>EC_UINT_BITS){ Chris@69: ftb-=EC_UINT_BITS; Chris@69: ft=(_ft>>ftb)+1; Chris@69: fl=(unsigned)(_fl>>ftb); Chris@69: ec_encode(_this,fl,fl+1,ft); Chris@69: ec_enc_bits(_this,_fl&(((opus_uint32)1<end_window; Chris@69: used=_this->nend_bits; Chris@69: celt_assert(_bits>0); Chris@69: if(used+_bits>EC_WINDOW_SIZE){ Chris@69: do{ Chris@69: _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); Chris@69: window>>=EC_SYM_BITS; Chris@69: used-=EC_SYM_BITS; Chris@69: } Chris@69: while(used>=EC_SYM_BITS); Chris@69: } Chris@69: window|=(ec_window)_fl<end_window=window; Chris@69: _this->nend_bits=used; Chris@69: _this->nbits_total+=_bits; Chris@69: } Chris@69: Chris@69: void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ Chris@69: int shift; Chris@69: unsigned mask; Chris@69: celt_assert(_nbits<=EC_SYM_BITS); Chris@69: shift=EC_SYM_BITS-_nbits; Chris@69: mask=((1<<_nbits)-1)<offs>0){ Chris@69: /*The first byte has been finalized.*/ Chris@69: _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<rem>=0){ Chris@69: /*The first byte is still awaiting carry propagation.*/ Chris@69: _this->rem=(_this->rem&~mask)|_val<rng<=(EC_CODE_TOP>>_nbits)){ Chris@69: /*The renormalization loop has never been run.*/ Chris@69: _this->val=(_this->val&~((opus_uint32)mask<error=-1; Chris@69: } Chris@69: Chris@69: void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){ Chris@69: celt_assert(_this->offs+_this->end_offs<=_size); Chris@69: OPUS_MOVE(_this->buf+_size-_this->end_offs, Chris@69: _this->buf+_this->storage-_this->end_offs,_this->end_offs); Chris@69: _this->storage=_size; Chris@69: } Chris@69: Chris@69: void ec_enc_done(ec_enc *_this){ Chris@69: ec_window window; Chris@69: int used; Chris@69: opus_uint32 msk; Chris@69: opus_uint32 end; Chris@69: int l; Chris@69: /*We output the minimum number of bits that ensures that the symbols encoded Chris@69: thus far will be decoded correctly regardless of the bits that follow.*/ Chris@69: l=EC_CODE_BITS-EC_ILOG(_this->rng); Chris@69: msk=(EC_CODE_TOP-1)>>l; Chris@69: end=(_this->val+msk)&~msk; Chris@69: if((end|msk)>=_this->val+_this->rng){ Chris@69: l++; Chris@69: msk>>=1; Chris@69: end=(_this->val+msk)&~msk; Chris@69: } Chris@69: while(l>0){ Chris@69: ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); Chris@69: end=(end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); Chris@69: /*If we have buffered extra bits, flush them as well.*/ Chris@69: window=_this->end_window; Chris@69: used=_this->nend_bits; Chris@69: while(used>=EC_SYM_BITS){ Chris@69: _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); Chris@69: window>>=EC_SYM_BITS; Chris@69: used-=EC_SYM_BITS; Chris@69: } Chris@69: /*Clear any excess space and add any remaining extra bits to the last byte.*/ Chris@69: if(!_this->error){ Chris@69: OPUS_CLEAR(_this->buf+_this->offs, Chris@69: _this->storage-_this->offs-_this->end_offs); Chris@69: if(used>0){ Chris@69: /*If there's no range coder data at all, give up.*/ Chris@69: if(_this->end_offs>=_this->storage)_this->error=-1; Chris@69: else{ Chris@69: l=-l; Chris@69: /*If we've busted, don't add too many extra bits to the last byte; it Chris@69: would corrupt the range coder data, and that's more important.*/ Chris@69: if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; Chris@69: } Chris@69: _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; Chris@69: } Chris@69: } Chris@69: } Chris@69: }