diff --git a/libentcode/ectest.c b/libentcode/ectest.c index 18d42bf1d478127532f75c008f4b362aa53dbd13..85994dcfe9b6032fed1a4e855698e0a5eefe35cb 100644 --- a/libentcode/ectest.c +++ b/libentcode/ectest.c @@ -11,6 +11,7 @@ int main(int _argc,char **_argv){ ec_probmod mod; ec_uint64 sym64; long nbits; + long nbits2; double entropy; int ft; int ftb; @@ -33,12 +34,10 @@ int main(int _argc,char **_argv){ /*Testing encoding of raw bit values.*/ for(ftb=0;ftb<16;ftb++){ for(i=0;i<(1<<ftb);i++){ - long nbits; - long nbits2; entropy+=ftb; - nbits=ec_enc_tell(&enc); + nbits=ec_enc_tell(&enc,0); ec_enc_bits(&enc,i,ftb); - nbits2=ec_enc_tell(&enc); + nbits2=ec_enc_tell(&enc,0); if(nbits2-nbits!=ftb){ fprintf(stderr,"Used %li bits to encode %i bits directly.\n", nbits2-nbits,ftb); @@ -46,7 +45,7 @@ int main(int _argc,char **_argv){ entropy+=ftb+30; nbits=nbits2; ec_enc_bits64(&enc,(ec_uint64)i<<30|i,ftb+30); - nbits2=ec_enc_tell(&enc); + nbits2=ec_enc_tell(&enc,0); if(nbits2-nbits!=ftb+30){ fprintf(stderr,"Used %li bits to encode %i bits directly.\n", nbits2-nbits,ftb+30); @@ -73,7 +72,7 @@ int main(int _argc,char **_argv){ } ec_probmod_clear(&mod); } - nbits=ec_enc_tellf(&enc,4); + nbits=ec_enc_tell(&enc,4); ec_enc_done(&enc); fprintf(stderr, "Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n", @@ -133,6 +132,12 @@ int main(int _argc,char **_argv){ } ec_probmod_clear(&mod); } + nbits2=ec_dec_tell(&dec,4); + if(nbits!=nbits2){ + fprintf(stderr, + "Reported number of bits used was %0.2lf, should be %0.2lf.\n", + ldexp(nbits2,-4),ldexp(nbits,-4)); + } ec_byte_writeclear(&buf); fprintf(stderr,"All tests passed.\n"); return 0; diff --git a/libentcode/entdec.h b/libentcode/entdec.h index bedb55eaf644644847958570e8a42bfbebe2465a..423c574ef5cd53a9e1339190893176b3634365f6 100644 --- a/libentcode/entdec.h +++ b/libentcode/entdec.h @@ -86,4 +86,17 @@ ec_uint32 ec_dec_uint(ec_dec *_this,ec_uint32 _ft); Return: The decoded bits.*/ ec_uint64 ec_dec_uint64(ec_dec *_this,ec_uint64 _ft); +/*Returns the number of bits "used" by the decoded symbols so far. + The actual number of bits may be larger, due to rounding to whole bytes, or + smaller, due to trailing zeros that were be stripped, so this is not an + estimate of the true packet size. + This same number can be computed by the encoder, and is suitable for making + coding decisions. + _b: The number of extra bits of precision to include. + At most 16 will be accurate. + Return: The number of bits scaled by 2**_b. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +long ec_dec_tell(ec_dec *_this,int _b); + #endif diff --git a/libentcode/entenc.h b/libentcode/entenc.h index 61f89879e88780134d79b9827cc64f1b949fa80d..ebaed88737d2c68d8bab6175445258fc58f6df6f 100644 --- a/libentcode/entenc.h +++ b/libentcode/entenc.h @@ -65,18 +65,16 @@ void ec_enc_uint64(ec_enc *_this,ec_uint64 _fl,ec_uint64 _ft); /*Returns the number of bits "used" by the encoded symbols so far. The actual number of bits may be larger, due to rounding to whole bytes, or - smaller, due to trailing zeros that can be stripped. - Return: The number of bits.*/ -long ec_enc_tell(ec_enc *_this); - -/*Returns the number of bits "used" by the encoded symbols so far. - The actual number of bits may be larger, due to rounding to whole bytes, or - smaller, due to trailing zeros that can be stripped. + smaller, due to trailing zeros that can be stripped, so this is not an + estimate of the true packet size. + This same number can be computed by the decoder, and is suitable for making + coding decisions. _b: The number of extra bits of precision to include. At most 16 will be accurate. Return: The number of bits scaled by 2**_b. - This will always be slightly larger than the exact value.*/ -long ec_enc_tellf(ec_enc *_this,int _b); + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +long ec_enc_tell(ec_enc *_this,int _b); /*Indicates that there are no more symbols to encode. All reamining output bytes are flushed to the output buffer. diff --git a/libentcode/mfrngdec.c b/libentcode/mfrngdec.c index caf1410f0c2a1cb1e358f95259d63dc9ccad081e..77b98e6b63a89ff3d88dbbe1ee28393e91efa7ba 100644 --- a/libentcode/mfrngdec.c +++ b/libentcode/mfrngdec.c @@ -137,26 +137,24 @@ static int ec_dec_in(ec_dec *_this){ int ret; ret=ec_byte_read1(_this->buf); if(ret<0){ - unsigned char *buf; - long bytes; + long bytes; bytes=ec_byte_bytes(_this->buf); - buf=ec_byte_get_buffer(_this->buf); /*Breaking abstraction: don't do this at home, kids.*/ - if(_this->buf->storage==bytes){ - ec_byte_adv1(_this->buf); - if(bytes>0){ - unsigned char *p; - p=buf+bytes; - /*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a - zero, return an extra EC_FOF_RSV1 byte.*/ - do p--; - while(p>buf&&p[0]==EC_FOF_RSV1); - if(!p[0])return EC_FOF_RSV1; - } + if(_this->buf->storage==bytes&&bytes>0){ + unsigned char *buf; + buf=ec_byte_get_buffer(_this->buf); + /*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a + zero, return an extra EC_FOF_RSV1 byte.*/ + do bytes--; + while(bytes>0&&buf[bytes]==EC_FOF_RSV1); + if(!buf[bytes])ret=EC_FOF_RSV1; } - return 0; + else ret=0; + /*Needed to make sure the above conditional only triggers once, and to keep + oc_dec_tell() operating correctly.*/ + ec_byte_adv1(_this->buf); } - else return ret; + return ret; } /*Normalizes the contents of dif and rng so that rng lies entirely in the @@ -222,6 +220,31 @@ void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ ec_dec_normalize(_this); } +long ec_dec_tell(ec_dec *_this,int _b){ + ec_uint32 r; + int l; + long nbits; + nbits=ec_byte_bytes(_this->buf)-(EC_CODE_BITS+EC_SYM_BITS-1)/EC_SYM_BITS<<3; + /*To handle the non-integral number of bits still left in the encoder state, + we compute the number of bits of low that must be encoded to ensure that + the value is inside the range for any possible subsequent bits. + Note that this is subtly different than the actual value we would end the + stream with, which tries to make as many of the trailing bits zeros as + possible.*/ + nbits+=EC_CODE_BITS; + nbits<<=_b; + l=EC_ILOG(_this->rng); + r=_this->rng>>l-16; + while(_b-->0){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} + #if 0 int ec_dec_done(ec_dec *_this){ unsigned low; diff --git a/libentcode/mfrngenc.c b/libentcode/mfrngenc.c index 5debf8adae5d47f67532f6c78a6af7b08b75e496..2b2b15c6d7b48ed348631198d8caa72664e75634 100644 --- a/libentcode/mfrngenc.c +++ b/libentcode/mfrngenc.c @@ -119,20 +119,7 @@ void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ ec_enc_normalize(_this); } -long ec_enc_tell(ec_enc *_this){ - long nbits; - nbits=ec_byte_bytes(_this->buf)+(_this->rem>=0)+_this->ext<<3; - /*To handle the non-integral number of bits still left in the encoder state, - we compute the number of bits of low that must be encoded to ensure that - the value is inside the range for any possible subsequent bits. - Note that this is subtly different than the actual value we would end the - stream with, which tries to make as many of the trailing bits zeros as - possible.*/ - nbits+=EC_CODE_BITS-EC_ILOG(_this->rng); - return nbits; -} - -long ec_enc_tellf(ec_enc *_this,int _b){ +long ec_enc_tell(ec_enc *_this,int _b){ ec_uint32 r; int l; long nbits; diff --git a/libentcode/rangedec.c b/libentcode/rangedec.c index 76817472fb9d0434e35287ff416de961d29a2e7a..49d26fd7557eb8fc93a13d33e833858bc758b9e6 100644 --- a/libentcode/rangedec.c +++ b/libentcode/rangedec.c @@ -120,26 +120,24 @@ static int ec_dec_in(ec_dec *_this){ int ret; ret=ec_byte_read1(_this->buf); if(ret<0){ - unsigned char *buf; - long bytes; + long bytes; bytes=ec_byte_bytes(_this->buf); - buf=ec_byte_get_buffer(_this->buf); /*Breaking abstraction: don't do this at home, kids.*/ - if(_this->buf->storage==bytes){ - ec_byte_adv1(_this->buf); - if(bytes>0){ - unsigned char *p; - p=buf+bytes; - /*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a - zero, return an extra EC_FOF_RSV1 byte.*/ - do p--; - while(p>buf&&p[0]==EC_FOF_RSV1); - if(!p[0])return EC_FOF_RSV1; - } + if(_this->buf->storage==bytes&&bytes>0){ + unsigned char *buf; + buf=ec_byte_get_buffer(_this->buf); + /*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a + zero, return an extra EC_FOF_RSV1 byte.*/ + do bytes--; + while(bytes>0&&buf[bytes]==EC_FOF_RSV1); + if(!buf[bytes])ret=EC_FOF_RSV1; } - return 0; + else ret=0; + /*Needed to make sure the above conditional only triggers once, and to keep + oc_dec_tell() operating correctly.*/ + ec_byte_adv1(_this->buf); } - else return ret; + return ret; } /*Normalizes the contents of dif and rng so that rng lies entirely in the @@ -188,6 +186,31 @@ void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ ec_dec_normalize(_this); } +long ec_dec_tell(ec_dec *_this,int _b){ + ec_uint32 r; + int l; + long nbits; + nbits=ec_byte_bytes(_this->buf)-(EC_CODE_BITS+EC_SYM_BITS-1)/EC_SYM_BITS<<3; + /*To handle the non-integral number of bits still left in the encoder state, + we compute the number of bits of low that must be encoded to ensure that + the value is inside the range for any possible subsequent bits. + Note that this is subtly different than the actual value we would end the + stream with, which tries to make as many of the trailing bits zeros as + possible.*/ + nbits+=EC_CODE_BITS; + nbits<<=_b; + l=EC_ILOG(_this->rng); + r=_this->rng>>l-16; + while(_b-->0){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} + #if 0 int ec_dec_done(ec_dec *_this){ unsigned low; diff --git a/libentcode/rangeenc.c b/libentcode/rangeenc.c index 8d3eef3b3c51a074cfc281590bab537a5f54c198..246a4555929181d2f0fa22045f27a0a8a5f55ba2 100644 --- a/libentcode/rangeenc.c +++ b/libentcode/rangeenc.c @@ -91,20 +91,7 @@ void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ ec_enc_normalize(_this); } -long ec_enc_tell(ec_enc *_this){ - long nbits; - nbits=ec_byte_bytes(_this->buf)+(_this->rem>=0)+_this->ext<<3; - /*To handle the non-integral number of bits still left in the encoder state, - we compute the number of bits of low that must be encoded to ensure that - the value is inside the range for any possible subsequent bits. - Note that this is subtly different than the actual value we would end the - stream with, which tries to make as many of the trailing bits zeros as - possible.*/ - nbits+=EC_CODE_BITS-EC_ILOG(_this->rng); - return nbits; -} - -long ec_enc_tellf(ec_enc *_this,int _b){ +long ec_enc_tell(ec_enc *_this,int _b){ ec_uint32 r; int l; long nbits;