Coverage Report

Created: 2025-10-10 07:02

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