examples/sfexamples/oggvorbiscodec/src/tremor/info.c

00001 /********************************************************************
00002  *                                                                  *
00003  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
00004  *                                                                  *
00005  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
00006  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
00007  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
00008  *                                                                  *
00009  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
00010  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
00011  *                                                                  *
00012  ********************************************************************
00013 
00014  function: maintain the info structure, info <-> header packets
00015 
00016  ********************************************************************/
00017 
00018 /* general handling of the header and the vorbis_info structure (and
00019    substructures) */
00020 
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <ctype.h>
00024 #include "ogg.h"
00025 #include "ivorbiscodec.h"
00026 #include "codec_internal.h"
00027 #include "codebook.h"
00028 #include "registry.h"
00029 #include "window.h"
00030 #include "misc.h"
00031 #include "os.h"
00032 
00033 /* helpers */
00034 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
00035   while(bytes--){
00036     *buf++=oggpack_read(o,8);
00037   }
00038 }
00039 
00040 void vorbis_comment_init(vorbis_comment *vc){
00041   memset(vc,0,sizeof(*vc));
00042 }
00043 
00044 /* This is more or less the same as strncasecmp - but that doesn't exist
00045  * everywhere, and this is a fairly trivial function, so we include it */
00046 static int tagcompare(const char *s1, const char *s2, int n){
00047   int c=0;
00048   while(c < n){
00049     if(toupper(s1[c]) != toupper(s2[c]))
00050       return !0;
00051     c++;
00052   }
00053   return 0;
00054 }
00055 
00056 char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
00057   long i;
00058   int found = 0;
00059   int taglen = strlen(tag)+1; /* +1 for the = we append */
00060   char *fulltag = (char *)_ogg_malloc(taglen+ 1);       
00061   strcpy(fulltag, tag);
00062   strcat(fulltag, "=");
00063   
00064   for(i=0;i<vc->comments;i++){
00065     if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
00066       if(count == found)
00067       {
00068       _ogg_free(fulltag);
00069       /* We return a pointer to the data, not a copy */
00070         return vc->user_comments[i] + taglen;   
00071       }
00072         
00073       else
00074         found++;
00075     }
00076   }
00077   _ogg_free(fulltag);
00078   return NULL; /* didn't find anything */
00079 }
00080 
00081 int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
00082   int i,count=0;
00083   int taglen = strlen(tag)+1; /* +1 for the = we append */
00084   char *fulltag = (char *)_ogg_malloc(taglen+1);
00085   strcpy(fulltag,tag);
00086   strcat(fulltag, "=");
00087 
00088   for(i=0;i<vc->comments;i++){
00089     if(!tagcompare(vc->user_comments[i], fulltag, taglen))
00090       count++;
00091   }
00092   _ogg_free(fulltag);
00093   return count;
00094 }
00095 
00096 void vorbis_comment_clear(vorbis_comment *vc){
00097   if(vc){
00098     long i;
00099     for(i=0;i<vc->comments;i++)
00100       if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
00101     if(vc->user_comments)_ogg_free(vc->user_comments);
00102         if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
00103     if(vc->vendor)_ogg_free(vc->vendor);
00104     memset(vc,0,sizeof(*vc));
00105   }
00106 }
00107 
00108 /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
00109    They may be equal, but short will never ge greater than long */
00110 int vorbis_info_blocksize(vorbis_info *vi,int zo){
00111   codec_setup_info *ci = (codec_setup_info *)vi->codec_setup;
00112   return ci ? ci->blocksizes[zo] : -1;
00113 }
00114 
00115 /* used by synthesis, which has a full, alloced vi */
00116 void vorbis_info_init(vorbis_info *vi){
00117   memset(vi,0,sizeof(*vi));
00118   vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info));
00119 }
00120 
00121 void vorbis_info_clear(vorbis_info *vi){
00122   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
00123   int i;
00124 
00125   if(ci){
00126 
00127     for(i=0;i<ci->modes;i++)
00128       if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
00129 
00130     for(i=0;i<ci->maps;i++) /* unpack does the range checking */
00131       _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
00132 
00133     for(i=0;i<ci->floors;i++) /* unpack does the range checking */
00134       _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
00135     
00136     for(i=0;i<ci->residues;i++) /* unpack does the range checking */
00137       _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
00138 
00139     for(i=0;i<ci->books;i++){
00140       if(ci->book_param[i]){
00141         /* knows if the book was not alloced */
00142         vorbis_staticbook_destroy(ci->book_param[i]);
00143       }
00144       if(ci->fullbooks)
00145         vorbis_book_clear(ci->fullbooks+i);
00146     }
00147     if(ci->fullbooks)
00148         _ogg_free(ci->fullbooks);
00149     
00150     _ogg_free(ci);
00151   }
00152 
00153   memset(vi,0,sizeof(*vi));
00154 }
00155 
00156 /* Header packing/unpacking ********************************************/
00157 
00158 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
00159   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
00160   if(!ci)return(OV_EFAULT);
00161 
00162   vi->version=oggpack_read(opb,32);
00163   if(vi->version!=0)return(OV_EVERSION);
00164 
00165   vi->channels=oggpack_read(opb,8);
00166   vi->rate=oggpack_read(opb,32);
00167 
00168   vi->bitrate_upper=oggpack_read(opb,32);
00169   vi->bitrate_nominal=oggpack_read(opb,32);
00170   vi->bitrate_lower=oggpack_read(opb,32);
00171 
00172   ci->blocksizes[0]=1<<oggpack_read(opb,4);
00173   ci->blocksizes[1]=1<<oggpack_read(opb,4);
00174   
00175   if(vi->rate<1)goto err_out;
00176   if(vi->channels<1)goto err_out;
00177   if(ci->blocksizes[0]<64)goto err_out; 
00178   if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
00179   if(ci->blocksizes[1]>8192)goto err_out;
00180   
00181   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
00182 
00183   return(0);
00184  err_out:
00185   vorbis_info_clear(vi);
00186   return(OV_EBADHEADER);
00187 }
00188 
00189 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
00190   int i;
00191   int vendorlen=oggpack_read(opb,32);
00192   if(vendorlen<0)goto err_out;
00193   vc->vendor=(char *)_ogg_calloc(vendorlen+1,1);
00194   _v_readstring(opb,vc->vendor,vendorlen);
00195   vc->comments=oggpack_read(opb,32);
00196   if(vc->comments<0)goto err_out;
00197   vc->user_comments=(char **)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
00198   vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
00199             
00200   for(i=0;i<vc->comments;i++){
00201     int len=oggpack_read(opb,32);
00202     if(len<0)goto err_out;
00203         vc->comment_lengths[i]=len;
00204     vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
00205     _v_readstring(opb,vc->user_comments[i],len);
00206   }       
00207   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
00208 
00209   return(0);
00210  err_out:
00211   vorbis_comment_clear(vc);
00212   return(OV_EBADHEADER);
00213 }
00214 
00215 /* all of the real encoding details are here.  The modes, books,
00216    everything */
00217 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
00218   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
00219   int i;
00220   if(!ci)return(OV_EFAULT);
00221 
00222   /* codebooks */
00223   ci->books=oggpack_read(opb,8)+1;
00224   /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/
00225   for(i=0;i<ci->books;i++){
00226     ci->book_param[i]=(static_codebook *)_ogg_calloc(1,sizeof(*ci->book_param[i]));
00227     if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out;
00228   }
00229 
00230   /* time backend settings */
00231   ci->times=oggpack_read(opb,6)+1;
00232   /*ci->time_type=_ogg_malloc(ci->times*sizeof(*ci->time_type));*/
00233   /*ci->time_param=_ogg_calloc(ci->times,sizeof(void *));*/
00234   for(i=0;i<ci->times;i++){
00235     ci->time_type[i]=oggpack_read(opb,16);
00236     if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out;
00237     /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb);
00238        Vorbis I has no time backend */
00239     /*if(!ci->time_param[i])goto err_out;*/
00240   }
00241 
00242   /* floor backend settings */
00243   ci->floors=oggpack_read(opb,6)+1;
00244   /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/
00245   /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/
00246   for(i=0;i<ci->floors;i++){
00247     ci->floor_type[i]=oggpack_read(opb,16);
00248     if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
00249     ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
00250     if(!ci->floor_param[i])goto err_out;
00251   }
00252 
00253   /* residue backend settings */
00254   ci->residues=oggpack_read(opb,6)+1;
00255   /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/
00256   /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/
00257   for(i=0;i<ci->residues;i++){
00258     ci->residue_type[i]=oggpack_read(opb,16);
00259     if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
00260     ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
00261     if(!ci->residue_param[i])goto err_out;
00262   }
00263 
00264   /* map backend settings */
00265   ci->maps=oggpack_read(opb,6)+1;
00266   /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/
00267   /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/
00268   for(i=0;i<ci->maps;i++){
00269     ci->map_type[i]=oggpack_read(opb,16);
00270     if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
00271     ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
00272     if(!ci->map_param[i])goto err_out;
00273   }
00274   
00275   /* mode settings */
00276   ci->modes=oggpack_read(opb,6)+1;
00277   /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/
00278   for(i=0;i<ci->modes;i++){
00279     ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i]));
00280     ci->mode_param[i]->blockflag=oggpack_read(opb,1);
00281     ci->mode_param[i]->windowtype=oggpack_read(opb,16);
00282     ci->mode_param[i]->transformtype=oggpack_read(opb,16);
00283     ci->mode_param[i]->mapping=oggpack_read(opb,8);
00284 
00285     if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
00286     if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
00287     if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
00288   }
00289   
00290   if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
00291 
00292   return(0);
00293  err_out:
00294   vorbis_info_clear(vi);
00295   return(OV_EBADHEADER);
00296 }
00297 
00298 /* The Vorbis header is in three packets; the initial small packet in
00299    the first page that identifies basic parameters, a second packet
00300    with bitstream comments and a third packet that holds the
00301    codebook. */
00302 
00303 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
00304   oggpack_buffer opb;
00305   
00306   if(op){
00307     oggpack_readinit(&opb,op->packet);
00308 
00309     /* Which of the three types of header is this? */
00310     /* Also verify header-ness, vorbis */
00311     {
00312       char buffer[6];
00313       int packtype=oggpack_read(&opb,8);
00314       memset(buffer,0,6);
00315       _v_readstring(&opb,buffer,6);
00316       if(memcmp(buffer,"vorbis",6)){
00317         /* not a vorbis header */
00318         return(OV_ENOTVORBIS);
00319       }
00320       switch(packtype){
00321       case 0x01: /* least significant *bit* is read first */
00322         if(!op->b_o_s){
00323           /* Not the initial packet */
00324           return(OV_EBADHEADER);
00325         }
00326         if(vi->rate!=0){
00327           /* previously initialized info header */
00328           return(OV_EBADHEADER);
00329         }
00330 
00331         return(_vorbis_unpack_info(vi,&opb));
00332 
00333       case 0x03: /* least significant *bit* is read first */
00334         if(vi->rate==0){
00335           /* um... we didn't get the initial header */
00336           return(OV_EBADHEADER);
00337         }
00338 
00339         return(_vorbis_unpack_comment(vc,&opb));
00340 
00341       case 0x05: /* least significant *bit* is read first */
00342         if(vi->rate==0 || vc->vendor==NULL){
00343           /* um... we didn;t get the initial header or comments yet */
00344           return(OV_EBADHEADER);
00345         }
00346 
00347         return(_vorbis_unpack_books(vi,&opb));
00348 
00349       default:
00350         /* Not a valid vorbis header type */
00351         return(OV_EBADHEADER);
00352         }
00353     }
00354   }
00355   return(OV_EBADHEADER);
00356 }
00357 

Generated by  doxygen 1.6.2