misc/libtremor/info.c
branchhedgeroid
changeset 6043 9bd2d6b1ba52
parent 6041 04bbe344b8d3
child 6045 9a7cc0f29430
equal deleted inserted replaced
6041:04bbe344b8d3 6043:9bd2d6b1ba52
     1 /********************************************************************
       
     2  *                                                                  *
       
     3  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
       
     4  *                                                                  *
       
     5  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
       
     6  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
       
     7  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
       
     8  *                                                                  *
       
     9  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
       
    10  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
       
    11  *                                                                  *
       
    12  ********************************************************************
       
    13 
       
    14  function: maintain the info structure, info <-> header packets
       
    15 
       
    16  ********************************************************************/
       
    17 
       
    18 /* general handling of the header and the vorbis_info structure (and
       
    19    substructures) */
       
    20 
       
    21 #include <stdlib.h>
       
    22 #include <string.h>
       
    23 #include <ctype.h>
       
    24 #include "ogg.h"
       
    25 #include "ivorbiscodec.h"
       
    26 #include "codec_internal.h"
       
    27 #include "codebook.h"
       
    28 #include "registry.h"
       
    29 #include "window.h"
       
    30 #include "misc.h"
       
    31 
       
    32 /* helpers */
       
    33 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
       
    34   while(bytes--){
       
    35     *buf++=oggpack_read(o,8);
       
    36   }
       
    37 }
       
    38 
       
    39 void vorbis_comment_init(vorbis_comment *vc){
       
    40   memset(vc,0,sizeof(*vc));
       
    41 }
       
    42 
       
    43 /* This is more or less the same as strncasecmp - but that doesn't exist
       
    44  * everywhere, and this is a fairly trivial function, so we include it */
       
    45 static int tagcompare(const char *s1, const char *s2, int n){
       
    46   int c=0;
       
    47   while(c < n){
       
    48     if(toupper(s1[c]) != toupper(s2[c]))
       
    49       return !0;
       
    50     c++;
       
    51   }
       
    52   return 0;
       
    53 }
       
    54 
       
    55 char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
       
    56   long i;
       
    57   int found = 0;
       
    58   int taglen = strlen(tag)+1; /* +1 for the = we append */
       
    59   char *fulltag = (char *)alloca(taglen+ 1);
       
    60 
       
    61   strcpy(fulltag, tag);
       
    62   strcat(fulltag, "=");
       
    63   
       
    64   for(i=0;i<vc->comments;i++){
       
    65     if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
       
    66       if(count == found)
       
    67 	/* We return a pointer to the data, not a copy */
       
    68       	return vc->user_comments[i] + taglen;
       
    69       else
       
    70 	found++;
       
    71     }
       
    72   }
       
    73   return NULL; /* didn't find anything */
       
    74 }
       
    75 
       
    76 int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
       
    77   int i,count=0;
       
    78   int taglen = strlen(tag)+1; /* +1 for the = we append */
       
    79   char *fulltag = (char *)alloca(taglen+1);
       
    80   strcpy(fulltag,tag);
       
    81   strcat(fulltag, "=");
       
    82 
       
    83   for(i=0;i<vc->comments;i++){
       
    84     if(!tagcompare(vc->user_comments[i], fulltag, taglen))
       
    85       count++;
       
    86   }
       
    87 
       
    88   return count;
       
    89 }
       
    90 
       
    91 void vorbis_comment_clear(vorbis_comment *vc){
       
    92   if(vc){
       
    93     long i;
       
    94     for(i=0;i<vc->comments;i++)
       
    95       if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
       
    96     if(vc->user_comments)_ogg_free(vc->user_comments);
       
    97 	if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
       
    98     if(vc->vendor)_ogg_free(vc->vendor);
       
    99     memset(vc,0,sizeof(*vc));
       
   100   }
       
   101 }
       
   102 
       
   103 /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
       
   104    They may be equal, but short will never ge greater than long */
       
   105 int vorbis_info_blocksize(vorbis_info *vi,int zo){
       
   106   codec_setup_info *ci = (codec_setup_info *)vi->codec_setup;
       
   107   return ci ? ci->blocksizes[zo] : -1;
       
   108 }
       
   109 
       
   110 /* used by synthesis, which has a full, alloced vi */
       
   111 void vorbis_info_init(vorbis_info *vi){
       
   112   memset(vi,0,sizeof(*vi));
       
   113   vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info));
       
   114 }
       
   115 
       
   116 void vorbis_info_clear(vorbis_info *vi){
       
   117   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
       
   118   int i;
       
   119 
       
   120   if(ci){
       
   121 
       
   122     for(i=0;i<ci->modes;i++)
       
   123       if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
       
   124 
       
   125     for(i=0;i<ci->maps;i++) /* unpack does the range checking */
       
   126       if(ci->map_param[i])
       
   127 	_mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
       
   128 
       
   129     for(i=0;i<ci->floors;i++) /* unpack does the range checking */
       
   130       if(ci->floor_param[i])
       
   131 	_floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
       
   132     
       
   133     for(i=0;i<ci->residues;i++) /* unpack does the range checking */
       
   134       if(ci->residue_param[i])
       
   135 	_residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
       
   136 
       
   137     for(i=0;i<ci->books;i++){
       
   138       if(ci->book_param[i]){
       
   139 	/* knows if the book was not alloced */
       
   140 	vorbis_staticbook_destroy(ci->book_param[i]);
       
   141       }
       
   142       if(ci->fullbooks)
       
   143 	vorbis_book_clear(ci->fullbooks+i);
       
   144     }
       
   145     if(ci->fullbooks)
       
   146 	_ogg_free(ci->fullbooks);
       
   147     
       
   148     _ogg_free(ci);
       
   149   }
       
   150 
       
   151   memset(vi,0,sizeof(*vi));
       
   152 }
       
   153 
       
   154 /* Header packing/unpacking ********************************************/
       
   155 
       
   156 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
       
   157   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
       
   158   if(!ci)return(OV_EFAULT);
       
   159 
       
   160   vi->version=oggpack_read(opb,32);
       
   161   if(vi->version!=0)return(OV_EVERSION);
       
   162 
       
   163   vi->channels=oggpack_read(opb,8);
       
   164   vi->rate=oggpack_read(opb,32);
       
   165 
       
   166   vi->bitrate_upper=oggpack_read(opb,32);
       
   167   vi->bitrate_nominal=oggpack_read(opb,32);
       
   168   vi->bitrate_lower=oggpack_read(opb,32);
       
   169 
       
   170   ci->blocksizes[0]=1<<oggpack_read(opb,4);
       
   171   ci->blocksizes[1]=1<<oggpack_read(opb,4);
       
   172   
       
   173   if(vi->rate<1)goto err_out;
       
   174   if(vi->channels<1)goto err_out;
       
   175   if(ci->blocksizes[0]<64)goto err_out; 
       
   176   if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
       
   177   if(ci->blocksizes[1]>8192)goto err_out;
       
   178   
       
   179   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
       
   180 
       
   181   return(0);
       
   182  err_out:
       
   183   vorbis_info_clear(vi);
       
   184   return(OV_EBADHEADER);
       
   185 }
       
   186 
       
   187 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
       
   188   int i;
       
   189   int vendorlen=oggpack_read(opb,32);
       
   190   if(vendorlen<0)goto err_out;
       
   191   vc->vendor=(char *)_ogg_calloc(vendorlen+1,1);
       
   192   _v_readstring(opb,vc->vendor,vendorlen);
       
   193   vc->comments=oggpack_read(opb,32);
       
   194   if(vc->comments<0)goto err_out;
       
   195   vc->user_comments=(char **)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
       
   196   vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
       
   197 	    
       
   198   for(i=0;i<vc->comments;i++){
       
   199     int len=oggpack_read(opb,32);
       
   200     if(len<0)goto err_out;
       
   201 	vc->comment_lengths[i]=len;
       
   202     vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
       
   203     _v_readstring(opb,vc->user_comments[i],len);
       
   204   }	  
       
   205   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
       
   206 
       
   207   return(0);
       
   208  err_out:
       
   209   vorbis_comment_clear(vc);
       
   210   return(OV_EBADHEADER);
       
   211 }
       
   212 
       
   213 /* all of the real encoding details are here.  The modes, books,
       
   214    everything */
       
   215 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
       
   216   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
       
   217   int i;
       
   218   if(!ci)return(OV_EFAULT);
       
   219 
       
   220   /* codebooks */
       
   221   ci->books=oggpack_read(opb,8)+1;
       
   222   /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/
       
   223   for(i=0;i<ci->books;i++){
       
   224     ci->book_param[i]=(static_codebook *)_ogg_calloc(1,sizeof(*ci->book_param[i]));
       
   225     if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out;
       
   226   }
       
   227 
       
   228   /* time backend settings */
       
   229   ci->times=oggpack_read(opb,6)+1;
       
   230   /*ci->time_type=_ogg_malloc(ci->times*sizeof(*ci->time_type));*/
       
   231   /*ci->time_param=_ogg_calloc(ci->times,sizeof(void *));*/
       
   232   for(i=0;i<ci->times;i++){
       
   233     ci->time_type[i]=oggpack_read(opb,16);
       
   234     if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out;
       
   235     /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb);
       
   236        Vorbis I has no time backend */
       
   237     /*if(!ci->time_param[i])goto err_out;*/
       
   238   }
       
   239 
       
   240   /* floor backend settings */
       
   241   ci->floors=oggpack_read(opb,6)+1;
       
   242   /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/
       
   243   /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/
       
   244   for(i=0;i<ci->floors;i++){
       
   245     ci->floor_type[i]=oggpack_read(opb,16);
       
   246     if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
       
   247     ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
       
   248     if(!ci->floor_param[i])goto err_out;
       
   249   }
       
   250 
       
   251   /* residue backend settings */
       
   252   ci->residues=oggpack_read(opb,6)+1;
       
   253   /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/
       
   254   /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/
       
   255   for(i=0;i<ci->residues;i++){
       
   256     ci->residue_type[i]=oggpack_read(opb,16);
       
   257     if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
       
   258     ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
       
   259     if(!ci->residue_param[i])goto err_out;
       
   260   }
       
   261 
       
   262   /* map backend settings */
       
   263   ci->maps=oggpack_read(opb,6)+1;
       
   264   /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/
       
   265   /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/
       
   266   for(i=0;i<ci->maps;i++){
       
   267     ci->map_type[i]=oggpack_read(opb,16);
       
   268     if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
       
   269     ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
       
   270     if(!ci->map_param[i])goto err_out;
       
   271   }
       
   272   
       
   273   /* mode settings */
       
   274   ci->modes=oggpack_read(opb,6)+1;
       
   275   /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/
       
   276   for(i=0;i<ci->modes;i++){
       
   277     ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i]));
       
   278     ci->mode_param[i]->blockflag=oggpack_read(opb,1);
       
   279     ci->mode_param[i]->windowtype=oggpack_read(opb,16);
       
   280     ci->mode_param[i]->transformtype=oggpack_read(opb,16);
       
   281     ci->mode_param[i]->mapping=oggpack_read(opb,8);
       
   282 
       
   283     if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
       
   284     if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
       
   285     if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
       
   286   }
       
   287   
       
   288   if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
       
   289 
       
   290   return(0);
       
   291  err_out:
       
   292   vorbis_info_clear(vi);
       
   293   return(OV_EBADHEADER);
       
   294 }
       
   295 
       
   296 /* The Vorbis header is in three packets; the initial small packet in
       
   297    the first page that identifies basic parameters, a second packet
       
   298    with bitstream comments and a third packet that holds the
       
   299    codebook. */
       
   300 
       
   301 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
       
   302   oggpack_buffer opb;
       
   303   
       
   304   if(op){
       
   305     oggpack_readinit(&opb,op->packet);
       
   306 
       
   307     /* Which of the three types of header is this? */
       
   308     /* Also verify header-ness, vorbis */
       
   309     {
       
   310       char buffer[6];
       
   311       int packtype=oggpack_read(&opb,8);
       
   312       memset(buffer,0,6);
       
   313       _v_readstring(&opb,buffer,6);
       
   314       if(memcmp(buffer,"vorbis",6)){
       
   315 	/* not a vorbis header */
       
   316 	return(OV_ENOTVORBIS);
       
   317       }
       
   318       switch(packtype){
       
   319       case 0x01: /* least significant *bit* is read first */
       
   320 	if(!op->b_o_s){
       
   321 	  /* Not the initial packet */
       
   322 	  return(OV_EBADHEADER);
       
   323 	}
       
   324 	if(vi->rate!=0){
       
   325 	  /* previously initialized info header */
       
   326 	  return(OV_EBADHEADER);
       
   327 	}
       
   328 
       
   329 	return(_vorbis_unpack_info(vi,&opb));
       
   330 
       
   331       case 0x03: /* least significant *bit* is read first */
       
   332 	if(vi->rate==0){
       
   333 	  /* um... we didn't get the initial header */
       
   334 	  return(OV_EBADHEADER);
       
   335 	}
       
   336 
       
   337 	return(_vorbis_unpack_comment(vc,&opb));
       
   338 
       
   339       case 0x05: /* least significant *bit* is read first */
       
   340 	if(vi->rate==0 || vc->vendor==NULL){
       
   341 	  /* um... we didn;t get the initial header or comments yet */
       
   342 	  return(OV_EBADHEADER);
       
   343 	}
       
   344 
       
   345 	return(_vorbis_unpack_books(vi,&opb));
       
   346 
       
   347       default:
       
   348 	/* Not a valid vorbis header type */
       
   349 	return(OV_EBADHEADER);
       
   350 	break;
       
   351       }
       
   352     }
       
   353   }
       
   354   return(OV_EBADHEADER);
       
   355 }
       
   356