annotate src/libvorbis-1.3.3/lib/info.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 05aa0afa9217
children
rev   line source
Chris@1 1 /********************************************************************
Chris@1 2 * *
Chris@1 3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
Chris@1 4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
Chris@1 5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
Chris@1 6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
Chris@1 7 * *
Chris@1 8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
Chris@1 9 * by the Xiph.Org Foundation http://www.xiph.org/ *
Chris@1 10 * *
Chris@1 11 ********************************************************************
Chris@1 12
Chris@1 13 function: maintain the info structure, info <-> header packets
Chris@1 14 last mod: $Id: info.c 18186 2012-02-03 22:08:44Z xiphmont $
Chris@1 15
Chris@1 16 ********************************************************************/
Chris@1 17
Chris@1 18 /* general handling of the header and the vorbis_info structure (and
Chris@1 19 substructures) */
Chris@1 20
Chris@1 21 #include <stdlib.h>
Chris@1 22 #include <string.h>
Chris@1 23 #include <ctype.h>
Chris@1 24 #include <ogg/ogg.h>
Chris@1 25 #include "vorbis/codec.h"
Chris@1 26 #include "codec_internal.h"
Chris@1 27 #include "codebook.h"
Chris@1 28 #include "registry.h"
Chris@1 29 #include "window.h"
Chris@1 30 #include "psy.h"
Chris@1 31 #include "misc.h"
Chris@1 32 #include "os.h"
Chris@1 33
Chris@1 34 #define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.3"
Chris@1 35 #define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20120203 (Omnipresent)"
Chris@1 36
Chris@1 37 /* helpers */
Chris@1 38 static int ilog2(unsigned int v){
Chris@1 39 int ret=0;
Chris@1 40 if(v)--v;
Chris@1 41 while(v){
Chris@1 42 ret++;
Chris@1 43 v>>=1;
Chris@1 44 }
Chris@1 45 return(ret);
Chris@1 46 }
Chris@1 47
Chris@1 48 static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){
Chris@1 49
Chris@1 50 while(bytes--){
Chris@1 51 oggpack_write(o,*s++,8);
Chris@1 52 }
Chris@1 53 }
Chris@1 54
Chris@1 55 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
Chris@1 56 while(bytes--){
Chris@1 57 *buf++=oggpack_read(o,8);
Chris@1 58 }
Chris@1 59 }
Chris@1 60
Chris@1 61 void vorbis_comment_init(vorbis_comment *vc){
Chris@1 62 memset(vc,0,sizeof(*vc));
Chris@1 63 }
Chris@1 64
Chris@1 65 void vorbis_comment_add(vorbis_comment *vc,const char *comment){
Chris@1 66 vc->user_comments=_ogg_realloc(vc->user_comments,
Chris@1 67 (vc->comments+2)*sizeof(*vc->user_comments));
Chris@1 68 vc->comment_lengths=_ogg_realloc(vc->comment_lengths,
Chris@1 69 (vc->comments+2)*sizeof(*vc->comment_lengths));
Chris@1 70 vc->comment_lengths[vc->comments]=strlen(comment);
Chris@1 71 vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1);
Chris@1 72 strcpy(vc->user_comments[vc->comments], comment);
Chris@1 73 vc->comments++;
Chris@1 74 vc->user_comments[vc->comments]=NULL;
Chris@1 75 }
Chris@1 76
Chris@1 77 void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents){
Chris@1 78 char *comment=alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */
Chris@1 79 strcpy(comment, tag);
Chris@1 80 strcat(comment, "=");
Chris@1 81 strcat(comment, contents);
Chris@1 82 vorbis_comment_add(vc, comment);
Chris@1 83 }
Chris@1 84
Chris@1 85 /* This is more or less the same as strncasecmp - but that doesn't exist
Chris@1 86 * everywhere, and this is a fairly trivial function, so we include it */
Chris@1 87 static int tagcompare(const char *s1, const char *s2, int n){
Chris@1 88 int c=0;
Chris@1 89 while(c < n){
Chris@1 90 if(toupper(s1[c]) != toupper(s2[c]))
Chris@1 91 return !0;
Chris@1 92 c++;
Chris@1 93 }
Chris@1 94 return 0;
Chris@1 95 }
Chris@1 96
Chris@1 97 char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count){
Chris@1 98 long i;
Chris@1 99 int found = 0;
Chris@1 100 int taglen = strlen(tag)+1; /* +1 for the = we append */
Chris@1 101 char *fulltag = alloca(taglen+ 1);
Chris@1 102
Chris@1 103 strcpy(fulltag, tag);
Chris@1 104 strcat(fulltag, "=");
Chris@1 105
Chris@1 106 for(i=0;i<vc->comments;i++){
Chris@1 107 if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
Chris@1 108 if(count == found)
Chris@1 109 /* We return a pointer to the data, not a copy */
Chris@1 110 return vc->user_comments[i] + taglen;
Chris@1 111 else
Chris@1 112 found++;
Chris@1 113 }
Chris@1 114 }
Chris@1 115 return NULL; /* didn't find anything */
Chris@1 116 }
Chris@1 117
Chris@1 118 int vorbis_comment_query_count(vorbis_comment *vc, const char *tag){
Chris@1 119 int i,count=0;
Chris@1 120 int taglen = strlen(tag)+1; /* +1 for the = we append */
Chris@1 121 char *fulltag = alloca(taglen+1);
Chris@1 122 strcpy(fulltag,tag);
Chris@1 123 strcat(fulltag, "=");
Chris@1 124
Chris@1 125 for(i=0;i<vc->comments;i++){
Chris@1 126 if(!tagcompare(vc->user_comments[i], fulltag, taglen))
Chris@1 127 count++;
Chris@1 128 }
Chris@1 129
Chris@1 130 return count;
Chris@1 131 }
Chris@1 132
Chris@1 133 void vorbis_comment_clear(vorbis_comment *vc){
Chris@1 134 if(vc){
Chris@1 135 long i;
Chris@1 136 if(vc->user_comments){
Chris@1 137 for(i=0;i<vc->comments;i++)
Chris@1 138 if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
Chris@1 139 _ogg_free(vc->user_comments);
Chris@1 140 }
Chris@1 141 if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
Chris@1 142 if(vc->vendor)_ogg_free(vc->vendor);
Chris@1 143 memset(vc,0,sizeof(*vc));
Chris@1 144 }
Chris@1 145 }
Chris@1 146
Chris@1 147 /* blocksize 0 is guaranteed to be short, 1 is guaranteed to be long.
Chris@1 148 They may be equal, but short will never ge greater than long */
Chris@1 149 int vorbis_info_blocksize(vorbis_info *vi,int zo){
Chris@1 150 codec_setup_info *ci = vi->codec_setup;
Chris@1 151 return ci ? ci->blocksizes[zo] : -1;
Chris@1 152 }
Chris@1 153
Chris@1 154 /* used by synthesis, which has a full, alloced vi */
Chris@1 155 void vorbis_info_init(vorbis_info *vi){
Chris@1 156 memset(vi,0,sizeof(*vi));
Chris@1 157 vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info));
Chris@1 158 }
Chris@1 159
Chris@1 160 void vorbis_info_clear(vorbis_info *vi){
Chris@1 161 codec_setup_info *ci=vi->codec_setup;
Chris@1 162 int i;
Chris@1 163
Chris@1 164 if(ci){
Chris@1 165
Chris@1 166 for(i=0;i<ci->modes;i++)
Chris@1 167 if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
Chris@1 168
Chris@1 169 for(i=0;i<ci->maps;i++) /* unpack does the range checking */
Chris@1 170 if(ci->map_param[i]) /* this may be cleaning up an aborted
Chris@1 171 unpack, in which case the below type
Chris@1 172 cannot be trusted */
Chris@1 173 _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
Chris@1 174
Chris@1 175 for(i=0;i<ci->floors;i++) /* unpack does the range checking */
Chris@1 176 if(ci->floor_param[i]) /* this may be cleaning up an aborted
Chris@1 177 unpack, in which case the below type
Chris@1 178 cannot be trusted */
Chris@1 179 _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
Chris@1 180
Chris@1 181 for(i=0;i<ci->residues;i++) /* unpack does the range checking */
Chris@1 182 if(ci->residue_param[i]) /* this may be cleaning up an aborted
Chris@1 183 unpack, in which case the below type
Chris@1 184 cannot be trusted */
Chris@1 185 _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
Chris@1 186
Chris@1 187 for(i=0;i<ci->books;i++){
Chris@1 188 if(ci->book_param[i]){
Chris@1 189 /* knows if the book was not alloced */
Chris@1 190 vorbis_staticbook_destroy(ci->book_param[i]);
Chris@1 191 }
Chris@1 192 if(ci->fullbooks)
Chris@1 193 vorbis_book_clear(ci->fullbooks+i);
Chris@1 194 }
Chris@1 195 if(ci->fullbooks)
Chris@1 196 _ogg_free(ci->fullbooks);
Chris@1 197
Chris@1 198 for(i=0;i<ci->psys;i++)
Chris@1 199 _vi_psy_free(ci->psy_param[i]);
Chris@1 200
Chris@1 201 _ogg_free(ci);
Chris@1 202 }
Chris@1 203
Chris@1 204 memset(vi,0,sizeof(*vi));
Chris@1 205 }
Chris@1 206
Chris@1 207 /* Header packing/unpacking ********************************************/
Chris@1 208
Chris@1 209 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
Chris@1 210 codec_setup_info *ci=vi->codec_setup;
Chris@1 211 if(!ci)return(OV_EFAULT);
Chris@1 212
Chris@1 213 vi->version=oggpack_read(opb,32);
Chris@1 214 if(vi->version!=0)return(OV_EVERSION);
Chris@1 215
Chris@1 216 vi->channels=oggpack_read(opb,8);
Chris@1 217 vi->rate=oggpack_read(opb,32);
Chris@1 218
Chris@1 219 vi->bitrate_upper=oggpack_read(opb,32);
Chris@1 220 vi->bitrate_nominal=oggpack_read(opb,32);
Chris@1 221 vi->bitrate_lower=oggpack_read(opb,32);
Chris@1 222
Chris@1 223 ci->blocksizes[0]=1<<oggpack_read(opb,4);
Chris@1 224 ci->blocksizes[1]=1<<oggpack_read(opb,4);
Chris@1 225
Chris@1 226 if(vi->rate<1)goto err_out;
Chris@1 227 if(vi->channels<1)goto err_out;
Chris@1 228 if(ci->blocksizes[0]<64)goto err_out;
Chris@1 229 if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
Chris@1 230 if(ci->blocksizes[1]>8192)goto err_out;
Chris@1 231
Chris@1 232 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
Chris@1 233
Chris@1 234 return(0);
Chris@1 235 err_out:
Chris@1 236 vorbis_info_clear(vi);
Chris@1 237 return(OV_EBADHEADER);
Chris@1 238 }
Chris@1 239
Chris@1 240 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
Chris@1 241 int i;
Chris@1 242 int vendorlen=oggpack_read(opb,32);
Chris@1 243 if(vendorlen<0)goto err_out;
Chris@1 244 if(vendorlen>opb->storage-8)goto err_out;
Chris@1 245 vc->vendor=_ogg_calloc(vendorlen+1,1);
Chris@1 246 _v_readstring(opb,vc->vendor,vendorlen);
Chris@1 247 i=oggpack_read(opb,32);
Chris@1 248 if(i<0)goto err_out;
Chris@1 249 if(i>((opb->storage-oggpack_bytes(opb))>>2))goto err_out;
Chris@1 250 vc->comments=i;
Chris@1 251 vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
Chris@1 252 vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
Chris@1 253
Chris@1 254 for(i=0;i<vc->comments;i++){
Chris@1 255 int len=oggpack_read(opb,32);
Chris@1 256 if(len<0)goto err_out;
Chris@1 257 if(len>opb->storage-oggpack_bytes(opb))goto err_out;
Chris@1 258 vc->comment_lengths[i]=len;
Chris@1 259 vc->user_comments[i]=_ogg_calloc(len+1,1);
Chris@1 260 _v_readstring(opb,vc->user_comments[i],len);
Chris@1 261 }
Chris@1 262 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
Chris@1 263
Chris@1 264 return(0);
Chris@1 265 err_out:
Chris@1 266 vorbis_comment_clear(vc);
Chris@1 267 return(OV_EBADHEADER);
Chris@1 268 }
Chris@1 269
Chris@1 270 /* all of the real encoding details are here. The modes, books,
Chris@1 271 everything */
Chris@1 272 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
Chris@1 273 codec_setup_info *ci=vi->codec_setup;
Chris@1 274 int i;
Chris@1 275 if(!ci)return(OV_EFAULT);
Chris@1 276
Chris@1 277 /* codebooks */
Chris@1 278 ci->books=oggpack_read(opb,8)+1;
Chris@1 279 if(ci->books<=0)goto err_out;
Chris@1 280 for(i=0;i<ci->books;i++){
Chris@1 281 ci->book_param[i]=vorbis_staticbook_unpack(opb);
Chris@1 282 if(!ci->book_param[i])goto err_out;
Chris@1 283 }
Chris@1 284
Chris@1 285 /* time backend settings; hooks are unused */
Chris@1 286 {
Chris@1 287 int times=oggpack_read(opb,6)+1;
Chris@1 288 if(times<=0)goto err_out;
Chris@1 289 for(i=0;i<times;i++){
Chris@1 290 int test=oggpack_read(opb,16);
Chris@1 291 if(test<0 || test>=VI_TIMEB)goto err_out;
Chris@1 292 }
Chris@1 293 }
Chris@1 294
Chris@1 295 /* floor backend settings */
Chris@1 296 ci->floors=oggpack_read(opb,6)+1;
Chris@1 297 if(ci->floors<=0)goto err_out;
Chris@1 298 for(i=0;i<ci->floors;i++){
Chris@1 299 ci->floor_type[i]=oggpack_read(opb,16);
Chris@1 300 if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
Chris@1 301 ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
Chris@1 302 if(!ci->floor_param[i])goto err_out;
Chris@1 303 }
Chris@1 304
Chris@1 305 /* residue backend settings */
Chris@1 306 ci->residues=oggpack_read(opb,6)+1;
Chris@1 307 if(ci->residues<=0)goto err_out;
Chris@1 308 for(i=0;i<ci->residues;i++){
Chris@1 309 ci->residue_type[i]=oggpack_read(opb,16);
Chris@1 310 if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
Chris@1 311 ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
Chris@1 312 if(!ci->residue_param[i])goto err_out;
Chris@1 313 }
Chris@1 314
Chris@1 315 /* map backend settings */
Chris@1 316 ci->maps=oggpack_read(opb,6)+1;
Chris@1 317 if(ci->maps<=0)goto err_out;
Chris@1 318 for(i=0;i<ci->maps;i++){
Chris@1 319 ci->map_type[i]=oggpack_read(opb,16);
Chris@1 320 if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
Chris@1 321 ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
Chris@1 322 if(!ci->map_param[i])goto err_out;
Chris@1 323 }
Chris@1 324
Chris@1 325 /* mode settings */
Chris@1 326 ci->modes=oggpack_read(opb,6)+1;
Chris@1 327 if(ci->modes<=0)goto err_out;
Chris@1 328 for(i=0;i<ci->modes;i++){
Chris@1 329 ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i]));
Chris@1 330 ci->mode_param[i]->blockflag=oggpack_read(opb,1);
Chris@1 331 ci->mode_param[i]->windowtype=oggpack_read(opb,16);
Chris@1 332 ci->mode_param[i]->transformtype=oggpack_read(opb,16);
Chris@1 333 ci->mode_param[i]->mapping=oggpack_read(opb,8);
Chris@1 334
Chris@1 335 if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
Chris@1 336 if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
Chris@1 337 if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
Chris@1 338 if(ci->mode_param[i]->mapping<0)goto err_out;
Chris@1 339 }
Chris@1 340
Chris@1 341 if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
Chris@1 342
Chris@1 343 return(0);
Chris@1 344 err_out:
Chris@1 345 vorbis_info_clear(vi);
Chris@1 346 return(OV_EBADHEADER);
Chris@1 347 }
Chris@1 348
Chris@1 349 /* Is this packet a vorbis ID header? */
Chris@1 350 int vorbis_synthesis_idheader(ogg_packet *op){
Chris@1 351 oggpack_buffer opb;
Chris@1 352 char buffer[6];
Chris@1 353
Chris@1 354 if(op){
Chris@1 355 oggpack_readinit(&opb,op->packet,op->bytes);
Chris@1 356
Chris@1 357 if(!op->b_o_s)
Chris@1 358 return(0); /* Not the initial packet */
Chris@1 359
Chris@1 360 if(oggpack_read(&opb,8) != 1)
Chris@1 361 return 0; /* not an ID header */
Chris@1 362
Chris@1 363 memset(buffer,0,6);
Chris@1 364 _v_readstring(&opb,buffer,6);
Chris@1 365 if(memcmp(buffer,"vorbis",6))
Chris@1 366 return 0; /* not vorbis */
Chris@1 367
Chris@1 368 return 1;
Chris@1 369 }
Chris@1 370
Chris@1 371 return 0;
Chris@1 372 }
Chris@1 373
Chris@1 374 /* The Vorbis header is in three packets; the initial small packet in
Chris@1 375 the first page that identifies basic parameters, a second packet
Chris@1 376 with bitstream comments and a third packet that holds the
Chris@1 377 codebook. */
Chris@1 378
Chris@1 379 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
Chris@1 380 oggpack_buffer opb;
Chris@1 381
Chris@1 382 if(op){
Chris@1 383 oggpack_readinit(&opb,op->packet,op->bytes);
Chris@1 384
Chris@1 385 /* Which of the three types of header is this? */
Chris@1 386 /* Also verify header-ness, vorbis */
Chris@1 387 {
Chris@1 388 char buffer[6];
Chris@1 389 int packtype=oggpack_read(&opb,8);
Chris@1 390 memset(buffer,0,6);
Chris@1 391 _v_readstring(&opb,buffer,6);
Chris@1 392 if(memcmp(buffer,"vorbis",6)){
Chris@1 393 /* not a vorbis header */
Chris@1 394 return(OV_ENOTVORBIS);
Chris@1 395 }
Chris@1 396 switch(packtype){
Chris@1 397 case 0x01: /* least significant *bit* is read first */
Chris@1 398 if(!op->b_o_s){
Chris@1 399 /* Not the initial packet */
Chris@1 400 return(OV_EBADHEADER);
Chris@1 401 }
Chris@1 402 if(vi->rate!=0){
Chris@1 403 /* previously initialized info header */
Chris@1 404 return(OV_EBADHEADER);
Chris@1 405 }
Chris@1 406
Chris@1 407 return(_vorbis_unpack_info(vi,&opb));
Chris@1 408
Chris@1 409 case 0x03: /* least significant *bit* is read first */
Chris@1 410 if(vi->rate==0){
Chris@1 411 /* um... we didn't get the initial header */
Chris@1 412 return(OV_EBADHEADER);
Chris@1 413 }
Chris@1 414
Chris@1 415 return(_vorbis_unpack_comment(vc,&opb));
Chris@1 416
Chris@1 417 case 0x05: /* least significant *bit* is read first */
Chris@1 418 if(vi->rate==0 || vc->vendor==NULL){
Chris@1 419 /* um... we didn;t get the initial header or comments yet */
Chris@1 420 return(OV_EBADHEADER);
Chris@1 421 }
Chris@1 422
Chris@1 423 return(_vorbis_unpack_books(vi,&opb));
Chris@1 424
Chris@1 425 default:
Chris@1 426 /* Not a valid vorbis header type */
Chris@1 427 return(OV_EBADHEADER);
Chris@1 428 break;
Chris@1 429 }
Chris@1 430 }
Chris@1 431 }
Chris@1 432 return(OV_EBADHEADER);
Chris@1 433 }
Chris@1 434
Chris@1 435 /* pack side **********************************************************/
Chris@1 436
Chris@1 437 static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
Chris@1 438 codec_setup_info *ci=vi->codec_setup;
Chris@1 439 if(!ci)return(OV_EFAULT);
Chris@1 440
Chris@1 441 /* preamble */
Chris@1 442 oggpack_write(opb,0x01,8);
Chris@1 443 _v_writestring(opb,"vorbis", 6);
Chris@1 444
Chris@1 445 /* basic information about the stream */
Chris@1 446 oggpack_write(opb,0x00,32);
Chris@1 447 oggpack_write(opb,vi->channels,8);
Chris@1 448 oggpack_write(opb,vi->rate,32);
Chris@1 449
Chris@1 450 oggpack_write(opb,vi->bitrate_upper,32);
Chris@1 451 oggpack_write(opb,vi->bitrate_nominal,32);
Chris@1 452 oggpack_write(opb,vi->bitrate_lower,32);
Chris@1 453
Chris@1 454 oggpack_write(opb,ilog2(ci->blocksizes[0]),4);
Chris@1 455 oggpack_write(opb,ilog2(ci->blocksizes[1]),4);
Chris@1 456 oggpack_write(opb,1,1);
Chris@1 457
Chris@1 458 return(0);
Chris@1 459 }
Chris@1 460
Chris@1 461 static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){
Chris@1 462 int bytes = strlen(ENCODE_VENDOR_STRING);
Chris@1 463
Chris@1 464 /* preamble */
Chris@1 465 oggpack_write(opb,0x03,8);
Chris@1 466 _v_writestring(opb,"vorbis", 6);
Chris@1 467
Chris@1 468 /* vendor */
Chris@1 469 oggpack_write(opb,bytes,32);
Chris@1 470 _v_writestring(opb,ENCODE_VENDOR_STRING, bytes);
Chris@1 471
Chris@1 472 /* comments */
Chris@1 473
Chris@1 474 oggpack_write(opb,vc->comments,32);
Chris@1 475 if(vc->comments){
Chris@1 476 int i;
Chris@1 477 for(i=0;i<vc->comments;i++){
Chris@1 478 if(vc->user_comments[i]){
Chris@1 479 oggpack_write(opb,vc->comment_lengths[i],32);
Chris@1 480 _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
Chris@1 481 }else{
Chris@1 482 oggpack_write(opb,0,32);
Chris@1 483 }
Chris@1 484 }
Chris@1 485 }
Chris@1 486 oggpack_write(opb,1,1);
Chris@1 487
Chris@1 488 return(0);
Chris@1 489 }
Chris@1 490
Chris@1 491 static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
Chris@1 492 codec_setup_info *ci=vi->codec_setup;
Chris@1 493 int i;
Chris@1 494 if(!ci)return(OV_EFAULT);
Chris@1 495
Chris@1 496 oggpack_write(opb,0x05,8);
Chris@1 497 _v_writestring(opb,"vorbis", 6);
Chris@1 498
Chris@1 499 /* books */
Chris@1 500 oggpack_write(opb,ci->books-1,8);
Chris@1 501 for(i=0;i<ci->books;i++)
Chris@1 502 if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out;
Chris@1 503
Chris@1 504 /* times; hook placeholders */
Chris@1 505 oggpack_write(opb,0,6);
Chris@1 506 oggpack_write(opb,0,16);
Chris@1 507
Chris@1 508 /* floors */
Chris@1 509 oggpack_write(opb,ci->floors-1,6);
Chris@1 510 for(i=0;i<ci->floors;i++){
Chris@1 511 oggpack_write(opb,ci->floor_type[i],16);
Chris@1 512 if(_floor_P[ci->floor_type[i]]->pack)
Chris@1 513 _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb);
Chris@1 514 else
Chris@1 515 goto err_out;
Chris@1 516 }
Chris@1 517
Chris@1 518 /* residues */
Chris@1 519 oggpack_write(opb,ci->residues-1,6);
Chris@1 520 for(i=0;i<ci->residues;i++){
Chris@1 521 oggpack_write(opb,ci->residue_type[i],16);
Chris@1 522 _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb);
Chris@1 523 }
Chris@1 524
Chris@1 525 /* maps */
Chris@1 526 oggpack_write(opb,ci->maps-1,6);
Chris@1 527 for(i=0;i<ci->maps;i++){
Chris@1 528 oggpack_write(opb,ci->map_type[i],16);
Chris@1 529 _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb);
Chris@1 530 }
Chris@1 531
Chris@1 532 /* modes */
Chris@1 533 oggpack_write(opb,ci->modes-1,6);
Chris@1 534 for(i=0;i<ci->modes;i++){
Chris@1 535 oggpack_write(opb,ci->mode_param[i]->blockflag,1);
Chris@1 536 oggpack_write(opb,ci->mode_param[i]->windowtype,16);
Chris@1 537 oggpack_write(opb,ci->mode_param[i]->transformtype,16);
Chris@1 538 oggpack_write(opb,ci->mode_param[i]->mapping,8);
Chris@1 539 }
Chris@1 540 oggpack_write(opb,1,1);
Chris@1 541
Chris@1 542 return(0);
Chris@1 543 err_out:
Chris@1 544 return(-1);
Chris@1 545 }
Chris@1 546
Chris@1 547 int vorbis_commentheader_out(vorbis_comment *vc,
Chris@1 548 ogg_packet *op){
Chris@1 549
Chris@1 550 oggpack_buffer opb;
Chris@1 551
Chris@1 552 oggpack_writeinit(&opb);
Chris@1 553 if(_vorbis_pack_comment(&opb,vc)){
Chris@1 554 oggpack_writeclear(&opb);
Chris@1 555 return OV_EIMPL;
Chris@1 556 }
Chris@1 557
Chris@1 558 op->packet = _ogg_malloc(oggpack_bytes(&opb));
Chris@1 559 memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));
Chris@1 560
Chris@1 561 op->bytes=oggpack_bytes(&opb);
Chris@1 562 op->b_o_s=0;
Chris@1 563 op->e_o_s=0;
Chris@1 564 op->granulepos=0;
Chris@1 565 op->packetno=1;
Chris@1 566
Chris@1 567 oggpack_writeclear(&opb);
Chris@1 568 return 0;
Chris@1 569 }
Chris@1 570
Chris@1 571 int vorbis_analysis_headerout(vorbis_dsp_state *v,
Chris@1 572 vorbis_comment *vc,
Chris@1 573 ogg_packet *op,
Chris@1 574 ogg_packet *op_comm,
Chris@1 575 ogg_packet *op_code){
Chris@1 576 int ret=OV_EIMPL;
Chris@1 577 vorbis_info *vi=v->vi;
Chris@1 578 oggpack_buffer opb;
Chris@1 579 private_state *b=v->backend_state;
Chris@1 580
Chris@1 581 if(!b){
Chris@1 582 ret=OV_EFAULT;
Chris@1 583 goto err_out;
Chris@1 584 }
Chris@1 585
Chris@1 586 /* first header packet **********************************************/
Chris@1 587
Chris@1 588 oggpack_writeinit(&opb);
Chris@1 589 if(_vorbis_pack_info(&opb,vi))goto err_out;
Chris@1 590
Chris@1 591 /* build the packet */
Chris@1 592 if(b->header)_ogg_free(b->header);
Chris@1 593 b->header=_ogg_malloc(oggpack_bytes(&opb));
Chris@1 594 memcpy(b->header,opb.buffer,oggpack_bytes(&opb));
Chris@1 595 op->packet=b->header;
Chris@1 596 op->bytes=oggpack_bytes(&opb);
Chris@1 597 op->b_o_s=1;
Chris@1 598 op->e_o_s=0;
Chris@1 599 op->granulepos=0;
Chris@1 600 op->packetno=0;
Chris@1 601
Chris@1 602 /* second header packet (comments) **********************************/
Chris@1 603
Chris@1 604 oggpack_reset(&opb);
Chris@1 605 if(_vorbis_pack_comment(&opb,vc))goto err_out;
Chris@1 606
Chris@1 607 if(b->header1)_ogg_free(b->header1);
Chris@1 608 b->header1=_ogg_malloc(oggpack_bytes(&opb));
Chris@1 609 memcpy(b->header1,opb.buffer,oggpack_bytes(&opb));
Chris@1 610 op_comm->packet=b->header1;
Chris@1 611 op_comm->bytes=oggpack_bytes(&opb);
Chris@1 612 op_comm->b_o_s=0;
Chris@1 613 op_comm->e_o_s=0;
Chris@1 614 op_comm->granulepos=0;
Chris@1 615 op_comm->packetno=1;
Chris@1 616
Chris@1 617 /* third header packet (modes/codebooks) ****************************/
Chris@1 618
Chris@1 619 oggpack_reset(&opb);
Chris@1 620 if(_vorbis_pack_books(&opb,vi))goto err_out;
Chris@1 621
Chris@1 622 if(b->header2)_ogg_free(b->header2);
Chris@1 623 b->header2=_ogg_malloc(oggpack_bytes(&opb));
Chris@1 624 memcpy(b->header2,opb.buffer,oggpack_bytes(&opb));
Chris@1 625 op_code->packet=b->header2;
Chris@1 626 op_code->bytes=oggpack_bytes(&opb);
Chris@1 627 op_code->b_o_s=0;
Chris@1 628 op_code->e_o_s=0;
Chris@1 629 op_code->granulepos=0;
Chris@1 630 op_code->packetno=2;
Chris@1 631
Chris@1 632 oggpack_writeclear(&opb);
Chris@1 633 return(0);
Chris@1 634 err_out:
Chris@1 635 memset(op,0,sizeof(*op));
Chris@1 636 memset(op_comm,0,sizeof(*op_comm));
Chris@1 637 memset(op_code,0,sizeof(*op_code));
Chris@1 638
Chris@1 639 if(b){
Chris@1 640 oggpack_writeclear(&opb);
Chris@1 641 if(b->header)_ogg_free(b->header);
Chris@1 642 if(b->header1)_ogg_free(b->header1);
Chris@1 643 if(b->header2)_ogg_free(b->header2);
Chris@1 644 b->header=NULL;
Chris@1 645 b->header1=NULL;
Chris@1 646 b->header2=NULL;
Chris@1 647 }
Chris@1 648 return(ret);
Chris@1 649 }
Chris@1 650
Chris@1 651 double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){
Chris@1 652 if(granulepos == -1) return -1;
Chris@1 653
Chris@1 654 /* We're not guaranteed a 64 bit unsigned type everywhere, so we
Chris@1 655 have to put the unsigned granpo in a signed type. */
Chris@1 656 if(granulepos>=0){
Chris@1 657 return((double)granulepos/v->vi->rate);
Chris@1 658 }else{
Chris@1 659 ogg_int64_t granuleoff=0xffffffff;
Chris@1 660 granuleoff<<=31;
Chris@1 661 granuleoff|=0x7ffffffff;
Chris@1 662 return(((double)granulepos+2+granuleoff+granuleoff)/v->vi->rate);
Chris@1 663 }
Chris@1 664 }
Chris@1 665
Chris@1 666 const char *vorbis_version_string(void){
Chris@1 667 return GENERAL_VENDOR_STRING;
Chris@1 668 }