media/libtremor/lib/tremor_block.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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-2002 *
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: PCM data vector blocking, windowing and dis/reassembly
michael@0 15
michael@0 16 ********************************************************************/
michael@0 17
michael@0 18 #include <stdio.h>
michael@0 19 #include <stdlib.h>
michael@0 20 #include <string.h>
michael@0 21 #include <ogg/ogg.h>
michael@0 22 #include "ivorbiscodec.h"
michael@0 23 #include "codec_internal.h"
michael@0 24
michael@0 25 #include "window.h"
michael@0 26 #include "registry.h"
michael@0 27 #include "misc.h"
michael@0 28
michael@0 29 static int ilog(unsigned int v){
michael@0 30 int ret=0;
michael@0 31 if(v)--v;
michael@0 32 while(v){
michael@0 33 ret++;
michael@0 34 v>>=1;
michael@0 35 }
michael@0 36 return(ret);
michael@0 37 }
michael@0 38
michael@0 39 /* pcm accumulator examples (not exhaustive):
michael@0 40
michael@0 41 <-------------- lW ---------------->
michael@0 42 <--------------- W ---------------->
michael@0 43 : .....|..... _______________ |
michael@0 44 : .''' | '''_--- | |\ |
michael@0 45 :.....''' |_____--- '''......| | \_______|
michael@0 46 :.................|__________________|_______|__|______|
michael@0 47 |<------ Sl ------>| > Sr < |endW
michael@0 48 |beginSl |endSl | |endSr
michael@0 49 |beginW |endlW |beginSr
michael@0 50
michael@0 51
michael@0 52 |< lW >|
michael@0 53 <--------------- W ---------------->
michael@0 54 | | .. ______________ |
michael@0 55 | | ' `/ | ---_ |
michael@0 56 |___.'___/`. | ---_____|
michael@0 57 |_______|__|_______|_________________|
michael@0 58 | >|Sl|< |<------ Sr ----->|endW
michael@0 59 | | |endSl |beginSr |endSr
michael@0 60 |beginW | |endlW
michael@0 61 mult[0] |beginSl mult[n]
michael@0 62
michael@0 63 <-------------- lW ----------------->
michael@0 64 |<--W-->|
michael@0 65 : .............. ___ | |
michael@0 66 : .''' |`/ \ | |
michael@0 67 :.....''' |/`....\|...|
michael@0 68 :.........................|___|___|___|
michael@0 69 |Sl |Sr |endW
michael@0 70 | | |endSr
michael@0 71 | |beginSr
michael@0 72 | |endSl
michael@0 73 |beginSl
michael@0 74 |beginW
michael@0 75 */
michael@0 76
michael@0 77 /* block abstraction setup *********************************************/
michael@0 78
michael@0 79 #ifndef WORD_ALIGN
michael@0 80 #define WORD_ALIGN 8
michael@0 81 #endif
michael@0 82
michael@0 83 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
michael@0 84 memset(vb,0,sizeof(*vb));
michael@0 85 vb->vd=v;
michael@0 86 vb->localalloc=0;
michael@0 87 vb->localstore=NULL;
michael@0 88
michael@0 89 return(0);
michael@0 90 }
michael@0 91
michael@0 92 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
michael@0 93 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
michael@0 94 if(bytes+vb->localtop>vb->localalloc){
michael@0 95 /* can't just _ogg_realloc... there are outstanding pointers */
michael@0 96 if(vb->localstore){
michael@0 97 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
michael@0 98 vb->totaluse+=vb->localtop;
michael@0 99 link->next=vb->reap;
michael@0 100 link->ptr=vb->localstore;
michael@0 101 vb->reap=link;
michael@0 102 }
michael@0 103 /* highly conservative */
michael@0 104 vb->localalloc=bytes;
michael@0 105 vb->localstore=_ogg_malloc(vb->localalloc);
michael@0 106 vb->localtop=0;
michael@0 107 }
michael@0 108 {
michael@0 109 void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
michael@0 110 vb->localtop+=bytes;
michael@0 111 return ret;
michael@0 112 }
michael@0 113 }
michael@0 114
michael@0 115 /* reap the chain, pull the ripcord */
michael@0 116 void _vorbis_block_ripcord(vorbis_block *vb){
michael@0 117 /* reap the chain */
michael@0 118 struct alloc_chain *reap=vb->reap;
michael@0 119 while(reap){
michael@0 120 struct alloc_chain *next=reap->next;
michael@0 121 _ogg_free(reap->ptr);
michael@0 122 memset(reap,0,sizeof(*reap));
michael@0 123 _ogg_free(reap);
michael@0 124 reap=next;
michael@0 125 }
michael@0 126 /* consolidate storage */
michael@0 127 if(vb->totaluse){
michael@0 128 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
michael@0 129 vb->localalloc+=vb->totaluse;
michael@0 130 vb->totaluse=0;
michael@0 131 }
michael@0 132
michael@0 133 /* pull the ripcord */
michael@0 134 vb->localtop=0;
michael@0 135 vb->reap=NULL;
michael@0 136 }
michael@0 137
michael@0 138 int vorbis_block_clear(vorbis_block *vb){
michael@0 139 _vorbis_block_ripcord(vb);
michael@0 140 if(vb->localstore)_ogg_free(vb->localstore);
michael@0 141
michael@0 142 memset(vb,0,sizeof(*vb));
michael@0 143 return(0);
michael@0 144 }
michael@0 145
michael@0 146 static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
michael@0 147 int i;
michael@0 148 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
michael@0 149 private_state *b=NULL;
michael@0 150
michael@0 151 if(ci==NULL) return 1;
michael@0 152
michael@0 153 memset(v,0,sizeof(*v));
michael@0 154 b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
michael@0 155
michael@0 156 v->vi=vi;
michael@0 157 b->modebits=ilog(ci->modes);
michael@0 158
michael@0 159 /* Vorbis I uses only window type 0 */
michael@0 160 b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
michael@0 161 b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
michael@0 162
michael@0 163 /* finish the codebooks */
michael@0 164 if(!ci->fullbooks){
michael@0 165 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
michael@0 166 for(i=0;i<ci->books;i++){
michael@0 167 if(ci->book_param[i]==NULL)
michael@0 168 goto abort_books;
michael@0 169 if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
michael@0 170 goto abort_books;
michael@0 171 /* decode codebooks are now standalone after init */
michael@0 172 vorbis_staticbook_destroy(ci->book_param[i]);
michael@0 173 ci->book_param[i]=NULL;
michael@0 174 }
michael@0 175 }
michael@0 176
michael@0 177 v->pcm_storage=ci->blocksizes[1];
michael@0 178 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
michael@0 179 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
michael@0 180 for(i=0;i<vi->channels;i++)
michael@0 181 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
michael@0 182
michael@0 183 /* all 1 (large block) or 0 (small block) */
michael@0 184 /* explicitly set for the sake of clarity */
michael@0 185 v->lW=0; /* previous window size */
michael@0 186 v->W=0; /* current window size */
michael@0 187
michael@0 188 /* initialize all the mapping/backend lookups */
michael@0 189 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
michael@0 190 for(i=0;i<ci->modes;i++){
michael@0 191 int mapnum=ci->mode_param[i]->mapping;
michael@0 192 int maptype=ci->map_type[mapnum];
michael@0 193 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
michael@0 194 ci->map_param[mapnum]);
michael@0 195 }
michael@0 196 return 0;
michael@0 197 abort_books:
michael@0 198 for(i=0;i<ci->books;i++){
michael@0 199 if(ci->book_param[i]!=NULL){
michael@0 200 vorbis_staticbook_destroy(ci->book_param[i]);
michael@0 201 ci->book_param[i]=NULL;
michael@0 202 }
michael@0 203 }
michael@0 204 vorbis_dsp_clear(v);
michael@0 205 return -1;
michael@0 206 }
michael@0 207
michael@0 208 int vorbis_synthesis_restart(vorbis_dsp_state *v){
michael@0 209 vorbis_info *vi=v->vi;
michael@0 210 codec_setup_info *ci;
michael@0 211
michael@0 212 if(!v->backend_state)return -1;
michael@0 213 if(!vi)return -1;
michael@0 214 ci=vi->codec_setup;
michael@0 215 if(!ci)return -1;
michael@0 216
michael@0 217 v->centerW=ci->blocksizes[1]/2;
michael@0 218 v->pcm_current=v->centerW;
michael@0 219
michael@0 220 v->pcm_returned=-1;
michael@0 221 v->granulepos=-1;
michael@0 222 v->sequence=-1;
michael@0 223 ((private_state *)(v->backend_state))->sample_count=-1;
michael@0 224
michael@0 225 return(0);
michael@0 226 }
michael@0 227
michael@0 228 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
michael@0 229 if(_vds_init(v,vi))return 1;
michael@0 230 vorbis_synthesis_restart(v);
michael@0 231
michael@0 232 return 0;
michael@0 233 }
michael@0 234
michael@0 235 void vorbis_dsp_clear(vorbis_dsp_state *v){
michael@0 236 int i;
michael@0 237 if(v){
michael@0 238 vorbis_info *vi=v->vi;
michael@0 239 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
michael@0 240 private_state *b=(private_state *)v->backend_state;
michael@0 241
michael@0 242 if(v->pcm){
michael@0 243 for(i=0;i<vi->channels;i++)
michael@0 244 if(v->pcm[i])_ogg_free(v->pcm[i]);
michael@0 245 _ogg_free(v->pcm);
michael@0 246 if(v->pcmret)_ogg_free(v->pcmret);
michael@0 247 }
michael@0 248
michael@0 249 /* free mode lookups; these are actually vorbis_look_mapping structs */
michael@0 250 if(ci){
michael@0 251 for(i=0;i<ci->modes;i++){
michael@0 252 int mapnum=ci->mode_param[i]->mapping;
michael@0 253 int maptype=ci->map_type[mapnum];
michael@0 254 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
michael@0 255 }
michael@0 256 }
michael@0 257
michael@0 258 if(b){
michael@0 259 if(b->mode)_ogg_free(b->mode);
michael@0 260 _ogg_free(b);
michael@0 261 }
michael@0 262
michael@0 263 memset(v,0,sizeof(*v));
michael@0 264 }
michael@0 265 }
michael@0 266
michael@0 267 /* Unlike in analysis, the window is only partially applied for each
michael@0 268 block. The time domain envelope is not yet handled at the point of
michael@0 269 calling (as it relies on the previous block). */
michael@0 270
michael@0 271 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
michael@0 272 vorbis_info *vi=v->vi;
michael@0 273 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
michael@0 274 private_state *b=v->backend_state;
michael@0 275 int i,j;
michael@0 276
michael@0 277 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
michael@0 278
michael@0 279 v->lW=v->W;
michael@0 280 v->W=vb->W;
michael@0 281 v->nW=-1;
michael@0 282
michael@0 283 if((v->sequence==-1)||
michael@0 284 (v->sequence+1 != vb->sequence)){
michael@0 285 v->granulepos=-1; /* out of sequence; lose count */
michael@0 286 b->sample_count=-1;
michael@0 287 }
michael@0 288
michael@0 289 v->sequence=vb->sequence;
michael@0 290
michael@0 291 if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
michael@0 292 was called on block */
michael@0 293 int n=ci->blocksizes[v->W]/2;
michael@0 294 int n0=ci->blocksizes[0]/2;
michael@0 295 int n1=ci->blocksizes[1]/2;
michael@0 296
michael@0 297 int thisCenter;
michael@0 298 int prevCenter;
michael@0 299
michael@0 300 if(v->centerW){
michael@0 301 thisCenter=n1;
michael@0 302 prevCenter=0;
michael@0 303 }else{
michael@0 304 thisCenter=0;
michael@0 305 prevCenter=n1;
michael@0 306 }
michael@0 307
michael@0 308 /* v->pcm is now used like a two-stage double buffer. We don't want
michael@0 309 to have to constantly shift *or* adjust memory usage. Don't
michael@0 310 accept a new block until the old is shifted out */
michael@0 311
michael@0 312 /* overlap/add PCM */
michael@0 313
michael@0 314 for(j=0;j<vi->channels;j++){
michael@0 315 /* the overlap/add section */
michael@0 316 if(v->lW){
michael@0 317 if(v->W){
michael@0 318 /* large/large */
michael@0 319 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
michael@0 320 ogg_int32_t *p=vb->pcm[j];
michael@0 321 for(i=0;i<n1;i++)
michael@0 322 pcm[i]+=p[i];
michael@0 323 }else{
michael@0 324 /* large/small */
michael@0 325 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
michael@0 326 ogg_int32_t *p=vb->pcm[j];
michael@0 327 for(i=0;i<n0;i++)
michael@0 328 pcm[i]+=p[i];
michael@0 329 }
michael@0 330 }else{
michael@0 331 if(v->W){
michael@0 332 /* small/large */
michael@0 333 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
michael@0 334 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
michael@0 335 for(i=0;i<n0;i++)
michael@0 336 pcm[i]+=p[i];
michael@0 337 for(;i<n1/2+n0/2;i++)
michael@0 338 pcm[i]=p[i];
michael@0 339 }else{
michael@0 340 /* small/small */
michael@0 341 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
michael@0 342 ogg_int32_t *p=vb->pcm[j];
michael@0 343 for(i=0;i<n0;i++)
michael@0 344 pcm[i]+=p[i];
michael@0 345 }
michael@0 346 }
michael@0 347
michael@0 348 /* the copy section */
michael@0 349 {
michael@0 350 ogg_int32_t *pcm=v->pcm[j]+thisCenter;
michael@0 351 ogg_int32_t *p=vb->pcm[j]+n;
michael@0 352 for(i=0;i<n;i++)
michael@0 353 pcm[i]=p[i];
michael@0 354 }
michael@0 355 }
michael@0 356
michael@0 357 if(v->centerW)
michael@0 358 v->centerW=0;
michael@0 359 else
michael@0 360 v->centerW=n1;
michael@0 361
michael@0 362 /* deal with initial packet state; we do this using the explicit
michael@0 363 pcm_returned==-1 flag otherwise we're sensitive to first block
michael@0 364 being short or long */
michael@0 365
michael@0 366 if(v->pcm_returned==-1){
michael@0 367 v->pcm_returned=thisCenter;
michael@0 368 v->pcm_current=thisCenter;
michael@0 369 }else{
michael@0 370 v->pcm_returned=prevCenter;
michael@0 371 v->pcm_current=prevCenter+
michael@0 372 ci->blocksizes[v->lW]/4+
michael@0 373 ci->blocksizes[v->W]/4;
michael@0 374 }
michael@0 375
michael@0 376 }
michael@0 377
michael@0 378 /* track the frame number... This is for convenience, but also
michael@0 379 making sure our last packet doesn't end with added padding. If
michael@0 380 the last packet is partial, the number of samples we'll have to
michael@0 381 return will be past the vb->granulepos.
michael@0 382
michael@0 383 This is not foolproof! It will be confused if we begin
michael@0 384 decoding at the last page after a seek or hole. In that case,
michael@0 385 we don't have a starting point to judge where the last frame
michael@0 386 is. For this reason, vorbisfile will always try to make sure
michael@0 387 it reads the last two marked pages in proper sequence */
michael@0 388
michael@0 389 if(b->sample_count==-1){
michael@0 390 b->sample_count=0;
michael@0 391 }else{
michael@0 392 b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
michael@0 393 }
michael@0 394
michael@0 395 if(v->granulepos==-1){
michael@0 396 if(vb->granulepos!=-1){ /* only set if we have a position to set to */
michael@0 397
michael@0 398 v->granulepos=vb->granulepos;
michael@0 399
michael@0 400 /* is this a short page? */
michael@0 401 if(b->sample_count>v->granulepos){
michael@0 402 /* corner case; if this is both the first and last audio page,
michael@0 403 then spec says the end is cut, not beginning */
michael@0 404 long extra=b->sample_count-vb->granulepos;
michael@0 405
michael@0 406 /* we use ogg_int64_t for granule positions because a
michael@0 407 uint64 isn't universally available. Unfortunately,
michael@0 408 that means granposes can be 'negative' and result in
michael@0 409 extra being negative */
michael@0 410 if(extra<0)
michael@0 411 extra=0;
michael@0 412
michael@0 413 if(vb->eofflag){
michael@0 414 /* trim the end */
michael@0 415 /* no preceeding granulepos; assume we started at zero (we'd
michael@0 416 have to in a short single-page stream) */
michael@0 417 /* granulepos could be -1 due to a seek, but that would result
michael@0 418 in a long coun`t, not short count */
michael@0 419
michael@0 420 /* Guard against corrupt/malicious frames that set EOP and
michael@0 421 a backdated granpos; don't rewind more samples than we
michael@0 422 actually have */
michael@0 423 if(extra > v->pcm_current - v->pcm_returned)
michael@0 424 extra = v->pcm_current - v->pcm_returned;
michael@0 425
michael@0 426 v->pcm_current-=extra;
michael@0 427 }else{
michael@0 428 /* trim the beginning */
michael@0 429 v->pcm_returned+=extra;
michael@0 430 if(v->pcm_returned>v->pcm_current)
michael@0 431 v->pcm_returned=v->pcm_current;
michael@0 432 }
michael@0 433
michael@0 434 }
michael@0 435
michael@0 436 }
michael@0 437 }else{
michael@0 438 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
michael@0 439 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
michael@0 440
michael@0 441 if(v->granulepos>vb->granulepos){
michael@0 442 long extra=v->granulepos-vb->granulepos;
michael@0 443
michael@0 444 if(extra)
michael@0 445 if(vb->eofflag){
michael@0 446 /* partial last frame. Strip the extra samples off */
michael@0 447
michael@0 448 /* Guard against corrupt/malicious frames that set EOP and
michael@0 449 a backdated granpos; don't rewind more samples than we
michael@0 450 actually have */
michael@0 451 if(extra > v->pcm_current - v->pcm_returned)
michael@0 452 extra = v->pcm_current - v->pcm_returned;
michael@0 453
michael@0 454 /* we use ogg_int64_t for granule positions because a
michael@0 455 uint64 isn't universally available. Unfortunately,
michael@0 456 that means granposes can be 'negative' and result in
michael@0 457 extra being negative */
michael@0 458 if(extra<0)
michael@0 459 extra=0;
michael@0 460
michael@0 461 v->pcm_current-=extra;
michael@0 462
michael@0 463 } /* else {Shouldn't happen *unless* the bitstream is out of
michael@0 464 spec. Either way, believe the bitstream } */
michael@0 465 } /* else {Shouldn't happen *unless* the bitstream is out of
michael@0 466 spec. Either way, believe the bitstream } */
michael@0 467 v->granulepos=vb->granulepos;
michael@0 468 }
michael@0 469 }
michael@0 470
michael@0 471 /* Update, cleanup */
michael@0 472
michael@0 473 if(vb->eofflag)v->eofflag=1;
michael@0 474 return(0);
michael@0 475 }
michael@0 476
michael@0 477 /* pcm==NULL indicates we just want the pending samples, no more */
michael@0 478 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
michael@0 479 vorbis_info *vi=v->vi;
michael@0 480 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
michael@0 481 if(pcm){
michael@0 482 int i;
michael@0 483 for(i=0;i<vi->channels;i++)
michael@0 484 v->pcmret[i]=v->pcm[i]+v->pcm_returned;
michael@0 485 *pcm=v->pcmret;
michael@0 486 }
michael@0 487 return(v->pcm_current-v->pcm_returned);
michael@0 488 }
michael@0 489 return(0);
michael@0 490 }
michael@0 491
michael@0 492 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
michael@0 493 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
michael@0 494 v->pcm_returned+=bytes;
michael@0 495 return(0);
michael@0 496 }
michael@0 497

mercurial