Index: media/libvorbis/lib/codebook.h =================================================================== --- media/libvorbis/lib/codebook.h +++ media/libvorbis/lib/codebook.h @@ -59,59 +59,92 @@ long entries; /* codebook entries */ long used_entries; /* populated codebook entries */ const static_codebook *c; /* for encode, the below are entry-ordered, fully populated */ - /* for decode, the below are ordered by bitreversed codeword and only - used entries are populated */ float *valuelist; /* list of dim*entries actual entry values */ ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */ - int *dec_index; /* only used if sparseness collapsed */ - char *dec_codelengths; - ogg_uint32_t *dec_firsttable; - int dec_firsttablen; - int dec_maxlength; - /* The current encoder uses only centered, integer-only lattice books. */ int quantvals; int minval; int delta; } codebook; +typedef struct dec_codebook{ + signed char dim; /* codebook dimensions (elements per vector) */ + signed char minlength; + signed char maxlength; + signed char firsttablen; /* number of bits in decode fastpath table */ + ogg_int32_t entries; /* codebook entries */ + ogg_int32_t hi_max; /* the maximum value of the fastpath hi hint */ + signed char hint_shift; /* the amount to shift the hints */ + + /* The below does a linear, single monotonic sequence mapping. */ + signed char maptype; + signed char q_quant; /* bits: 0 < quant <= 16 */ + signed char q_sequencep; /* bitflag */ + ogg_uint32_t q_min; /* packed 32 bit float; + quant value 0 maps to minval */ + ogg_uint32_t q_delta; /* packed 32 bit float; val 1 - val 0 == delta */ + ogg_uint16_t *quantlist; /* map == 1: + (int)(entries^(1/dim)) element column map + map == 2: + list of dim*entries quantized entry vals */ + + ogg_uint32_t *firsttable; /* decode fastpath lookup table */ + /* the below are ordered by bitreversed codeword and only used entries are + populated */ + ogg_uint32_t *codelist; /* unordered: list of codewords for each entry. + ordered: sentinel value for each length as large + as any codeword (of that length or shorter) + with any trailing bits appended. */ + signed char *codelengths;/* unordered: length of each codeword. + ordered: unused (NULL). */ + ogg_int32_t *index; /* unordered: a mapping from codeword index (in the + collapsed, sorted list in codelist) to the entry + in the original (possibly-sparse) codebook. + ordered: cumulative count of entries for each + length (starting from the minimum length). */ + float *valuelist; /* list of dim*entries actual entry values */ + +} dec_codebook; + extern void vorbis_staticbook_destroy(static_codebook *b); extern int vorbis_book_init_encode(codebook *dest,const static_codebook *source); -extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source); +extern int vorbis_book_init_decode(dec_codebook *c); extern void vorbis_book_clear(codebook *b); +extern void vorbis_decbook_clear(dec_codebook *c); -extern float *_book_unquantize(const static_codebook *b,int n,int *map); +extern void _book_unquantize(float *r,const dec_codebook *b,int n, + ogg_int64_t *map); extern float *_book_logdist(const static_codebook *b,float *vals); extern float _float32_unpack(long val); extern long _float32_pack(float val); extern int _best(codebook *book, float *a, int step); -extern long _book_maptype1_quantvals(const static_codebook *b); +extern long _book_maptype1_quantvals(long dim, long entries); extern int vorbis_book_besterror(codebook *book,float *a,int step,int addmul); extern long vorbis_book_codeword(codebook *book,int entry); extern long vorbis_book_codelen(codebook *book,int entry); extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b); -extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b); +extern int vorbis_decbook_unpack(dec_codebook *c,oggpack_buffer *opb); extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b); -extern long vorbis_book_decode(codebook *book, oggpack_buffer *b); -extern long vorbis_book_decodevs_add(codebook *book, float *a, +extern long vorbis_book_decode(dec_codebook *book, oggpack_buffer *b); +extern long vorbis_book_decodevs_add(dec_codebook *book, float *a, oggpack_buffer *b,int n); -extern long vorbis_book_decodev_set(codebook *book, float *a, +extern long vorbis_book_decodev_set(dec_codebook *book, float *a, oggpack_buffer *b,int n); -extern long vorbis_book_decodev_add(codebook *book, float *a, +extern long vorbis_book_decodev_add(dec_codebook *book, float *a, oggpack_buffer *b,int n); -extern long vorbis_book_decodevv_add(codebook *book, float **a, +extern long vorbis_book_decodevv_add(dec_codebook *book, float **a, long off,int ch, - oggpack_buffer *b,int n); + oggpack_buffer *b,int n); #endif Index: media/libvorbis/lib/codec_internal.h =================================================================== --- media/libvorbis/lib/codec_internal.h +++ media/libvorbis/lib/codec_internal.h @@ -116,10 +116,11 @@ vorbis_info_floor *floor_param[64]; int residue_type[64]; vorbis_info_residue *residue_param[64]; static_codebook *book_param[256]; codebook *fullbooks; + dec_codebook *decbooks; vorbis_info_psy *psy_param[4]; /* encode only */ vorbis_info_psy_global psy_g_param; bitrate_manager_info bi; Index: media/libvorbis/lib/vorbis_block.c =================================================================== --- media/libvorbis/lib/vorbis_block.c +++ media/libvorbis/lib/vorbis_block.c @@ -230,21 +230,15 @@ } v->analysisp=1; }else{ /* finish the codebooks */ - if(!ci->fullbooks){ - ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); - for(i=0;ibooks;i++){ - if(ci->book_param[i]==NULL) - goto abort_books; - if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i])) - goto abort_books; - /* decode codebooks are now standalone after init */ - vorbis_staticbook_destroy(ci->book_param[i]); - ci->book_param[i]=NULL; - } + if(ci->decbooks==NULL) + goto abort_books; + for(i=0;ibooks;i++){ + if(vorbis_book_init_decode(ci->decbooks+i)) + goto abort_books; } } /* initialize the storage vectors. blocksize[1] is small for encode, but the correct size for decode */ @@ -284,10 +278,17 @@ for(i=0;ibooks;i++){ if(ci->book_param[i]!=NULL){ vorbis_staticbook_destroy(ci->book_param[i]); ci->book_param[i]=NULL; } + if(ci->decbooks!=NULL){ + vorbis_decbook_clear(ci->decbooks+i); + } + } + if(ci->decbooks!=NULL){ + _ogg_free(ci->decbooks); + ci->decbooks=NULL; } vorbis_dsp_clear(v); return -1; } Index: media/libvorbis/lib/vorbis_codebook.c =================================================================== --- media/libvorbis/lib/vorbis_codebook.c +++ media/libvorbis/lib/vorbis_codebook.c @@ -117,11 +117,11 @@ int quantvals; switch(c->maptype){ case 1: /* a single column of (c->entries/c->dim) quantized values for building a full value list algorithmically (square lattice) */ - quantvals=_book_maptype1_quantvals(c); + quantvals=_book_maptype1_quantvals(c->dim, c->entries); break; case 2: /* every value (c->entries*c->dim total) specified explicitly */ quantvals=c->entries*c->dim; break; @@ -141,134 +141,149 @@ } return(0); } -/* unpacks a codebook from the packet buffer into the codebook struct, - readies the codebook auxiliary structures for decode *************/ -static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){ - long i,j; - static_codebook *s=_ogg_calloc(1,sizeof(*s)); - s->allocedp=1; +/* unpacks a codebook from the packet buffer into the codebook struct */ +int vorbis_decbook_unpack(dec_codebook *c,oggpack_buffer *opb){ + long i; /* make sure alignment is correct */ if(oggpack_read(opb,24)!=0x564342)goto _eofout; /* first the basic parameters */ - s->dim=oggpack_read(opb,16); - s->entries=oggpack_read(opb,24); - if(s->entries==-1)goto _eofout; + c->dim=(signed char)oggpack_read(opb,16); + c->entries=(ogg_int32_t)oggpack_read(opb,24); + if(c->entries==-1)goto _eofout; - if(ov_ilog(s->dim)+ov_ilog(s->entries)>24)goto _eofout; + if(ov_ilog(c->dim)+ov_ilog(c->entries)>24)goto _eofout; /* codeword ordering.... length ordered or unordered? */ switch((int)oggpack_read(opb,1)){ case 0:{ long unused; /* allocated but unused entries? */ unused=oggpack_read(opb,1); - if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb)) + if((c->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb)) goto _eofout; /* unordered */ - s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries); + c->codelengths=_ogg_malloc(sizeof(*c->codelengths)*c->entries); + if(c->codelengths==NULL)goto _errout; /* allocated but unused entries? */ if(unused){ /* yes, unused entries */ - for(i=0;ientries;i++){ + for(i=0;ientries;i++){ if(oggpack_read(opb,1)){ long num=oggpack_read(opb,5); if(num==-1)goto _eofout; - s->lengthlist[i]=num+1; + c->codelengths[i]=(signed char)(num+1); }else - s->lengthlist[i]=0; + c->codelengths[i]=0; } }else{ /* all entries used; no tagging */ - for(i=0;ientries;i++){ + for(i=0;ientries;i++){ long num=oggpack_read(opb,5); if(num==-1)goto _eofout; - s->lengthlist[i]=num+1; + c->codelengths[i]=(signed char)(num+1); } } break; } case 1: /* ordered */ { - long length=oggpack_read(opb,5)+1; - if(length==0)goto _eofout; - s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries); - - for(i=0;ientries;){ - long num=oggpack_read(opb,ov_ilog(s->entries-i)); + ogg_int32_t cum_entries[32]; + long minlength=oggpack_read(opb,5)+1; + long maxlength; + long length; + if(minlength==0)goto _eofout; + maxlength=length=minlength; + for(i=0;ientries;length++){ + long num=oggpack_read(opb,ov_ilog(c->entries-i)); if(num==-1)goto _eofout; - if(length>32 || num>s->entries-i || + if(length>32 || num>c->entries-i || (num>0 && (num-1)>>(length-1)>1)){ goto _errout; } - if(length>32)goto _errout; - for(j=0;jlengthlist[i]=length; - length++; + i+=num; + cum_entries[length-minlength]=(ogg_int32_t)i; + /* skip lengths with 0 entries at the start, to avoid creating a + malformed codeword sentinel in vorbis_book_init_decode(). */ + if(i==0)minlength++; + maxlength=length; } + c->minlength=(signed char)minlength; + c->maxlength=(signed char)maxlength; + c->index=_ogg_malloc((maxlength-minlength+1)*sizeof(*c->index)); + if(c->index==NULL)goto _errout; + memcpy(c->index,cum_entries,(maxlength-minlength+1)*sizeof(*c->index)); } break; default: /* EOF */ goto _eofout; } /* Do we have a mapping to unpack? */ - switch((s->maptype=oggpack_read(opb,4))){ + switch((c->maptype=(signed char)oggpack_read(opb,4))){ case 0: /* no mapping */ break; case 1: case 2: /* implicitly populated value mapping */ /* explicitly populated value mapping */ - s->q_min=oggpack_read(opb,32); - s->q_delta=oggpack_read(opb,32); - s->q_quant=oggpack_read(opb,4)+1; - s->q_sequencep=oggpack_read(opb,1); - if(s->q_sequencep==-1)goto _eofout; + c->q_min=(ogg_uint32_t)oggpack_read(opb,32); + c->q_delta=(ogg_uint32_t)oggpack_read(opb,32); + c->q_quant=(signed char)oggpack_read(opb,4)+1; + c->q_sequencep=(signed char)oggpack_read(opb,1); + if(c->q_sequencep==-1)goto _eofout; { + long q=0; int quantvals=0; - switch(s->maptype){ + switch(c->maptype){ case 1: - quantvals=(s->dim==0?0:_book_maptype1_quantvals(s)); + quantvals=(c->dim==0?0:_book_maptype1_quantvals(c->dim, c->entries)); break; case 2: - quantvals=s->entries*s->dim; + quantvals=c->entries*c->dim; break; } /* quantized values */ - if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb)) + if(((quantvals*c->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb)) goto _eofout; - s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals); - for(i=0;iquantlist[i]=oggpack_read(opb,s->q_quant); + c->quantlist=_ogg_malloc(sizeof(*c->quantlist)*quantvals); + if(c->quantlist==NULL)goto _errout; + for(i=0;iq_quant); + c->quantlist[i]=(ogg_uint16_t)q; + } - if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout; + if(q==-1)goto _eofout; } break; default: goto _errout; } /* all set */ - return(s); + /* we could finish initializing the decode tables here, but this was a + separate step back when we had a shared encoder/decoder codebook struct, + and deferring it ensures we continue to report the same kinds of errors + in the same places. */ + return(0); _errout: _eofout: - vorbis_staticbook_destroy(s); - return(NULL); + /* our caller will clean up the partially constructed book */ + return(-1); } /* returns the number of bits ************************************************/ int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){ if(a<0 || a>=book->c->entries)return(0); @@ -290,27 +305,28 @@ x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0); x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc); return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa); } -STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){ - int read=book->dec_maxlength; +STIN long decode_packed_entry_number(dec_codebook *book, oggpack_buffer *b){ + ogg_uint32_t testword; + int read=book->maxlength; long lo,hi; - long lok = oggpack_look(b,book->dec_firsttablen); + long lok = oggpack_look(b,book->firsttablen); if (lok >= 0) { - long entry = book->dec_firsttable[lok]; + long entry = book->firsttable[lok]; if(entry&0x80000000UL){ - lo=(entry>>15)&0x7fff; - hi=book->used_entries-(entry&0x7fff); + lo=((entry>>15)&0x7fff)<hint_shift; + hi=book->hi_max-((entry&0x7fff)<hint_shift); }else{ - oggpack_adv(b, book->dec_codelengths[entry-1]); - return(entry-1); + oggpack_adv(b, (int)(entry&0x3f)); + return(entry>>6); } }else{ lo=0; - hi=book->used_entries; + hi=book->hi_max; } /* Single entry codebooks use a firsttablen of 1 and a dec_maxlength of 1. If a single-entry codebook gets here (due to failure to read one bit above), the next look attempt will also @@ -321,23 +337,33 @@ while(lok<0 && read>1) lok = oggpack_look(b, --read); if(lok<0)return -1; - /* bisect search for the codeword in the ordered list */ - { - ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok); - + testword=bitreverse((ogg_uint32_t)lok); + if(book->codelengths==NULL){ + int length; + /* ordered codebook: search for the codeword length */ + while(testword>book->codelist[lo])lo++; + length=(int)lo+book->minlength; + if(length<=read){ + long entry= + book->index[lo]-(((book->codelist[lo]-testword)>>(32-length))+1); + oggpack_adv(b, length); + return(entry); + } + }else{ + /* bisect search for the codeword in the ordered list */ while(hi-lo>1){ long p=(hi-lo)>>1; long test=book->codelist[lo+p]>testword; lo+=p&(test-1); hi-=p&(-test); } - if(book->dec_codelengths[lo]<=read){ - oggpack_adv(b, book->dec_codelengths[lo]); + if(book->codelengths[lo]<=read){ + oggpack_adv(b, book->codelengths[lo]); return(lo); } } oggpack_adv(b, read); @@ -358,25 +384,31 @@ addmul==0 -> declarative (set the value) addmul==1 -> additive addmul==2 -> multiplicitive */ /* returns the [original, not compacted] entry number or -1 on eof *********/ -long vorbis_book_decode(codebook *book, oggpack_buffer *b){ - if(book->used_entries>0){ +long vorbis_book_decode(dec_codebook *book, oggpack_buffer *b){ + if(book->codelist){ long packed_entry=decode_packed_entry_number(book,b); - if(packed_entry>=0) - return(book->dec_index[packed_entry]); + if(packed_entry>=0){ + /* if we have an unordered book, look up the original entry number */ + if(book->codelengths) + return(book->index[packed_entry]); + /* if we have an ordered book, the packed_entry number is the original */ + return(packed_entry); + } } - /* if there's no dec_index, the codebook unpacking isn't collapsed */ + /* if there's no codelist, the codebook hasn't been init'd */ return(-1); } /* returns 0 on OK or -1 on eof *************************************/ /* decode vector / dim granularity gaurding is done in the upper layer */ -long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){ - if(book->used_entries>0){ +long vorbis_book_decodevs_add(dec_codebook *book,float *a,oggpack_buffer *b, + int n){ + if(book->codelist){ int step=n/book->dim; long *entry = alloca(sizeof(*entry)*step); float **t = alloca(sizeof(*t)*step); int i,j,o; @@ -391,12 +423,13 @@ } return(0); } /* decode vector / dim granularity gaurding is done in the upper layer */ -long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){ - if(book->used_entries>0){ +long vorbis_book_decodev_add(dec_codebook *book,float *a,oggpack_buffer *b, + int n){ + if(book->codelist){ int i,j,entry; float *t; for(i=0;i internally rather than in the upper layer (called only by floor0) */ -long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){ - if(book->used_entries>0){ +long vorbis_book_decodev_set(dec_codebook *book,float *a,oggpack_buffer *b, + int n){ + if(book->codelist){ int i,j,entry; float *t; for(i=0;iused_entries>0){ + if(book->codelist){ int m=(offset+n)/ch; for(i=offset/ch;inumbooks<1)goto err_out; for(j=0;jnumbooks;j++){ info->books[j]=oggpack_read(opb,8); if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out; - if(ci->book_param[info->books[j]]->maptype==0)goto err_out; - if(ci->book_param[info->books[j]]->dim<1)goto err_out; + if(ci->decbooks[info->books[j]].maptype==0)goto err_out; + if(ci->decbooks[info->books[j]].dim<1)goto err_out; } return(info); err_out: floor0_free_info(info); @@ -169,11 +169,11 @@ float amp=(float)ampraw/maxval*info->ampdB; int booknum=oggpack_read(&vb->opb,ov_ilog(info->numbooks)); if(booknum!=-1 && booknumnumbooks){ /* be paranoid */ codec_setup_info *ci=vb->vd->vi->codec_setup; - codebook *b=ci->fullbooks+info->books[booknum]; + dec_codebook *b=ci->decbooks+info->books[booknum]; float last=0.f; /* the additional b->dim is a guard against any possible stack smash; b->dim is provably more than we can overflow the vector */ Index: media/libvorbis/lib/vorbis_floor1.c =================================================================== --- media/libvorbis/lib/vorbis_floor1.c +++ media/libvorbis/lib/vorbis_floor1.c @@ -956,11 +956,11 @@ vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; vorbis_info_floor1 *info=look->vi; codec_setup_info *ci=vb->vd->vi->codec_setup; int i,j,k; - codebook *books=ci->fullbooks; + dec_codebook *books=ci->decbooks; /* unpack wrapped/predicted values from stream */ if(oggpack_read(&vb->opb,1)==1){ int *fit_value=_vorbis_block_alloc(vb,(look->posts)*sizeof(*fit_value)); Index: media/libvorbis/lib/vorbis_info.c =================================================================== --- media/libvorbis/lib/vorbis_info.c +++ media/libvorbis/lib/vorbis_info.c @@ -187,13 +187,17 @@ /* knows if the book was not alloced */ vorbis_staticbook_destroy(ci->book_param[i]); } if(ci->fullbooks) vorbis_book_clear(ci->fullbooks+i); + if(ci->decbooks) + vorbis_decbook_clear(ci->decbooks+i); } if(ci->fullbooks) _ogg_free(ci->fullbooks); + if(ci->decbooks) + _ogg_free(ci->decbooks); for(i=0;ipsys;i++) _vi_psy_free(ci->psy_param[i]); _ogg_free(ci); @@ -277,13 +281,14 @@ int i; /* codebooks */ ci->books=oggpack_read(opb,8)+1; if(ci->books<=0)goto err_out; + ci->decbooks=_ogg_calloc(ci->books,sizeof(*ci->decbooks)); + if(ci->decbooks==NULL)goto err_out; for(i=0;ibooks;i++){ - ci->book_param[i]=vorbis_staticbook_unpack(opb); - if(!ci->book_param[i])goto err_out; + if(vorbis_decbook_unpack(ci->decbooks+i,opb)<0)goto err_out; } /* time backend settings; hooks are unused */ { int times=oggpack_read(opb,6)+1; Index: media/libvorbis/lib/vorbis_res0.c =================================================================== --- media/libvorbis/lib/vorbis_res0.c +++ media/libvorbis/lib/vorbis_res0.c @@ -35,31 +35,32 @@ #endif typedef struct { vorbis_info_residue0 *info; - int parts; - int stages; - codebook *fullbooks; - codebook *phrasebook; - codebook ***partbooks; + int parts; + int stages; + codebook *fullbooks; + dec_codebook *decbooks; + int phrasebook; + int **partbooks; - int partvals; - int **decodemap; + int partvals; + int **decodemap; - long postbits; - long phrasebits; - long frames; + long postbits; + long phrasebits; + long frames; #if defined(TRAIN_RES) || defined(TRAIN_RESAUX) - int train_seq; - long *training_data[8][64]; - float training_max[8][64]; - float training_min[8][64]; - float tmin; - float tmax; - int submap; + int train_seq; + long *training_data[8][64]; + float training_max[8][64]; + float training_min[8][64]; + float tmin; + float tmax; + int submap; #endif } vorbis_look_residue0; void res0_free_info(vorbis_info_residue *i){ @@ -83,11 +84,11 @@ /*fprintf(stderr,"partition %d: ",j);*/ for(k=0;k<8;k++) if(look->training_data[k][j]){ char buffer[80]; FILE *of; - codebook *statebook=look->partbooks[j][k]; + codebook *statebook=look->fullbooks+look->partbooks[j][k]; /* long and short into the same bucket by current convention */ sprintf(buffer,"res_sub%d_part%d_pass%d.vqd",look->submap,j,k); of=fopen(buffer,"a"); @@ -222,22 +223,22 @@ } if(info->groupbook>=ci->books)goto errout; for(j=0;jbooklist[j]>=ci->books)goto errout; - if(ci->book_param[info->booklist[j]]->maptype==0)goto errout; + if(ci->decbooks[info->booklist[j]].maptype==0)goto errout; } /* verify the phrasebook is not specifying an impossible or inconsistent partitioning scheme. */ /* modify the phrasebook ranging check from r16327; an early beta encoder had a bug where it used an oversized phrasebook by accident. These files should continue to be playable, but don't allow an exploit */ { - int entries = ci->book_param[info->groupbook]->entries; - int dim = ci->book_param[info->groupbook]->dim; + int entries = ci->decbooks[info->groupbook].entries; + int dim = ci->decbooks[info->groupbook].dim; int partvals = 1; if (dim<1) goto errout; while(dim>0){ partvals *= info->partitions; if(partvals > entries) goto errout; @@ -263,27 +264,32 @@ int maxstage=0; look->info=info; look->parts=info->partitions; look->fullbooks=ci->fullbooks; - look->phrasebook=ci->fullbooks+info->groupbook; - dim=look->phrasebook->dim; + look->decbooks=ci->decbooks; + look->phrasebook=info->groupbook; + dim=look->fullbooks? + look->fullbooks[look->phrasebook].dim:look->decbooks[look->phrasebook].dim; look->partbooks=_ogg_calloc(look->parts,sizeof(*look->partbooks)); for(j=0;jparts;j++){ int stages=ov_ilog(info->secondstages[j]); if(stages){ if(stages>maxstage)maxstage=stages; look->partbooks[j]=_ogg_calloc(stages,sizeof(*look->partbooks[j])); for(k=0;ksecondstages[j]&(1<partbooks[j][k]=ci->fullbooks+info->booklist[acc++]; + look->partbooks[j][k]=info->booklist[acc++]; #ifdef TRAIN_RES - look->training_data[k][j]=_ogg_calloc(look->partbooks[j][k]->entries, - sizeof(***look->training_data)); + look->training_data[k][j]=_ogg_calloc( + look->fullbooks[look->partbooks[j][k]].entries, + sizeof(***look->training_data)); #endif + }else{ + look->partbooks[j][k]=-1; } } } look->partvals=1; @@ -539,19 +545,20 @@ #endif ){ long i,j,k,s; vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; vorbis_info_residue0 *info=look->info; + codebook *phrasebook=look->fullbooks+look->phrasebook; #ifdef TRAIN_RES look->submap=submap; #endif /* move all this setup out later */ int samples_per_partition=info->grouping; int possible_partitions=info->partitions; - int partitions_per_word=look->phrasebook->dim; + int partitions_per_word=phrasebook->dim; int n=info->end-info->begin; int partvals=n/samples_per_partition; long resbits[128]; long resvals[128]; @@ -585,12 +592,12 @@ if(i+kphrasebook->entries) - look->phrasebits+=vorbis_book_encode(look->phrasebook,val,opb); + if(valentries) + look->phrasebits+=vorbis_book_encode(phrasebook,val,opb); #if 0 /*def TRAIN_RES*/ else fprintf(stderr,"!"); #endif @@ -602,12 +609,13 @@ long offset=i*samples_per_partition+info->begin; for(j=0;jsecondstages[partword[j][i]]&(1<partbooks[partword[j][i]][s]; - if(statebook){ + int statebooknum=look->partbooks[partword[j][i]][s]; + if(statebooknum>=0){ + codebook *statebook=look->fullbooks+statebooknum; int ret; #ifdef TRAIN_RES long *accumulator=NULL; accumulator=look->training_data[s][partword[j][i]]; { @@ -640,20 +648,21 @@ } /* a truncated packet here just means 'stop working'; it's not an error */ static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl, float **in,int ch, - long (*decodepart)(codebook *, float *, + long (*decodepart)(dec_codebook *, float *, oggpack_buffer *,int)){ long i,j,k,l,s; vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; vorbis_info_residue0 *info=look->info; + dec_codebook *phrasebook=look->decbooks+look->phrasebook; /* move all this setup out later */ int samples_per_partition=info->grouping; - int partitions_per_word=look->phrasebook->dim; + int partitions_per_word=phrasebook->dim; int max=vb->pcmend>>1; int end=(info->endend:max); int n=end-info->begin; if(n>0){ @@ -670,11 +679,11 @@ partitions_per_word partitions */ for(i=0,l=0;iphrasebook,&vb->opb); + int temp=vorbis_book_decode(phrasebook,&vb->opb); if(temp==-1 || temp>=info->partvals)goto eopbreak; partword[j][l]=look->decodemap[temp]; if(partword[j][l]==NULL)goto errout; } @@ -683,12 +692,13 @@ /* now we decode residual values for the partitions */ for(k=0;kbegin+i*samples_per_partition; if(info->secondstages[partword[j][l][k]]&(1<partbooks[partword[j][l][k]][s]; - if(stagebook){ + int stagebooknum=look->partbooks[partword[j][l][k]][s]; + if(stagebooknum>=0){ + dec_codebook *stagebook=look->decbooks+stagebooknum; if(decodepart(stagebook,in[j]+offset,&vb->opb, samples_per_partition)==-1)goto eopbreak; } } } @@ -802,14 +812,15 @@ int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl, float **in,int *nonzero,int ch){ long i,k,l,s; vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; vorbis_info_residue0 *info=look->info; + dec_codebook *phrasebook=look->decbooks+look->phrasebook; /* move all this setup out later */ int samples_per_partition=info->grouping; - int partitions_per_word=look->phrasebook->dim; + int partitions_per_word=phrasebook->dim; int max=(vb->pcmend*ch)>>1; int end=(info->endend:max); int n=end-info->begin; if(n>0){ @@ -823,22 +834,23 @@ for(s=0;sstages;s++){ for(i=0,l=0;iphrasebook,&vb->opb); + int temp=vorbis_book_decode(phrasebook,&vb->opb); if(temp==-1 || temp>=info->partvals)goto eopbreak; partword[l]=look->decodemap[temp]; if(partword[l]==NULL)goto errout; } /* now we decode residual values for the partitions */ for(k=0;ksecondstages[partword[l][k]]&(1<partbooks[partword[l][k]][s]; + int stagebooknum=look->partbooks[partword[l][k]][s]; - if(stagebook){ + if(stagebooknum>=0){ + dec_codebook *stagebook=look->decbooks+stagebooknum; if(vorbis_book_decodevv_add(stagebook,in, i*samples_per_partition+info->begin,ch, &vb->opb,samples_per_partition)==-1) goto eopbreak; } Index: media/libvorbis/lib/vorbis_sharedbook.c =================================================================== --- media/libvorbis/lib/vorbis_sharedbook.c +++ media/libvorbis/lib/vorbis_sharedbook.c @@ -160,62 +160,137 @@ } return(r); } +/* given a list of word lengths, generate a list of packed MSb codewords and + entry numbers. This is like the above, except that the codewords are MSb + first and aligned to be 32-bits in size, and the lower 24 bits include the + entry number the codeword corresponds to. */ +static ogg_int64_t *dec_make_words(signed char *l,long n,long sparsecount){ + long i,j,count=0; + ogg_uint32_t marker[33]; + ogg_int64_t *r=_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r)); + if(r==NULL)return(NULL); + memset(marker,0,sizeof(marker)); + + for(i=0;i0){ + ogg_uint32_t entry=marker[length]; + + /* when we claim a node for an entry, we also claim the nodes + below it (pruning off the imagined tree that may have dangled + from it) as well as blocking the use of any nodes directly + above for leaves */ + + /* update ourself */ + if(length<32 && (entry>>length)){ + /* error condition; the lengths must specify an overpopulated tree */ + _ogg_free(r); + return(NULL); + } + r[count++]=(ogg_int64_t)entry<<(32-l[i]+24)|i; + + /* Look to see if the next shorter marker points to the node + above. if so, update it and repeat. */ + { + for(j=length;j>0;j--){ + + if(marker[j]&1){ + /* have to jump branches */ + if(j==1) + marker[1]++; + else + marker[j]=marker[j-1]<<1; + break; /* invariant says next upper marker would already + have been moved if it was on the same path */ + } + marker[j]++; + } + } + + /* prune the tree; the implicit invariant says all the longer + markers were dangling from our just-taken node. Dangle them + from our *new* node. */ + for(j=length+1;j<33;j++) + if((marker[j]>>1) == entry){ + entry=marker[j]; + marker[j]=marker[j-1]<<1; + }else + break; + }else + if(sparsecount==0)count++; + } + + /* any underpopulated tree must be rejected. */ + /* Single-entry codebooks are a retconned extension to the spec. + They have a single codeword '0' of length 1 that results in an + underpopulated tree. Shield that case from the underformed tree check. */ + if(!(count==1 && marker[2]==2)){ + for(i=1;i<33;i++) + if(marker[i] & (0xffffffffUL>>(32-i))){ + _ogg_free(r); + return(NULL); + } + } + + return(r); +} + /* there might be a straightforward one-line way to do the below that's portable and totally safe against roundoff, but I haven't thought of it. Therefore, we opt on the side of caution */ -long _book_maptype1_quantvals(const static_codebook *b){ +long _book_maptype1_quantvals(long dim, long entries){ long vals; - if(b->entries<1){ + if(entries<1){ return(0); } - vals=floor(pow((float)b->entries,1.f/b->dim)); + vals=floor(pow((float)entries,1.f/dim)); /* the above *should* be reliable, but we'll not assume that FP is ever reliable when bitstream sync is at stake; verify via integer means that vals really is the greatest value of dim for which - vals^b->bim <= b->entries */ + vals^dim <= entries */ /* treat the above as an initial guess */ if(vals<1){ vals=1; } while(1){ long acc=1; long acc1=1; int i; - for(i=0;idim;i++){ - if(b->entries/vals=b->dim && acc<=b->entries && acc1>b->entries){ + if(i>=dim && acc<=entries && acc1>entries){ return(vals); }else{ - if(idim || acc>b->entries){ + if(ientries){ vals--; }else{ vals++; } } } } -/* unpack the quantized list of values for encode/decode ***********/ +/* unpack the quantized list of values for decode ***********/ /* we need to deal with two map types: in map type 1, the values are generated algorithmically (each column of the vector counts through the values in the quant vector). in map type 2, all the values came in in an explicit list. Both value lists must be unpacked */ -float *_book_unquantize(const static_codebook *b,int n,int *sparsemap){ - long j,k,count=0; +void _book_unquantize(float *r,const dec_codebook *b,ogg_int32_t n, + ogg_int64_t *sparsemap){ + ogg_int32_t i,j,k; if(b->maptype==1 || b->maptype==2){ - int quantvals; + ogg_int32_t quantvals; float mindel=_float32_unpack(b->q_min); float delta=_float32_unpack(b->q_delta); - float *r=_ogg_calloc(n*b->dim,sizeof(*r)); /* maptype 1 and 2 both use a quantized value vector, but different sizes */ switch(b->maptype){ case 1: @@ -224,54 +299,40 @@ scalar is values == entries/dim. If entries%dim != 0, we'll have 'too few' values (values*dimentries;j++){ - if((sparsemap && b->lengthlist[j]) || !sparsemap){ - float last=0.f; - int indexdiv=1; - for(k=0;kdim;k++){ - int index= (j/indexdiv)%quantvals; - float val=b->quantlist[index]; - val=fabs(val)*delta+mindel+last; - if(b->q_sequencep)last=val; - if(sparsemap) - r[sparsemap[count]*b->dim+k]=val; - else - r[count*b->dim+k]=val; - indexdiv*=quantvals; - } - count++; + quantvals=(ogg_int32_t)_book_maptype1_quantvals(b->dim, b->entries); + for(i=0;idim;k++){ + ogg_int32_t index=(j/indexdiv)%quantvals; + float val=b->quantlist[index]; + val=fabs(val)*delta+mindel+last; + if(b->q_sequencep)last=val; + r[i*b->dim+k]=val; + indexdiv*=quantvals; } - } break; case 2: - for(j=0;jentries;j++){ - if((sparsemap && b->lengthlist[j]) || !sparsemap){ - float last=0.f; - - for(k=0;kdim;k++){ - float val=b->quantlist[j*b->dim+k]; - val=fabs(val)*delta+mindel+last; - if(b->q_sequencep)last=val; - if(sparsemap) - r[sparsemap[count]*b->dim+k]=val; - else - r[count*b->dim+k]=val; - } - count++; + for(i=0;idim;k++){ + float val=b->quantlist[j*b->dim+k]; + val=fabs(val)*delta+mindel+last; + if(b->q_sequencep)last=val; + r[i*b->dim+k]=val; } } break; } - return(r); } - return(NULL); } void vorbis_staticbook_destroy(static_codebook *b){ if(b->allocedp){ if(b->quantlist)_ogg_free(b->quantlist); @@ -285,14 +346,20 @@ /* static book is not cleared; we're likely called on the lookup and the static codebook belongs to the info struct */ if(b->valuelist)_ogg_free(b->valuelist); if(b->codelist)_ogg_free(b->codelist); - if(b->dec_index)_ogg_free(b->dec_index); - if(b->dec_codelengths)_ogg_free(b->dec_codelengths); - if(b->dec_firsttable)_ogg_free(b->dec_firsttable); + memset(b,0,sizeof(*b)); +} +void vorbis_decbook_clear(dec_codebook *b){ + if(b->quantlist)_ogg_free(b->quantlist); + if(b->firsttable)_ogg_free(b->firsttable); + if(b->codelist)_ogg_free(b->codelist); + if(b->codelengths)_ogg_free(b->codelengths); + if(b->index)_ogg_free(b->index); + if(b->valuelist)_ogg_free(b->valuelist); memset(b,0,sizeof(*b)); } int vorbis_book_init_encode(codebook *c,const static_codebook *s){ @@ -300,12 +367,11 @@ c->c=s; c->entries=s->entries; c->used_entries=s->entries; c->dim=s->dim; c->codelist=_make_words(s->lengthlist,s->entries,0); - /* c->valuelist=_book_unquantize(s,s->entries,NULL); */ - c->quantvals=_book_maptype1_quantvals(s); + c->quantvals=_book_maptype1_quantvals(s->dim, s->entries); c->minval=(int)rint(_float32_unpack(s->q_min)); c->delta=(int)rint(_float32_unpack(s->q_delta)); return(0); } @@ -316,155 +382,289 @@ x= ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL); x= ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL); return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL); } -static int sort32a(const void *a,const void *b){ - return ( **(ogg_uint32_t **)a>**(ogg_uint32_t **)b)- - ( **(ogg_uint32_t **)a<**(ogg_uint32_t **)b); +static int sort64a(const void *a,const void *b){ + return ( *(ogg_int64_t *)a>*(ogg_int64_t *)b)- + ( *(ogg_int64_t *)a<*(ogg_int64_t *)b); } /* decode codebook arrangement is more heavily optimized than encode */ -int vorbis_book_init_decode(codebook *c,const static_codebook *s){ - int i,j,n=0,tabn; - int *sortindex=NULL; - ogg_uint32_t *codes=NULL; - ogg_uint32_t **codep=NULL; +int vorbis_book_init_decode(dec_codebook *c){ + ogg_int32_t i,j,n; + ogg_int64_t *codes=NULL; + + /* only initialize once */ + if(c->codelist)return(0); - memset(c,0,sizeof(*c)); + if(c->codelengths){ + /* unordered codebook */ + /* count actually used entries */ + n=0; + for(i=0;ientries;i++) + if(c->codelengths[i]>0) + n++; - /* count actually used entries and find max length */ - for(i=0;ientries;i++) - if(s->lengthlist[i]>0) - n++; + if(n>0){ + signed char *codelengths; + /* two different remappings go on here. + + First, we collapse the likely sparse codebook down only to + actually represented values/words. This collapsing needs to be + indexed as map-valueless books are used to encode original entry + positions as integers. - c->entries=s->entries; - c->used_entries=n; - c->dim=s->dim; + Second, we reorder all vectors, including the entry index above, + by sorted bitreversed codeword to allow treeless decode. */ + + /* perform sort */ + codes=dec_make_words(c->codelengths,c->entries,n); + if(codes==NULL)goto err_out; + + qsort(codes,n,sizeof(*codes),sort64a); - if(n>0){ - /* two different remappings go on here. + c->codelist=_ogg_malloc(n*sizeof(*c->codelist)); + if(c->codelist==NULL)goto err_out; - First, we collapse the likely sparse codebook down only to - actually represented values/words. This collapsing needs to be - indexed as map-valueless books are used to encode original entry - positions as integers. - - Second, we reorder all vectors, including the entry index above, - by sorted bitreversed codeword to allow treeless decode. */ + for(i=0;icodelist[i]=(ogg_uint32_t)(codes[i]>>24); + } - /* perform sort */ - codes=_make_words(s->lengthlist,s->entries,c->used_entries); - if(codes==NULL)goto err_out; + if(c->maptype==1 || c->maptype==2){ + c->valuelist=_ogg_malloc(c->dim*n*sizeof(*c->valuelist)); + if(c->valuelist==NULL)goto err_out; + _book_unquantize(c->valuelist,c,n,codes); + _ogg_free(c->quantlist); + c->quantlist=NULL; + } + c->index=_ogg_malloc(n*sizeof(*c->index)); + if(c->index==NULL)goto err_out; + codelengths=_ogg_malloc(n*sizeof(*c->codelengths)); + if(codelengths==NULL)goto err_out; - codep=_ogg_malloc(sizeof(*codep)*n); - if(codep==NULL)goto err_out; - - for(i=0;iminlength=32; + c->maxlength=0; + for(i=0;iindex[i]=j; + codelengths[i]=c->codelengths[j]; + if(codelengths[i]minlength) + c->minlength=codelengths[i]; + if(codelengths[i]>c->maxlength) + c->maxlength=codelengths[i]; + } + _ogg_free(codes); + codes=NULL; + _ogg_free(c->codelengths); + c->codelengths=codelengths; } - - qsort(codep,n,sizeof(*codep),sort32a); - - sortindex=_ogg_malloc(n*sizeof(*sortindex)); - if(sortindex==NULL)goto err_out; - - c->codelist=_ogg_malloc(n*sizeof(*c->codelist)); - if(c->codelist==NULL)goto err_out; - /* the index is a reverse index */ - for(i=0;ientries; + if(n>0){ + ogg_uint32_t prev_entry; + ogg_uint32_t code; + int nlengths; + int length; + int l; + nlengths=c->maxlength-c->minlength+1; + c->codelist=_ogg_malloc(nlengths*sizeof(*c->codelist)); + if(c->codelist==NULL)goto err_out; + /* for this case, codelist[l] contains the last codeword of the l'th + length, left-aligned in a 32-bit word, with all remaining bits filled + with trailing 1's. This ensures that 32 bits taken from the stream + will be <= codelist[l] if the codeword length is <= length l. */ + prev_entry=0; + code=0; + length=c->minlength; + for(l=0;lindex[l]-prev_entry; + /* guard against an over-populated tree. We do not check the last + length, because it should exactly use the remaining space, which + causes code to wrap to 0 (something this check prevents for any + earlier length). We'll check it after the loop. */ + if(l+1((0xffffffffUL-code)>>(32-length))) + goto err_out; + code+=nentries<<(32-length); + /* this requires that the first length have a non-zero number of + entries, or c->codelist[0] will wrap to 0xffffffff, making the list + non-monotonic. */ + c->codelist[l]=code-1; + prev_entry=c->index[l]; + } + /* for a complete tree, the last value will have all bits set, which + guarantees we will not walk past the end of the array during decode */ + if(c->codelist[nlengths-1]!=0xffffffffUL){ + /* reject over/underpopulated trees, with the exception of a + single-entry codebook. */ + if(n!=1 || c->maxlength!=1)goto err_out; + } + if(c->maptype==1 || c->maptype==2){ + c->valuelist=_ogg_malloc(c->dim*n*sizeof(*c->valuelist)); + if(c->valuelist==NULL)goto err_out; + _book_unquantize(c->valuelist,c,n,NULL); + _ogg_free(c->quantlist); + c->quantlist=NULL; + } } - _ogg_free(codep); codep=NULL; - - for(i=0;icodelist[sortindex[i]]=codes[i]; - _ogg_free(codes); codes=NULL; - - c->valuelist=_book_unquantize(s,n,sortindex); - c->dec_index=_ogg_malloc(n*sizeof(*c->dec_index)); - if(c->dec_index==NULL)goto err_out; - - for(n=0,i=0;ientries;i++) - if(s->lengthlist[i]>0) - c->dec_index[sortindex[n++]]=i; - - c->dec_codelengths=_ogg_malloc(n*sizeof(*c->dec_codelengths)); - if(c->dec_codelengths==NULL)goto err_out; - c->dec_maxlength=0; - for(n=0,i=0;ientries;i++) - if(s->lengthlist[i]>0){ - c->dec_codelengths[sortindex[n++]]=s->lengthlist[i]; - if(s->lengthlist[i]>c->dec_maxlength) - c->dec_maxlength=s->lengthlist[i]; - } - _ogg_free(sortindex); sortindex=NULL; - - if(n==1 && c->dec_maxlength==1){ + } + /* build the fastpath lookup table */ + if(n>0){ + if(n==1 && c->maxlength==1){ /* special case the 'single entry codebook' with a single bit fastpath table (that always returns entry 0 )in order to use unmodified decode paths. */ - c->dec_firsttablen=1; - c->dec_firsttable=_ogg_calloc(2,sizeof(*c->dec_firsttable)); - if(c->dec_firsttable==NULL)goto err_out; - c->dec_firsttable[0]=c->dec_firsttable[1]=1; + c->firsttablen=1; + c->firsttable=_ogg_calloc(2,sizeof(*c->firsttable)); + if(c->firsttable==NULL)goto err_out; + c->firsttable[0]=c->firsttable[1]=1; }else{ - c->dec_firsttablen=ov_ilog(c->used_entries)-4; /* this is magic */ - if(c->dec_firsttablen<5)c->dec_firsttablen=5; - if(c->dec_firsttablen>8)c->dec_firsttablen=8; - - tabn=1<dec_firsttablen; - c->dec_firsttable=_ogg_calloc(tabn,sizeof(*c->dec_firsttable)); - if(c->dec_firsttable==NULL)goto err_out; + int used_bits; + int tabn; + used_bits=ov_ilog(n); + c->firsttablen=(signed char)(used_bits-4); /* this is magic */ + if(c->firsttablen<5)c->firsttablen=5; + /* if the codewords all have similar lengths, we might wind up with a + table smaller than the shorter codes: increase the size or we could + take the slow path in a large fraction of cases */ + if(c->firsttablenminlength+1) + c->firsttablen=c->minlength+1; + /* also cap the table by the max length, or we are just wasting space */ + if(c->firsttablen>c->maxlength) + c->firsttablen=c->maxlength; + /* if we have an ordered book with a very large minimum length, an 8-bit + table would be mostly wasted. Instead, try to make one just large + enough to get a good guess for the codeword length. */ + if(c->codelengths==NULL && c->minlength>8) + c->firsttablen=c->maxlength-c->minlength+1; + if(c->firsttablen>8)c->firsttablen=8; - for(i=0;idec_codelengths[i]<=c->dec_firsttablen){ - ogg_uint32_t orig=bitreverse(c->codelist[i]); - for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++) - c->dec_firsttable[orig|(j<dec_codelengths[i])]=i+1; - } - } + tabn=1<firsttablen; + c->firsttable=_ogg_calloc(tabn,sizeof(*c->firsttable)); + if(c->firsttable==NULL)goto err_out; - /* now fill in 'unused' entries in the firsttable with hi/lo search - hints for the non-direct-hits */ - { - ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen); - long lo=0,hi=0; + if(c->codelengths!=NULL){ + /* unordered codebook: + use the codewords for each entry to build the fastpath table */ + for(i=0;icodelengths[i]<=c->firsttablen){ + ogg_uint32_t orig=bitreverse(c->codelist[i]); + for(j=0;j<(1<<(c->firsttablen-c->codelengths[i]));j++) + /* pack the length into the table, too, to avoid an extra lookup. + This also guarantees the table value is non-zero, since the + length of any used entry is positive. */ + c->firsttable[orig|(j<codelengths[i])]= + i<<6|c->codelengths[i]; + } + } - for(i=0;idec_firsttablen)); - if(c->dec_firsttable[bitreverse(word)]==0){ - while((lo+1)codelist[lo+1]<=word)lo++; - while( hi=(c->codelist[hi]&mask))hi++; + /* now fill in 'unused' entries in the firsttable with hi/lo search + hints for the non-direct-hits */ + { + ogg_uint32_t mask=0xfffffffeUL<<(31-c->firsttablen); + long lo=0,hi=0; + int hint_shift; - /* we only actually have 15 bits per hint to play with here. - In order to overflow gracefully (nothing breaks, efficiency - just drops), encode as the difference from the extremes. */ - { - unsigned long loval=lo; - unsigned long hival=n-hi; + c->hi_max=n; + hint_shift=used_bits>15?used_bits-15:0; + c->hint_shift=(signed char)hint_shift; + for(i=0;ifirsttablen)); + if(c->firsttable[bitreverse(word)]==0){ + while((lo+1)codelist[lo+1]<=word)lo++; + while( hi=(c->codelist[hi]&mask))hi++; - if(loval>0x7fff)loval=0x7fff; - if(hival>0x7fff)hival=0x7fff; - c->dec_firsttable[bitreverse(word)]= - 0x80000000UL | (loval<<15) | hival; + /* we only actually have 15 bits per hint to play with here. + In order to overflow gracefully (nothing breaks, efficiency + just drops), shift the values down when the range gets too + large. We encode the hi value as a difference from the max so + truncation error moves it upwards without risk of stepping + past the end of the arrays. */ + { + unsigned long loval=lo>>hint_shift; + unsigned long hival=(n-hi)>>hint_shift; + + if(loval>0x7fff)loval=0x7fff; + if(hival>0x7fff)hival=0x7fff; + c->firsttable[bitreverse(word)]= + 0x80000000UL | (loval<<15) | hival; + } } } } + }else{ + ogg_uint32_t code; + int nlengths; + int length; + int l; + /* ordered codebook: + step through the code lengths to build the fastpath table */ + nlengths=c->maxlength-c->minlength+1; + c->hi_max=nlengths-1; + c->hint_shift=0; + length=c->minlength; + code=0; + for(i=l=0;length<=c->firsttablen;l++,length++){ + for(;iindex[l];i++,code++){ + ogg_uint32_t orig=bitreverse(code<<(32-length)); + for(j=0;j<(1<<(c->firsttablen-length));j++){ + /* pack the length into the table to avoid an extra lookup */ + c->firsttable[(j<codelist[l]>>(32-length))-code+1; + slot_count=(ogg_uint32_t)1<<(length-c->firsttablen); + if(nleft>=slot_count){ + ogg_uint32_t word=code>>(length-c->firsttablen); + c->firsttable[bitreverse(word<<(32-c->firsttablen))]= + 0x80000000UL | ((ogg_uint32_t)lo<<15) | (nlengths-1-l); + code+=slot_count; + lo=l; + }else{ + /* not enough: consider longer codes */ + l++; + length++; + code<<=1; + if(nleft==0)lo=l; + } + } + while(lc) /* only use with encode; decode optimizations are @@ -496,54 +696,46 @@ nonsequential sequential */ -static long full_quantlist1[]={0,1,2,3, 4,5,6,7, 8,3,6,1}; -static long partial_quantlist1[]={0,7,2}; +static ogg_uint16_t full_quantlist1[]={0,1,2,3, 4,5,6,7, 8,3,6,1}; +static ogg_uint16_t partial_quantlist1[]={0,7,2}; /* no mapping */ -static_codebook test1={ - 4,16, +dec_codebook test1={ + 4,0,0,0,16,0,0, + 0,0,0,0,0, NULL, - 0, - 0,0,0,0, - NULL, - 0 + NULL,NULL,NULL,NULL,NULL }; static float *test1_result=NULL; /* linear, full mapping, nonsequential */ -static_codebook test2={ - 4,3, - NULL, - 2, - -533200896,1611661312,4,0, +dec_codebook test2={ + 4,0,0,0,3,0,0, + 2,4,0,3761766400U,1611661312, full_quantlist1, - 0 + NULL,NULL,NULL,NULL,NULL }; static float test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2}; /* linear, full mapping, sequential */ -static_codebook test3={ - 4,3, - NULL, - 2, - -533200896,1611661312,4,1, +dec_codebook test3={ + 4,0,0,0,3,0,0, + 2,4,1,3761766400U,1611661312, full_quantlist1, - 0 + NULL,NULL,NULL,NULL,NULL }; static float test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6}; /* linear, algorithmic mapping, nonsequential */ -static_codebook test4={ - 3,27, - NULL, - 1, - -533200896,1611661312,4,0, +dec_codebook test4={ + 3,0,0,0,27,0,0, + 1,4,0,3761766400U,1611661312, partial_quantlist1, - 0 + NULL,NULL,NULL,NULL,NULL }; static float test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3, -3, 4,-3, 4, 4,-3, -1, 4,-3, -3,-1,-3, 4,-1,-3, -1,-1,-3, -3,-3, 4, 4,-3, 4, -1,-3, 4, @@ -552,17 +744,15 @@ -3,-3,-1, 4,-3,-1, -1,-3,-1, -3, 4,-1, 4, 4,-1, -1, 4,-1, -3,-1,-1, 4,-1,-1, -1,-1,-1}; /* linear, algorithmic mapping, sequential */ -static_codebook test5={ - 3,27, - NULL, - 1, - -533200896,1611661312,4,1, +dec_codebook test5={ + 3,0,0,0,27,0,0, + 1,4,1,3761766400U,1611661312, partial_quantlist1, - 0 + NULL,NULL,NULL,NULL,NULL, }; static float test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7, -3, 1,-2, 4, 8, 5, -1, 3, 0, -3,-4,-7, 4, 3, 0, -1,-2,-5, -3,-6,-2, 4, 1, 5, -1,-4, 0, @@ -570,35 +760,24 @@ -3,-4, 0, 4, 3, 7, -1,-2, 2, -3,-6,-7, 4, 1, 0, -1,-4,-5, -3, 1, 0, 4, 8, 7, -1, 3, 2, -3,-4,-5, 4, 3, 2, -1,-2,-3}; -void run_test(static_codebook *b,float *comp){ - float *out=_book_unquantize(b,b->entries,NULL); +void run_test(dec_codebook *b,float *comp){ + float out[3*27]; int i; if(comp){ - if(!out){ - fprintf(stderr,"_book_unquantize incorrectly returned NULL\n"); - exit(1); - } - + _book_unquantize(out,b,b->entries,NULL); for(i=0;ientries*b->dim;i++) if(fabs(out[i]-comp[i])>.0001){ fprintf(stderr,"disagreement in unquantized and reference data:\n" "position %d, %g != %g\n",i,out[i],comp[i]); exit(1); } - }else{ - if(out){ - fprintf(stderr,"_book_unquantize returned a value array: \n" - " correct result should have been NULL\n"); - exit(1); - } } - _ogg_free(out); } int main(){ /* run the nine dequant tests, and compare to the hand-rolled results */ fprintf(stderr,"Dequant test 1... "); Index: media/libvorbis/moz.yaml =================================================================== --- media/libvorbis/moz.yaml +++ media/libvorbis/moz.yaml @@ -8,12 +8,12 @@ name: libvorbis description: software implementation of the Vorbis specification url: https://xiph.org/vorbis/ - release: c9b52fc1c81d8ced3f2eb880ce68162ff270ec47 (2026-05-24T14:15:22.000-07:00). - revision: c9b52fc1c81d8ced3f2eb880ce68162ff270ec47 + release: e3c9861ff096d52378e131ff8c334552e09cdffa (2026-06-08T13:57:34.000+00:00). + revision: e3c9861ff096d52378e131ff8c334552e09cdffa license: BSD-3-Clause license-file: COPYING