384 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			384 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /* Copyright (c) 2007-2011 Xiph.Org Foundation, Mozilla Corporation,
 | ||
|  |                            Gregory Maxwell | ||
|  |    Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */ | ||
|  | /*
 | ||
|  |    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 COPYRIGHT OWNER | ||
|  |    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 <stdlib.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <math.h>
 | ||
|  | #include <time.h>
 | ||
|  | #define CELT_C
 | ||
|  | #include "entcode.h"
 | ||
|  | #include "entenc.h"
 | ||
|  | #include "entdec.h"
 | ||
|  | #include <string.h>
 | ||
|  | 
 | ||
|  | #include "entenc.c"
 | ||
|  | #include "entdec.c"
 | ||
|  | #include "entcode.c"
 | ||
|  | 
 | ||
|  | #ifndef M_LOG2E
 | ||
|  | # define M_LOG2E    1.4426950408889634074
 | ||
|  | #endif
 | ||
|  | #define DATA_SIZE 10000000
 | ||
|  | #define DATA_SIZE2 10000
 | ||
|  | 
 | ||
|  | int main(int _argc,char **_argv){ | ||
|  |   ec_enc         enc; | ||
|  |   ec_dec         dec; | ||
|  |   long           nbits; | ||
|  |   long           nbits2; | ||
|  |   double         entropy; | ||
|  |   int            ft; | ||
|  |   int            ftb; | ||
|  |   int            sz; | ||
|  |   int            i; | ||
|  |   int            ret; | ||
|  |   unsigned int   sym; | ||
|  |   unsigned int   seed; | ||
|  |   unsigned char *ptr; | ||
|  |   const char    *env_seed; | ||
|  |   ret=0; | ||
|  |   entropy=0; | ||
|  |   if (_argc > 2) { | ||
|  |     fprintf(stderr, "Usage: %s [<seed>]\n", _argv[0]); | ||
|  |     return 1; | ||
|  |   } | ||
|  |   env_seed = getenv("SEED"); | ||
|  |   if (_argc > 1) | ||
|  |     seed = atoi(_argv[1]); | ||
|  |   else if (env_seed) | ||
|  |     seed = atoi(env_seed); | ||
|  |   else | ||
|  |     seed = time(NULL); | ||
|  |   /*Testing encoding of raw bit values.*/ | ||
|  |   ptr = (unsigned char *)malloc(DATA_SIZE); | ||
|  |   ec_enc_init(&enc,ptr, DATA_SIZE); | ||
|  |   for(ft=2;ft<1024;ft++){ | ||
|  |     for(i=0;i<ft;i++){ | ||
|  |       entropy+=log(ft)*M_LOG2E; | ||
|  |       ec_enc_uint(&enc,i,ft); | ||
|  |     } | ||
|  |   } | ||
|  |   /*Testing encoding of raw bit values.*/ | ||
|  |   for(ftb=1;ftb<16;ftb++){ | ||
|  |     for(i=0;i<(1<<ftb);i++){ | ||
|  |       entropy+=ftb; | ||
|  |       nbits=ec_tell(&enc); | ||
|  |       ec_enc_bits(&enc,i,ftb); | ||
|  |       nbits2=ec_tell(&enc); | ||
|  |       if(nbits2-nbits!=ftb){ | ||
|  |         fprintf(stderr,"Used %li bits to encode %i bits directly.\n", | ||
|  |          nbits2-nbits,ftb); | ||
|  |         ret=-1; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   nbits=ec_tell_frac(&enc); | ||
|  |   ec_enc_done(&enc); | ||
|  |   fprintf(stderr, | ||
|  |    "Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n", | ||
|  |    entropy,ldexp(nbits,-3),100*(nbits-ldexp(entropy,3))/nbits); | ||
|  |   fprintf(stderr,"Packed to %li bytes.\n",(long)ec_range_bytes(&enc)); | ||
|  |   ec_dec_init(&dec,ptr,DATA_SIZE); | ||
|  |   for(ft=2;ft<1024;ft++){ | ||
|  |     for(i=0;i<ft;i++){ | ||
|  |       sym=ec_dec_uint(&dec,ft); | ||
|  |       if(sym!=(unsigned)i){ | ||
|  |         fprintf(stderr,"Decoded %i instead of %i with ft of %i.\n",sym,i,ft); | ||
|  |         ret=-1; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   for(ftb=1;ftb<16;ftb++){ | ||
|  |     for(i=0;i<(1<<ftb);i++){ | ||
|  |       sym=ec_dec_bits(&dec,ftb); | ||
|  |       if(sym!=(unsigned)i){ | ||
|  |         fprintf(stderr,"Decoded %i instead of %i with ftb of %i.\n",sym,i,ftb); | ||
|  |         ret=-1; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   nbits2=ec_tell_frac(&dec); | ||
|  |   if(nbits!=nbits2){ | ||
|  |     fprintf(stderr, | ||
|  |      "Reported number of bits used was %0.2lf, should be %0.2lf.\n", | ||
|  |      ldexp(nbits2,-3),ldexp(nbits,-3)); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   /*Testing an encoder bust prefers range coder data over raw bits.
 | ||
|  |     This isn't a general guarantee, will only work for data that is buffered in | ||
|  |      the encoder state and not yet stored in the user buffer, and should never | ||
|  |      get used in practice. | ||
|  |     It's mostly here for code coverage completeness.*/ | ||
|  |   /*Start with a 16-bit buffer.*/ | ||
|  |   ec_enc_init(&enc,ptr,2); | ||
|  |   /*Write 7 raw bits.*/ | ||
|  |   ec_enc_bits(&enc,0x55,7); | ||
|  |   /*Write 12.3 bits of range coder data.*/ | ||
|  |   ec_enc_uint(&enc,1,2); | ||
|  |   ec_enc_uint(&enc,1,3); | ||
|  |   ec_enc_uint(&enc,1,4); | ||
|  |   ec_enc_uint(&enc,1,5); | ||
|  |   ec_enc_uint(&enc,2,6); | ||
|  |   ec_enc_uint(&enc,6,7); | ||
|  |   ec_enc_done(&enc); | ||
|  |   ec_dec_init(&dec,ptr,2); | ||
|  |   if(!enc.error | ||
|  |    /*The raw bits should have been overwritten by the range coder data.*/ | ||
|  |    ||ec_dec_bits(&dec,7)!=0x05 | ||
|  |    /*And all the range coder data should have been encoded correctly.*/ | ||
|  |    ||ec_dec_uint(&dec,2)!=1 | ||
|  |    ||ec_dec_uint(&dec,3)!=1 | ||
|  |    ||ec_dec_uint(&dec,4)!=1 | ||
|  |    ||ec_dec_uint(&dec,5)!=1 | ||
|  |    ||ec_dec_uint(&dec,6)!=2 | ||
|  |    ||ec_dec_uint(&dec,7)!=6){ | ||
|  |     fprintf(stderr,"Encoder bust overwrote range coder data with raw bits.\n"); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   srand(seed); | ||
|  |   fprintf(stderr,"Testing random streams... Random seed: %u (%.4X)\n", seed, rand() % 65536); | ||
|  |   for(i=0;i<409600;i++){ | ||
|  |     unsigned *data; | ||
|  |     unsigned *tell; | ||
|  |     unsigned tell_bits; | ||
|  |     int       j; | ||
|  |     int zeros; | ||
|  |     ft=rand()/((RAND_MAX>>(rand()%11U))+1U)+10; | ||
|  |     sz=rand()/((RAND_MAX>>(rand()%9U))+1U); | ||
|  |     data=(unsigned *)malloc(sz*sizeof(*data)); | ||
|  |     tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); | ||
|  |     ec_enc_init(&enc,ptr,DATA_SIZE2); | ||
|  |     zeros = rand()%13==0; | ||
|  |     tell[0]=ec_tell_frac(&enc); | ||
|  |     for(j=0;j<sz;j++){ | ||
|  |       if (zeros) | ||
|  |         data[j]=0; | ||
|  |       else | ||
|  |         data[j]=rand()%ft; | ||
|  |       ec_enc_uint(&enc,data[j],ft); | ||
|  |       tell[j+1]=ec_tell_frac(&enc); | ||
|  |     } | ||
|  |     if (rand()%2==0) | ||
|  |       while(ec_tell(&enc)%8 != 0) | ||
|  |         ec_enc_uint(&enc, rand()%2, 2); | ||
|  |     tell_bits = ec_tell(&enc); | ||
|  |     ec_enc_done(&enc); | ||
|  |     if(tell_bits!=(unsigned)ec_tell(&enc)){ | ||
|  |       fprintf(stderr,"ec_tell() changed after ec_enc_done(): %i instead of %i (Random seed: %u)\n", | ||
|  |        ec_tell(&enc),tell_bits,seed); | ||
|  |       ret=-1; | ||
|  |     } | ||
|  |     if ((tell_bits+7)/8 < ec_range_bytes(&enc)) | ||
|  |     { | ||
|  |       fprintf (stderr, "ec_tell() lied, there's %i bytes instead of %d (Random seed: %u)\n", | ||
|  |                ec_range_bytes(&enc), (tell_bits+7)/8,seed); | ||
|  |       ret=-1; | ||
|  |     } | ||
|  |     ec_dec_init(&dec,ptr,DATA_SIZE2); | ||
|  |     if(ec_tell_frac(&dec)!=tell[0]){ | ||
|  |       fprintf(stderr, | ||
|  |        "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", | ||
|  |        0,ec_tell_frac(&dec),tell[0],seed); | ||
|  |     } | ||
|  |     for(j=0;j<sz;j++){ | ||
|  |       sym=ec_dec_uint(&dec,ft); | ||
|  |       if(sym!=data[j]){ | ||
|  |         fprintf(stderr, | ||
|  |          "Decoded %i instead of %i with ft of %i at position %i of %i (Random seed: %u).\n", | ||
|  |          sym,data[j],ft,j,sz,seed); | ||
|  |         ret=-1; | ||
|  |       } | ||
|  |       if(ec_tell_frac(&dec)!=tell[j+1]){ | ||
|  |         fprintf(stderr, | ||
|  |          "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", | ||
|  |          j+1,ec_tell_frac(&dec),tell[j+1],seed); | ||
|  |       } | ||
|  |     } | ||
|  |     free(tell); | ||
|  |     free(data); | ||
|  |   } | ||
|  |   /*Test compatibility between multiple different encode/decode routines.*/ | ||
|  |   for(i=0;i<409600;i++){ | ||
|  |     unsigned *logp1; | ||
|  |     unsigned *data; | ||
|  |     unsigned *tell; | ||
|  |     unsigned *enc_method; | ||
|  |     int       j; | ||
|  |     sz=rand()/((RAND_MAX>>(rand()%9U))+1U); | ||
|  |     logp1=(unsigned *)malloc(sz*sizeof(*logp1)); | ||
|  |     data=(unsigned *)malloc(sz*sizeof(*data)); | ||
|  |     tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); | ||
|  |     enc_method=(unsigned *)malloc(sz*sizeof(*enc_method)); | ||
|  |     ec_enc_init(&enc,ptr,DATA_SIZE2); | ||
|  |     tell[0]=ec_tell_frac(&enc); | ||
|  |     for(j=0;j<sz;j++){ | ||
|  |       data[j]=rand()/((RAND_MAX>>1)+1); | ||
|  |       logp1[j]=(rand()%15)+1; | ||
|  |       enc_method[j]=rand()/((RAND_MAX>>2)+1); | ||
|  |       switch(enc_method[j]){ | ||
|  |         case 0:{ | ||
|  |           ec_encode(&enc,data[j]?(1<<logp1[j])-1:0, | ||
|  |            (1<<logp1[j])-(data[j]?0:1),1<<logp1[j]); | ||
|  |         }break; | ||
|  |         case 1:{ | ||
|  |           ec_encode_bin(&enc,data[j]?(1<<logp1[j])-1:0, | ||
|  |            (1<<logp1[j])-(data[j]?0:1),logp1[j]); | ||
|  |         }break; | ||
|  |         case 2:{ | ||
|  |           ec_enc_bit_logp(&enc,data[j],logp1[j]); | ||
|  |         }break; | ||
|  |         case 3:{ | ||
|  |           unsigned char icdf[2]; | ||
|  |           icdf[0]=1; | ||
|  |           icdf[1]=0; | ||
|  |           ec_enc_icdf(&enc,data[j],icdf,logp1[j]); | ||
|  |         }break; | ||
|  |       } | ||
|  |       tell[j+1]=ec_tell_frac(&enc); | ||
|  |     } | ||
|  |     ec_enc_done(&enc); | ||
|  |     if((ec_tell(&enc)+7U)/8U<ec_range_bytes(&enc)){ | ||
|  |       fprintf(stderr,"tell() lied, there's %i bytes instead of %d (Random seed: %u)\n", | ||
|  |        ec_range_bytes(&enc),(ec_tell(&enc)+7)/8,seed); | ||
|  |       ret=-1; | ||
|  |     } | ||
|  |     ec_dec_init(&dec,ptr,DATA_SIZE2); | ||
|  |     if(ec_tell_frac(&dec)!=tell[0]){ | ||
|  |       fprintf(stderr, | ||
|  |        "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", | ||
|  |        0,ec_tell_frac(&dec),tell[0],seed); | ||
|  |     } | ||
|  |     for(j=0;j<sz;j++){ | ||
|  |       int fs; | ||
|  |       int dec_method; | ||
|  |       dec_method=rand()/((RAND_MAX>>2)+1); | ||
|  |       switch(dec_method){ | ||
|  |         case 0:{ | ||
|  |           fs=ec_decode(&dec,1<<logp1[j]); | ||
|  |           sym=fs>=(1<<logp1[j])-1; | ||
|  |           ec_dec_update(&dec,sym?(1<<logp1[j])-1:0, | ||
|  |            (1<<logp1[j])-(sym?0:1),1<<logp1[j]); | ||
|  |         }break; | ||
|  |         case 1:{ | ||
|  |           fs=ec_decode_bin(&dec,logp1[j]); | ||
|  |           sym=fs>=(1<<logp1[j])-1; | ||
|  |           ec_dec_update(&dec,sym?(1<<logp1[j])-1:0, | ||
|  |            (1<<logp1[j])-(sym?0:1),1<<logp1[j]); | ||
|  |         }break; | ||
|  |         case 2:{ | ||
|  |           sym=ec_dec_bit_logp(&dec,logp1[j]); | ||
|  |         }break; | ||
|  |         case 3:{ | ||
|  |           unsigned char icdf[2]; | ||
|  |           icdf[0]=1; | ||
|  |           icdf[1]=0; | ||
|  |           sym=ec_dec_icdf(&dec,icdf,logp1[j]); | ||
|  |         }break; | ||
|  |       } | ||
|  |       if(sym!=data[j]){ | ||
|  |         fprintf(stderr, | ||
|  |          "Decoded %i instead of %i with logp1 of %i at position %i of %i (Random seed: %u).\n", | ||
|  |          sym,data[j],logp1[j],j,sz,seed); | ||
|  |         fprintf(stderr,"Encoding method: %i, decoding method: %i\n", | ||
|  |          enc_method[j],dec_method); | ||
|  |         ret=-1; | ||
|  |       } | ||
|  |       if(ec_tell_frac(&dec)!=tell[j+1]){ | ||
|  |         fprintf(stderr, | ||
|  |          "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", | ||
|  |          j+1,ec_tell_frac(&dec),tell[j+1],seed); | ||
|  |       } | ||
|  |     } | ||
|  |     free(enc_method); | ||
|  |     free(tell); | ||
|  |     free(data); | ||
|  |     free(logp1); | ||
|  |   } | ||
|  |   ec_enc_init(&enc,ptr,DATA_SIZE2); | ||
|  |   ec_enc_bit_logp(&enc,0,1); | ||
|  |   ec_enc_bit_logp(&enc,0,1); | ||
|  |   ec_enc_bit_logp(&enc,0,1); | ||
|  |   ec_enc_bit_logp(&enc,0,1); | ||
|  |   ec_enc_bit_logp(&enc,0,2); | ||
|  |   ec_enc_patch_initial_bits(&enc,3,2); | ||
|  |   if(enc.error){ | ||
|  |     fprintf(stderr,"patch_initial_bits failed"); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   ec_enc_patch_initial_bits(&enc,0,5); | ||
|  |   if(!enc.error){ | ||
|  |     fprintf(stderr,"patch_initial_bits didn't fail when it should have"); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   ec_enc_done(&enc); | ||
|  |   if(ec_range_bytes(&enc)!=1||ptr[0]!=192){ | ||
|  |     fprintf(stderr,"Got %d when expecting 192 for patch_initial_bits",ptr[0]); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   ec_enc_init(&enc,ptr,DATA_SIZE2); | ||
|  |   ec_enc_bit_logp(&enc,0,1); | ||
|  |   ec_enc_bit_logp(&enc,0,1); | ||
|  |   ec_enc_bit_logp(&enc,1,6); | ||
|  |   ec_enc_bit_logp(&enc,0,2); | ||
|  |   ec_enc_patch_initial_bits(&enc,0,2); | ||
|  |   if(enc.error){ | ||
|  |     fprintf(stderr,"patch_initial_bits failed"); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   ec_enc_done(&enc); | ||
|  |   if(ec_range_bytes(&enc)!=2||ptr[0]!=63){ | ||
|  |     fprintf(stderr,"Got %d when expecting 63 for patch_initial_bits",ptr[0]); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   ec_enc_init(&enc,ptr,2); | ||
|  |   ec_enc_bit_logp(&enc,0,2); | ||
|  |   for(i=0;i<48;i++){ | ||
|  |     ec_enc_bits(&enc,0,1); | ||
|  |   } | ||
|  |   ec_enc_done(&enc); | ||
|  |   if(!enc.error){ | ||
|  |     fprintf(stderr,"Raw bits overfill didn't fail when it should have"); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   ec_enc_init(&enc,ptr,2); | ||
|  |   for(i=0;i<17;i++){ | ||
|  |     ec_enc_bits(&enc,0,1); | ||
|  |   } | ||
|  |   ec_enc_done(&enc); | ||
|  |   if(!enc.error){ | ||
|  |     fprintf(stderr,"17 raw bits encoded in two bytes"); | ||
|  |     ret=-1; | ||
|  |   } | ||
|  |   free(ptr); | ||
|  |   return ret; | ||
|  | } |