media/libtremor/lib/tremor_info.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial