Add ec_dec_tell() to report the same information as ec_enc_tell() decode side. Remove ec_enc_tell() and replace it with ec_enc_tellf(): just request 0 fractional bits if you want an integer value.

git-svn-id: http://svn.xiph.org/trunk/ghost@14394 0101bb08-14d6-0310-b084-bc0e0c8e3800
This commit is contained in:
tterribe 2008-01-11 05:51:49 +00:00 committed by Jean-Marc Valin
parent fad779ca56
commit 3eff11d8d4
7 changed files with 111 additions and 75 deletions

View file

@ -11,6 +11,7 @@ int main(int _argc,char **_argv){
ec_probmod mod; ec_probmod mod;
ec_uint64 sym64; ec_uint64 sym64;
long nbits; long nbits;
long nbits2;
double entropy; double entropy;
int ft; int ft;
int ftb; int ftb;
@ -33,12 +34,10 @@ int main(int _argc,char **_argv){
/*Testing encoding of raw bit values.*/ /*Testing encoding of raw bit values.*/
for(ftb=0;ftb<16;ftb++){ for(ftb=0;ftb<16;ftb++){
for(i=0;i<(1<<ftb);i++){ for(i=0;i<(1<<ftb);i++){
long nbits;
long nbits2;
entropy+=ftb; entropy+=ftb;
nbits=ec_enc_tell(&enc); nbits=ec_enc_tell(&enc,0);
ec_enc_bits(&enc,i,ftb); ec_enc_bits(&enc,i,ftb);
nbits2=ec_enc_tell(&enc); nbits2=ec_enc_tell(&enc,0);
if(nbits2-nbits!=ftb){ if(nbits2-nbits!=ftb){
fprintf(stderr,"Used %li bits to encode %i bits directly.\n", fprintf(stderr,"Used %li bits to encode %i bits directly.\n",
nbits2-nbits,ftb); nbits2-nbits,ftb);
@ -46,7 +45,7 @@ int main(int _argc,char **_argv){
entropy+=ftb+30; entropy+=ftb+30;
nbits=nbits2; nbits=nbits2;
ec_enc_bits64(&enc,(ec_uint64)i<<30|i,ftb+30); 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){ if(nbits2-nbits!=ftb+30){
fprintf(stderr,"Used %li bits to encode %i bits directly.\n", fprintf(stderr,"Used %li bits to encode %i bits directly.\n",
nbits2-nbits,ftb+30); nbits2-nbits,ftb+30);
@ -73,7 +72,7 @@ int main(int _argc,char **_argv){
} }
ec_probmod_clear(&mod); ec_probmod_clear(&mod);
} }
nbits=ec_enc_tellf(&enc,4); nbits=ec_enc_tell(&enc,4);
ec_enc_done(&enc); ec_enc_done(&enc);
fprintf(stderr, fprintf(stderr,
"Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n", "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); 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); ec_byte_writeclear(&buf);
fprintf(stderr,"All tests passed.\n"); fprintf(stderr,"All tests passed.\n");
return 0; return 0;

View file

@ -86,4 +86,17 @@ ec_uint32 ec_dec_uint(ec_dec *_this,ec_uint32 _ft);
Return: The decoded bits.*/ Return: The decoded bits.*/
ec_uint64 ec_dec_uint64(ec_dec *_this,ec_uint64 _ft); 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 #endif

View file

@ -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. /*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 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
Return: The number of bits.*/ estimate of the true packet size.
long ec_enc_tell(ec_enc *_this); This same number can be computed by the decoder, and is suitable for making
coding decisions.
/*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.
_b: The number of extra bits of precision to include. _b: The number of extra bits of precision to include.
At most 16 will be accurate. At most 16 will be accurate.
Return: The number of bits scaled by 2**_b. Return: The number of bits scaled by 2**_b.
This will always be slightly larger than the exact value.*/ This will always be slightly larger than the exact value (e.g., all
long ec_enc_tellf(ec_enc *_this,int _b); 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. /*Indicates that there are no more symbols to encode.
All reamining output bytes are flushed to the output buffer. All reamining output bytes are flushed to the output buffer.

View file

@ -137,26 +137,24 @@ static int ec_dec_in(ec_dec *_this){
int ret; int ret;
ret=ec_byte_read1(_this->buf); ret=ec_byte_read1(_this->buf);
if(ret<0){ if(ret<0){
unsigned char *buf; long bytes;
long bytes;
bytes=ec_byte_bytes(_this->buf); bytes=ec_byte_bytes(_this->buf);
buf=ec_byte_get_buffer(_this->buf);
/*Breaking abstraction: don't do this at home, kids.*/ /*Breaking abstraction: don't do this at home, kids.*/
if(_this->buf->storage==bytes){ if(_this->buf->storage==bytes&&bytes>0){
ec_byte_adv1(_this->buf); unsigned char *buf;
if(bytes>0){ buf=ec_byte_get_buffer(_this->buf);
unsigned char *p; /*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a
p=buf+bytes; zero, return an extra EC_FOF_RSV1 byte.*/
/*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a do bytes--;
zero, return an extra EC_FOF_RSV1 byte.*/ while(bytes>0&&buf[bytes]==EC_FOF_RSV1);
do p--; if(!buf[bytes])ret=EC_FOF_RSV1;
while(p>buf&&p[0]==EC_FOF_RSV1);
if(!p[0])return 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 /*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); 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 #if 0
int ec_dec_done(ec_dec *_this){ int ec_dec_done(ec_dec *_this){
unsigned low; unsigned low;

View file

@ -119,20 +119,7 @@ void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){
ec_enc_normalize(_this); ec_enc_normalize(_this);
} }
long ec_enc_tell(ec_enc *_this){ long ec_enc_tell(ec_enc *_this,int _b){
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){
ec_uint32 r; ec_uint32 r;
int l; int l;
long nbits; long nbits;

View file

@ -120,26 +120,24 @@ static int ec_dec_in(ec_dec *_this){
int ret; int ret;
ret=ec_byte_read1(_this->buf); ret=ec_byte_read1(_this->buf);
if(ret<0){ if(ret<0){
unsigned char *buf; long bytes;
long bytes;
bytes=ec_byte_bytes(_this->buf); bytes=ec_byte_bytes(_this->buf);
buf=ec_byte_get_buffer(_this->buf);
/*Breaking abstraction: don't do this at home, kids.*/ /*Breaking abstraction: don't do this at home, kids.*/
if(_this->buf->storage==bytes){ if(_this->buf->storage==bytes&&bytes>0){
ec_byte_adv1(_this->buf); unsigned char *buf;
if(bytes>0){ buf=ec_byte_get_buffer(_this->buf);
unsigned char *p; /*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a
p=buf+bytes; zero, return an extra EC_FOF_RSV1 byte.*/
/*If we end in a string of 0 or more EC_FOF_RSV1 bytes preceded by a do bytes--;
zero, return an extra EC_FOF_RSV1 byte.*/ while(bytes>0&&buf[bytes]==EC_FOF_RSV1);
do p--; if(!buf[bytes])ret=EC_FOF_RSV1;
while(p>buf&&p[0]==EC_FOF_RSV1);
if(!p[0])return 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 /*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); 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 #if 0
int ec_dec_done(ec_dec *_this){ int ec_dec_done(ec_dec *_this){
unsigned low; unsigned low;

View file

@ -91,20 +91,7 @@ void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){
ec_enc_normalize(_this); ec_enc_normalize(_this);
} }
long ec_enc_tell(ec_enc *_this){ long ec_enc_tell(ec_enc *_this,int _b){
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){
ec_uint32 r; ec_uint32 r;
int l; int l;
long nbits; long nbits;