Chris@1: /******************************************************************** Chris@1: * * Chris@1: * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * Chris@1: * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * Chris@1: * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * Chris@1: * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * Chris@1: * * Chris@1: * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * Chris@1: * by the Xiph.Org Foundation http://www.xiph.org/ * Chris@1: * * Chris@1: ******************************************************************** Chris@1: Chris@1: function: utility functions for loading .vqh and .vqd files Chris@1: last mod: $Id: bookutil.c 16959 2010-03-10 16:03:11Z xiphmont $ Chris@1: Chris@1: ********************************************************************/ Chris@1: Chris@1: #include Chris@1: #include Chris@1: #include Chris@1: #include Chris@1: #include Chris@1: #include "bookutil.h" Chris@1: Chris@1: int _best(codebook *book, float *a, int step){ Chris@1: Chris@1: int dim=book->dim; Chris@1: int i,j,o; Chris@1: int minval=book->minval; Chris@1: int del=book->delta; Chris@1: int qv=book->quantvals; Chris@1: int ze=(qv>>1); Chris@1: int index=0; Chris@1: /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ Chris@1: Chris@1: if(del!=1){ Chris@1: for(i=0,o=step*(dim-1);i>1))/del; Chris@1: int m = (v=qv?qv-1:m)); Chris@1: } Chris@1: }else{ Chris@1: for(i=0,o=step*(dim-1);i=qv?qv-1:m)); Chris@1: } Chris@1: } Chris@1: Chris@1: if(book->c->lengthlist[index]<=0){ Chris@1: const static_codebook *c=book->c; Chris@1: int best=-1; Chris@1: /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ Chris@1: int e[8]={0,0,0,0,0,0,0,0}; Chris@1: int maxval = book->minval + book->delta*(book->quantvals-1); Chris@1: for(i=0;ientries;i++){ Chris@1: if(c->lengthlist[i]>0){ Chris@1: float this=0; Chris@1: for(j=0;j=maxval) Chris@1: e[j++]=0; Chris@1: if(e[j]>=0) Chris@1: e[j]+=book->delta; Chris@1: e[j]= -e[j]; Chris@1: } Chris@1: } Chris@1: Chris@1: return index; Chris@1: } Chris@1: Chris@1: /* A few little utils for reading files */ Chris@1: /* read a line. Use global, persistent buffering */ Chris@1: static char *linebuffer=NULL; Chris@1: static int lbufsize=0; Chris@1: char *get_line(FILE *in){ Chris@1: long sofar=0; Chris@1: if(feof(in))return NULL; Chris@1: Chris@1: while(1){ Chris@1: int gotline=0; Chris@1: Chris@1: while(!gotline){ Chris@1: if(sofar+1>=lbufsize){ Chris@1: if(!lbufsize){ Chris@1: lbufsize=1024; Chris@1: linebuffer=_ogg_malloc(lbufsize); Chris@1: }else{ Chris@1: lbufsize*=2; Chris@1: linebuffer=_ogg_realloc(linebuffer,lbufsize); Chris@1: } Chris@1: } Chris@1: { Chris@1: long c=fgetc(in); Chris@1: switch(c){ Chris@1: case EOF: Chris@1: if(sofar==0)return(NULL); Chris@1: /* fallthrough correct */ Chris@1: case '\n': Chris@1: linebuffer[sofar]='\0'; Chris@1: gotline=1; Chris@1: break; Chris@1: default: Chris@1: linebuffer[sofar++]=c; Chris@1: linebuffer[sofar]='\0'; Chris@1: break; Chris@1: } Chris@1: } Chris@1: } Chris@1: Chris@1: if(linebuffer[0]=='#'){ Chris@1: sofar=0; Chris@1: }else{ Chris@1: return(linebuffer); Chris@1: } Chris@1: } Chris@1: } Chris@1: Chris@1: /* read the next numerical value from the given file */ Chris@1: static char *value_line_buff=NULL; Chris@1: Chris@1: int get_line_value(FILE *in,float *value){ Chris@1: char *next; Chris@1: Chris@1: if(!value_line_buff)return(-1); Chris@1: Chris@1: *value=strtod(value_line_buff, &next); Chris@1: if(next==value_line_buff){ Chris@1: value_line_buff=NULL; Chris@1: return(-1); Chris@1: }else{ Chris@1: value_line_buff=next; Chris@1: while(*value_line_buff>44)value_line_buff++; Chris@1: if(*value_line_buff==44)value_line_buff++; Chris@1: return(0); Chris@1: } Chris@1: } Chris@1: Chris@1: int get_next_value(FILE *in,float *value){ Chris@1: while(1){ Chris@1: if(get_line_value(in,value)){ Chris@1: value_line_buff=get_line(in); Chris@1: if(!value_line_buff)return(-1); Chris@1: }else{ Chris@1: return(0); Chris@1: } Chris@1: } Chris@1: } Chris@1: Chris@1: int get_next_ivalue(FILE *in,long *ivalue){ Chris@1: float value; Chris@1: int ret=get_next_value(in,&value); Chris@1: *ivalue=value; Chris@1: return(ret); Chris@1: } Chris@1: Chris@1: static float sequence_base=0.f; Chris@1: static int v_sofar=0; Chris@1: void reset_next_value(void){ Chris@1: value_line_buff=NULL; Chris@1: sequence_base=0.f; Chris@1: v_sofar=0; Chris@1: } Chris@1: Chris@1: char *setup_line(FILE *in){ Chris@1: reset_next_value(); Chris@1: value_line_buff=get_line(in); Chris@1: return(value_line_buff); Chris@1: } Chris@1: Chris@1: Chris@1: int get_vector(codebook *b,FILE *in,int start, int n,float *a){ Chris@1: int i; Chris@1: const static_codebook *c=b->c; Chris@1: Chris@1: while(1){ Chris@1: Chris@1: if(v_sofar==n || get_line_value(in,a)){ Chris@1: reset_next_value(); Chris@1: if(get_next_value(in,a)) Chris@1: break; Chris@1: for(i=0;idim;i++) Chris@1: if(get_line_value(in,a+i)) Chris@1: break; Chris@1: Chris@1: if(i==c->dim){ Chris@1: float temp=a[c->dim-1]; Chris@1: for(i=0;idim;i++)a[i]-=sequence_base; Chris@1: if(c->q_sequencep)sequence_base=temp; Chris@1: v_sofar++; Chris@1: return(0); Chris@1: } Chris@1: sequence_base=0.f; Chris@1: } Chris@1: Chris@1: return(-1); Chris@1: } Chris@1: Chris@1: /* read lines fromt he beginning until we find one containing the Chris@1: specified string */ Chris@1: char *find_seek_to(FILE *in,char *s){ Chris@1: rewind(in); Chris@1: while(1){ Chris@1: char *line=get_line(in); Chris@1: if(line){ Chris@1: if(strstr(line,s)) Chris@1: return(line); Chris@1: }else Chris@1: return(NULL); Chris@1: } Chris@1: } Chris@1: Chris@1: Chris@1: /* this reads the format as written by vqbuild/latticebuild; innocent Chris@1: (legal) tweaking of the file that would not affect its valid Chris@1: header-ness will break this routine */ Chris@1: Chris@1: codebook *codebook_load(char *filename){ Chris@1: codebook *b=_ogg_calloc(1,sizeof(codebook)); Chris@1: static_codebook *c=(static_codebook *)(b->c=_ogg_calloc(1,sizeof(static_codebook))); Chris@1: int quant_to_read=0; Chris@1: FILE *in=fopen(filename,"r"); Chris@1: char *line; Chris@1: long i; Chris@1: Chris@1: if(in==NULL){ Chris@1: fprintf(stderr,"Couldn't open codebook %s\n",filename); Chris@1: exit(1); Chris@1: } Chris@1: Chris@1: /* find the codebook struct */ Chris@1: find_seek_to(in,"static const static_codebook "); Chris@1: Chris@1: /* get the major important values */ Chris@1: line=get_line(in); Chris@1: if(sscanf(line,"%ld, %ld,", Chris@1: &(c->dim),&(c->entries))!=2){ Chris@1: fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line); Chris@1: exit(1); Chris@1: } Chris@1: line=get_line(in); Chris@1: line=get_line(in); Chris@1: if(sscanf(line,"%d, %ld, %ld, %d, %d,", Chris@1: &(c->maptype),&(c->q_min),&(c->q_delta),&(c->q_quant), Chris@1: &(c->q_sequencep))!=5){ Chris@1: fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line); Chris@1: exit(1); Chris@1: } Chris@1: Chris@1: switch(c->maptype){ Chris@1: case 0: Chris@1: quant_to_read=0; Chris@1: break; Chris@1: case 1: Chris@1: quant_to_read=_book_maptype1_quantvals(c); Chris@1: break; Chris@1: case 2: Chris@1: quant_to_read=c->entries*c->dim; Chris@1: break; Chris@1: } Chris@1: Chris@1: /* load the quantized entries */ Chris@1: find_seek_to(in,"static const long _vq_quantlist_"); Chris@1: reset_next_value(); Chris@1: c->quantlist=_ogg_malloc(sizeof(long)*quant_to_read); Chris@1: for(i=0;iquantlist+i)){ Chris@1: fprintf(stderr,"out of data while reading codebook %s\n",filename); Chris@1: exit(1); Chris@1: } Chris@1: Chris@1: /* load the lengthlist */ Chris@1: find_seek_to(in,"_lengthlist"); Chris@1: reset_next_value(); Chris@1: c->lengthlist=_ogg_malloc(sizeof(long)*c->entries); Chris@1: for(i=0;ientries;i++) Chris@1: if(get_next_ivalue(in,c->lengthlist+i)){ Chris@1: fprintf(stderr,"out of data while reading codebook %s\n",filename); Chris@1: exit(1); Chris@1: } Chris@1: Chris@1: /* got it all */ Chris@1: fclose(in); Chris@1: Chris@1: vorbis_book_init_encode(b,c); Chris@1: b->valuelist=_book_unquantize(c,c->entries,NULL); Chris@1: Chris@1: return(b); Chris@1: } Chris@1: Chris@1: void spinnit(char *s,int n){ Chris@1: static int p=0; Chris@1: static long lasttime=0; Chris@1: long test; Chris@1: struct timeval thistime; Chris@1: Chris@1: gettimeofday(&thistime,NULL); Chris@1: test=thistime.tv_sec*10+thistime.tv_usec/100000; Chris@1: if(lasttime!=test){ Chris@1: lasttime=test; Chris@1: Chris@1: fprintf(stderr,"%s%d ",s,n); Chris@1: Chris@1: p++;if(p>3)p=0; Chris@1: switch(p){ Chris@1: case 0: Chris@1: fprintf(stderr,"| \r"); Chris@1: break; Chris@1: case 1: Chris@1: fprintf(stderr,"/ \r"); Chris@1: break; Chris@1: case 2: Chris@1: fprintf(stderr,"- \r"); Chris@1: break; Chris@1: case 3: Chris@1: fprintf(stderr,"\\ \r"); Chris@1: break; Chris@1: } Chris@1: fflush(stderr); Chris@1: } Chris@1: } Chris@1: Chris@1: void build_tree_from_lengths(int vals, long *hist, long *lengths){ Chris@1: int i,j; Chris@1: long *membership=_ogg_malloc(vals*sizeof(long)); Chris@1: long *histsave=alloca(vals*sizeof(long)); Chris@1: memcpy(histsave,hist,vals*sizeof(long)); Chris@1: Chris@1: for(i=0;i1;i--){ Chris@1: int first=-1,second=-1; Chris@1: long least=-1; Chris@1: Chris@1: spinnit("building... ",i); Chris@1: Chris@1: /* find the two nodes to join */ Chris@1: for(j=0;j0) Chris@1: newhist[upper++]=hist[i]; Chris@1: Chris@1: if(upper != vals){ Chris@1: fprintf(stderr,"\rEliminating %d unused entries; %d entries remain\n", Chris@1: vals-upper,upper); Chris@1: } Chris@1: Chris@1: build_tree_from_lengths(upper,newhist,lengthlist); Chris@1: Chris@1: upper=0; Chris@1: for(i=0;i0) Chris@1: lengths[i]=lengthlist[upper++]; Chris@1: else Chris@1: lengths[i]=0; Chris@1: Chris@1: free(lengthlist); Chris@1: } Chris@1: Chris@1: void write_codebook(FILE *out,char *name,const static_codebook *c){ Chris@1: int i,j,k; Chris@1: Chris@1: /* save the book in C header form */ Chris@1: Chris@1: /* first, the static vectors, then the book structure to tie it together. */ Chris@1: /* quantlist */ Chris@1: if(c->quantlist){ Chris@1: long vals=(c->maptype==1?_book_maptype1_quantvals(c):c->entries*c->dim); Chris@1: fprintf(out,"static const long _vq_quantlist_%s[] = {\n",name); Chris@1: for(j=0;jquantlist[j]); Chris@1: } Chris@1: fprintf(out,"};\n\n"); Chris@1: } Chris@1: Chris@1: /* lengthlist */ Chris@1: fprintf(out,"static const long _vq_lengthlist_%s[] = {\n",name); Chris@1: for(j=0;jentries;){ Chris@1: fprintf(out,"\t"); Chris@1: for(k=0;k<16 && jentries;k++,j++) Chris@1: fprintf(out,"%2ld,",c->lengthlist[j]); Chris@1: fprintf(out,"\n"); Chris@1: } Chris@1: fprintf(out,"};\n\n"); Chris@1: Chris@1: /* tie it all together */ Chris@1: Chris@1: fprintf(out,"static const static_codebook %s = {\n",name); Chris@1: Chris@1: fprintf(out,"\t%ld, %ld,\n",c->dim,c->entries); Chris@1: fprintf(out,"\t(long *)_vq_lengthlist_%s,\n",name); Chris@1: fprintf(out,"\t%d, %ld, %ld, %d, %d,\n", Chris@1: c->maptype,c->q_min,c->q_delta,c->q_quant,c->q_sequencep); Chris@1: if(c->quantlist) Chris@1: fprintf(out,"\t(long *)_vq_quantlist_%s,\n",name); Chris@1: else Chris@1: fprintf(out,"\tNULL,\n"); Chris@1: Chris@1: fprintf(out,"\t0\n};\n\n"); Chris@1: }