Wed, 31 Dec 2014 06:09:35 +0100
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 |