treminfo.c revision 0f6f2525f7b19c7de18bafe464b5ced1c714430a
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 "misc.h" 29#include "os.h" 30 31/* helpers */ 32static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ 33 while(bytes--){ 34 *buf++=(char)oggpack_read(o,8); 35 } 36} 37 38void vorbis_comment_init(vorbis_comment *vc){ 39 memset(vc,0,sizeof(*vc)); 40} 41 42/* This is more or less the same as strncasecmp - but that doesn't exist 43 * everywhere, and this is a fairly trivial function, so we include it */ 44static int tagcompare(const char *s1, const char *s2, int n){ 45 int c=0; 46 while(c < n){ 47 if(toupper(s1[c]) != toupper(s2[c])) 48 return !0; 49 c++; 50 } 51 return 0; 52} 53 54char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){ 55 long i; 56 int found = 0; 57 int taglen = strlen(tag)+1; /* +1 for the = we append */ 58 char *fulltag = (char *)alloca(taglen+ 1); 59 60 strcpy(fulltag, tag); 61 strcat(fulltag, "="); 62 63 for(i=0;i<vc->comments;i++){ 64 if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ 65 if(count == found) 66 /* We return a pointer to the data, not a copy */ 67 return vc->user_comments[i] + taglen; 68 else 69 found++; 70 } 71 } 72 return NULL; /* didn't find anything */ 73} 74 75int vorbis_comment_query_count(vorbis_comment *vc, char *tag){ 76 int i,count=0; 77 int taglen = strlen(tag)+1; /* +1 for the = we append */ 78 char *fulltag = (char *)alloca(taglen+1); 79 strcpy(fulltag,tag); 80 strcat(fulltag, "="); 81 82 for(i=0;i<vc->comments;i++){ 83 if(!tagcompare(vc->user_comments[i], fulltag, taglen)) 84 count++; 85 } 86 87 return count; 88} 89 90void vorbis_comment_clear(vorbis_comment *vc){ 91 if(vc){ 92 long i; 93 for(i=0;i<vc->comments;i++) 94 if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); 95 if(vc->user_comments)_ogg_free(vc->user_comments); 96 if(vc->comment_lengths)_ogg_free(vc->comment_lengths); 97 if(vc->vendor)_ogg_free(vc->vendor); 98 } 99 memset(vc,0,sizeof(*vc)); 100} 101 102/* blocksize 0 is guaranteed to be short, 1 is guarantted to be long. 103 They may be equal, but short will never ge greater than long */ 104int vorbis_info_blocksize(vorbis_info *vi,int zo){ 105 codec_setup_info *ci = (codec_setup_info *)vi->codec_setup; 106 return ci ? ci->blocksizes[zo] : -1; 107} 108 109/* used by synthesis, which has a full, alloced vi */ 110void vorbis_info_init(vorbis_info *vi){ 111 memset(vi,0,sizeof(*vi)); 112 vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info)); 113} 114 115void vorbis_info_clear(vorbis_info *vi){ 116 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 117 int i; 118 119 if(ci){ 120 121 if(ci->mode_param)_ogg_free(ci->mode_param); 122 123 if(ci->map_param){ 124 for(i=0;i<ci->maps;i++) /* unpack does the range checking */ 125 mapping_clear_info(ci->map_param+i); 126 _ogg_free(ci->map_param); 127 } 128 129 if(ci->floor_param){ 130 for(i=0;i<ci->floors;i++) /* unpack does the range checking */ 131 if(ci->floor_type[i]) 132 floor1_free_info(ci->floor_param[i]); 133 else 134 floor0_free_info(ci->floor_param[i]); 135 _ogg_free(ci->floor_param); 136 _ogg_free(ci->floor_type); 137 } 138 139 if(ci->residue_param){ 140 for(i=0;i<ci->residues;i++) /* unpack does the range checking */ 141 res_clear_info(ci->residue_param+i); 142 _ogg_free(ci->residue_param); 143 } 144 145 if(ci->book_param){ 146 for(i=0;i<ci->books;i++) 147 vorbis_book_clear(ci->book_param+i); 148 _ogg_free(ci->book_param); 149 } 150 151 _ogg_free(ci); 152 } 153 154 memset(vi,0,sizeof(*vi)); 155} 156 157/* Header packing/unpacking ********************************************/ 158 159static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ 160 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 161 if(!ci)return(OV_EFAULT); 162 163 vi->version=oggpack_read(opb,32); 164 if(vi->version!=0)return(OV_EVERSION); 165 166 vi->channels=oggpack_read(opb,8); 167 vi->rate=oggpack_read(opb,32); 168 169 vi->bitrate_upper=oggpack_read(opb,32); 170 vi->bitrate_nominal=oggpack_read(opb,32); 171 vi->bitrate_lower=oggpack_read(opb,32); 172 173 ci->blocksizes[0]=1<<oggpack_read(opb,4); 174 ci->blocksizes[1]=1<<oggpack_read(opb,4); 175 176#ifdef LIMIT_TO_64kHz 177 if(vi->rate>=64000 || ci->blocksizes[1]>4096)goto err_out; 178#else 179 if(vi->rate<64000 && ci->blocksizes[1]>4096)goto err_out; 180#endif 181 182 if(vi->rate<1)goto err_out; 183 if(vi->channels<1)goto err_out; 184 if(ci->blocksizes[0]<64)goto err_out; 185 if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out; 186 if(ci->blocksizes[1]>8192)goto err_out; 187 188 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ 189 190 return(0); 191 err_out: 192 vorbis_info_clear(vi); 193 return(OV_EBADHEADER); 194} 195 196static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ 197 int i; 198 int vendorlen=oggpack_read(opb,32); 199 if(vendorlen<0)goto err_out; 200 vc->vendor=(char *)_ogg_calloc(vendorlen+1,1); 201 _v_readstring(opb,vc->vendor,vendorlen); 202 vc->comments=oggpack_read(opb,32); 203 if(vc->comments<0)goto err_out; 204 vc->user_comments=(char **)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); 205 vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); 206 207 for(i=0;i<vc->comments;i++){ 208 int len=oggpack_read(opb,32); 209 if(len<0)goto err_out; 210 vc->comment_lengths[i]=len; 211 vc->user_comments[i]=(char *)_ogg_calloc(len+1,1); 212 _v_readstring(opb,vc->user_comments[i],len); 213 } 214 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ 215 216 return(0); 217 err_out: 218 vorbis_comment_clear(vc); 219 return(OV_EBADHEADER); 220} 221 222/* all of the real encoding details are here. The modes, books, 223 everything */ 224static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ 225 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 226 int i; 227 if(!ci)return(OV_EFAULT); 228 229 /* codebooks */ 230 ci->books=oggpack_read(opb,8)+1; 231 ci->book_param=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->book_param)); 232 for(i=0;i<ci->books;i++) 233 if(vorbis_book_unpack(opb,ci->book_param+i))goto err_out; 234 235 /* time backend settings, not actually used */ 236 i=oggpack_read(opb,6); 237 for(;i>=0;i--) 238 if(oggpack_read(opb,16)!=0)goto err_out; 239 240 /* floor backend settings */ 241 ci->floors=oggpack_read(opb,6)+1; 242 ci->floor_param=_ogg_malloc(sizeof(*ci->floor_param)*ci->floors); 243 ci->floor_type=_ogg_malloc(sizeof(*ci->floor_type)*ci->floors); 244 for(i=0;i<ci->floors;i++){ 245 ci->floor_type[i]=(char)oggpack_read(opb,16); 246 if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; 247 if(ci->floor_type[i]) 248 ci->floor_param[i]=floor1_info_unpack(vi,opb); 249 else 250 ci->floor_param[i]=floor0_info_unpack(vi,opb); 251 if(!ci->floor_param[i])goto err_out; 252 } 253 254 /* residue backend settings */ 255 ci->residues=oggpack_read(opb,6)+1; 256 ci->residue_param=_ogg_malloc(sizeof(*ci->residue_param)*ci->residues); 257 for(i=0;i<ci->residues;i++) 258 if(res_unpack(ci->residue_param+i,vi,opb))goto err_out; 259 260 /* map backend settings */ 261 ci->maps=oggpack_read(opb,6)+1; 262 ci->map_param=_ogg_malloc(sizeof(*ci->map_param)*ci->maps); 263 for(i=0;i<ci->maps;i++){ 264 if(oggpack_read(opb,16)!=0)goto err_out; 265 if(mapping_info_unpack(ci->map_param+i,vi,opb))goto err_out; 266 } 267 268 /* mode settings */ 269 ci->modes=oggpack_read(opb,6)+1; 270 ci->mode_param= 271 (vorbis_info_mode *)_ogg_malloc(ci->modes*sizeof(*ci->mode_param)); 272 for(i=0;i<ci->modes;i++){ 273 ci->mode_param[i].blockflag=(unsigned char)oggpack_read(opb,1); 274 if(oggpack_read(opb,16))goto err_out; 275 if(oggpack_read(opb,16))goto err_out; 276 ci->mode_param[i].mapping=(unsigned char)oggpack_read(opb,8); 277 if(ci->mode_param[i].mapping>=ci->maps)goto err_out; 278 } 279 280 if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ 281 282 return(0); 283 err_out: 284 vorbis_info_clear(vi); 285 return(OV_EBADHEADER); 286} 287 288/* The Vorbis header is in three packets; the initial small packet in 289 the first page that identifies basic parameters, a second packet 290 with bitstream comments and a third packet that holds the 291 codebook. */ 292 293int vorbis_dsp_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ 294 oggpack_buffer opb; 295 296 if(op){ 297 oggpack_readinit(&opb,op->packet); 298 299 /* Which of the three types of header is this? */ 300 /* Also verify header-ness, vorbis */ 301 { 302 char buffer[6]; 303 int packtype=oggpack_read(&opb,8); 304 memset(buffer,0,6); 305 _v_readstring(&opb,buffer,6); 306 if(memcmp(buffer,"vorbis",6)){ 307 /* not a vorbis header */ 308 return(OV_ENOTVORBIS); 309 } 310 switch(packtype){ 311 case 0x01: /* least significant *bit* is read first */ 312 if(!op->b_o_s){ 313 /* Not the initial packet */ 314 return(OV_EBADHEADER); 315 } 316 if(vi->rate!=0){ 317 /* previously initialized info header */ 318 return(OV_EBADHEADER); 319 } 320 321 return(_vorbis_unpack_info(vi,&opb)); 322 323 case 0x03: /* least significant *bit* is read first */ 324 if(vi->rate==0){ 325 /* um... we didn't get the initial header */ 326 return(OV_EBADHEADER); 327 } 328 329 return(_vorbis_unpack_comment(vc,&opb)); 330 331 case 0x05: /* least significant *bit* is read first */ 332 if(vi->rate==0 || vc->vendor==NULL){ 333 /* um... we didn;t get the initial header or comments yet */ 334 return(OV_EBADHEADER); 335 } 336 337 return(_vorbis_unpack_books(vi,&opb)); 338 339 default: 340 /* Not a valid vorbis header type */ 341 return(OV_EBADHEADER); 342 break; 343 } 344 } 345 } 346 return(OV_EBADHEADER); 347} 348 349