Coverage Report

Created: 2026-08-13 06:25

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
7.82k
static int ilog(unsigned int v){
30
7.82k
  int ret=0;
31
7.82k
  if(v)--v;
32
8.64k
  while(v){
33
821
    ret++;
34
821
    v>>=1;
35
821
  }
36
7.82k
  return(ret);
37
7.82k
}
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
9.26M
#define WORD_ALIGN 8
81
#endif
82
83
7.71k
int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
84
7.71k
  memset(vb,0,sizeof(*vb));
85
7.71k
  vb->vd=v;
86
7.71k
  vb->localalloc=0;
87
7.71k
  vb->localstore=NULL;
88
  
89
7.71k
  return(0);
90
7.71k
}
91
92
4.63M
void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
93
4.63M
  bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
94
4.63M
  if(bytes+vb->localtop>vb->localalloc){
95
    /* can't just _ogg_realloc... there are outstanding pointers */
96
383k
    if(vb->localstore){
97
377k
      struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
98
377k
      vb->totaluse+=vb->localtop;
99
377k
      link->next=vb->reap;
100
377k
      link->ptr=vb->localstore;
101
377k
      vb->reap=link;
102
377k
    }
103
    /* highly conservative */
104
383k
    vb->localalloc=bytes;
105
383k
    vb->localstore=_ogg_malloc(vb->localalloc);
106
383k
    vb->localtop=0;
107
383k
  }
108
4.63M
  {
109
4.63M
    void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
110
4.63M
    vb->localtop+=bytes;
111
4.63M
    return ret;
112
4.63M
  }
113
4.63M
}
114
115
/* reap the chain, pull the ripcord */
116
123k
void _vorbis_block_ripcord(vorbis_block *vb){
117
  /* reap the chain */
118
123k
  struct alloc_chain *reap=vb->reap;
119
501k
  while(reap){
120
377k
    struct alloc_chain *next=reap->next;
121
377k
    _ogg_free(reap->ptr);
122
377k
    memset(reap,0,sizeof(*reap));
123
377k
    _ogg_free(reap);
124
377k
    reap=next;
125
377k
  }
126
  /* consolidate storage */
127
123k
  if(vb->totaluse){
128
6.54k
    vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
129
6.54k
    vb->localalloc+=vb->totaluse;
130
6.54k
    vb->totaluse=0;
131
6.54k
  }
132
133
  /* pull the ripcord */
134
123k
  vb->localtop=0;
135
123k
  vb->reap=NULL;
136
123k
}
137
138
10.3k
int vorbis_block_clear(vorbis_block *vb){
139
10.3k
  _vorbis_block_ripcord(vb);
140
10.3k
  if(vb->localstore)_ogg_free(vb->localstore);
141
142
10.3k
  memset(vb,0,sizeof(*vb));
143
10.3k
  return(0);
144
10.3k
}
145
146
7.82k
static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
147
7.82k
  int i;
148
7.82k
  codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
149
7.82k
  private_state *b=NULL;
150
151
7.82k
  if(ci==NULL) return 1;
152
153
7.82k
  memset(v,0,sizeof(*v));
154
7.82k
  b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
155
156
7.82k
  v->vi=vi;
157
7.82k
  b->modebits=ilog(ci->modes);
158
159
  /* Vorbis I uses only window type 0 */
160
7.82k
  b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
161
7.82k
  b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
162
163
  /* finish the codebooks */
164
7.82k
  if(!ci->fullbooks){
165
7.82k
    ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
166
20.1k
    for(i=0;i<ci->books;i++){
167
12.4k
      if(ci->book_param[i]==NULL)
168
0
        goto abort_books;
169
12.4k
      if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
170
109
        goto abort_books;
171
      /* decode codebooks are now standalone after init */
172
12.3k
      vorbis_staticbook_destroy(ci->book_param[i]);
173
12.3k
      ci->book_param[i]=NULL;
174
12.3k
    }
175
7.82k
  }
176
177
7.71k
  v->pcm_storage=ci->blocksizes[1];
178
7.71k
  v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
179
7.71k
  v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
180
578k
  for(i=0;i<vi->channels;i++)
181
570k
    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
7.71k
  v->lW=0; /* previous window size */
186
7.71k
  v->W=0;  /* current window size */
187
188
  /* initialize all the mapping/backend lookups */
189
7.71k
  b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
190
17.1k
  for(i=0;i<ci->modes;i++){
191
9.44k
    int mapnum=ci->mode_param[i]->mapping;
192
9.44k
    int maptype=ci->map_type[mapnum];
193
9.44k
    b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
194
9.44k
           ci->map_param[mapnum]);
195
9.44k
  }
196
7.71k
  return 0;
197
109
abort_books:
198
2.15k
  for(i=0;i<ci->books;i++){
199
2.04k
    if(ci->book_param[i]!=NULL){
200
1.02k
      vorbis_staticbook_destroy(ci->book_param[i]);
201
1.02k
      ci->book_param[i]=NULL;
202
1.02k
    }
203
2.04k
  }
204
109
  vorbis_dsp_clear(v);
205
109
  return -1;
206
7.82k
}
207
208
7.71k
int vorbis_synthesis_restart(vorbis_dsp_state *v){
209
7.71k
  vorbis_info *vi=v->vi;
210
7.71k
  codec_setup_info *ci;
211
212
7.71k
  if(!v->backend_state)return -1;
213
7.71k
  if(!vi)return -1;
214
7.71k
  ci=vi->codec_setup;
215
7.71k
  if(!ci)return -1;
216
217
7.71k
  v->centerW=ci->blocksizes[1]/2;
218
7.71k
  v->pcm_current=v->centerW;
219
  
220
7.71k
  v->pcm_returned=-1;
221
7.71k
  v->granulepos=-1;
222
7.71k
  v->sequence=-1;
223
7.71k
  ((private_state *)(v->backend_state))->sample_count=-1;
224
225
7.71k
  return(0);
226
7.71k
}
227
228
7.82k
int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
229
7.82k
  if(_vds_init(v,vi))return 1;
230
7.71k
  vorbis_synthesis_restart(v);
231
232
7.71k
  return 0;
233
7.82k
}
234
235
10.4k
void vorbis_dsp_clear(vorbis_dsp_state *v){
236
10.4k
  int i;
237
10.4k
  if(v){
238
10.4k
    vorbis_info *vi=v->vi;
239
10.4k
    codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
240
10.4k
    private_state *b=(private_state *)v->backend_state;
241
242
10.4k
    if(v->pcm){
243
578k
      for(i=0;i<vi->channels;i++)
244
570k
  if(v->pcm[i])_ogg_free(v->pcm[i]);
245
7.71k
      _ogg_free(v->pcm);
246
7.71k
      if(v->pcmret)_ogg_free(v->pcmret);
247
7.71k
    }
248
249
    /* free mode lookups; these are actually vorbis_look_mapping structs */
250
10.4k
    if(ci){
251
17.5k
      for(i=0;i<ci->modes;i++){
252
9.68k
  int mapnum=ci->mode_param[i]->mapping;
253
9.68k
  int maptype=ci->map_type[mapnum];
254
9.68k
  if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
255
9.68k
      }
256
7.82k
    }
257
258
10.4k
    if(b){
259
7.82k
      if(b->mode)_ogg_free(b->mode);    
260
7.82k
      _ogg_free(b);
261
7.82k
    }
262
    
263
10.4k
    memset(v,0,sizeof(*v));
264
10.4k
  }
265
10.4k
}
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
44.4k
int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
272
44.4k
  vorbis_info *vi=v->vi;
273
44.4k
  codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
274
44.4k
  private_state *b=v->backend_state;
275
44.4k
  int i,j;
276
277
44.4k
  if(v->pcm_current>v->pcm_returned  && v->pcm_returned!=-1)return(OV_EINVAL);
278
279
42.7k
  v->lW=v->W;
280
42.7k
  v->W=vb->W;
281
42.7k
  v->nW=-1;
282
283
42.7k
  if((v->sequence==-1)||
284
37.3k
     (v->sequence+1 != vb->sequence)){
285
18.4k
    v->granulepos=-1; /* out of sequence; lose count */
286
18.4k
    b->sample_count=-1;
287
18.4k
  }
288
289
42.7k
  v->sequence=vb->sequence;
290
  
291
42.7k
  if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly 
292
                   was called on block */
293
42.7k
    int n=ci->blocksizes[v->W]/2;
294
42.7k
    int n0=ci->blocksizes[0]/2;
295
42.7k
    int n1=ci->blocksizes[1]/2;
296
    
297
42.7k
    int thisCenter;
298
42.7k
    int prevCenter;
299
    
300
42.7k
    if(v->centerW){
301
22.8k
      thisCenter=n1;
302
22.8k
      prevCenter=0;
303
22.8k
    }else{
304
19.9k
      thisCenter=0;
305
19.9k
      prevCenter=n1;
306
19.9k
    }
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
4.40M
    for(j=0;j<vi->channels;j++){
315
      /* the overlap/add section */
316
4.35M
      if(v->lW){
317
864k
  if(v->W){
318
    /* large/large */
319
858k
    ogg_int32_t *pcm=v->pcm[j]+prevCenter;
320
858k
    ogg_int32_t *p=vb->pcm[j];
321
1.38G
    for(i=0;i<n1;i++)
322
1.38G
      pcm[i]+=p[i];
323
858k
  }else{
324
    /* large/small */
325
6.18k
    ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
326
6.18k
    ogg_int32_t *p=vb->pcm[j];
327
7.90M
    for(i=0;i<n0;i++)
328
7.89M
      pcm[i]+=p[i];
329
6.18k
  }
330
3.49M
      }else{
331
3.49M
  if(v->W){
332
    /* small/large */
333
182k
    ogg_int32_t *pcm=v->pcm[j]+prevCenter;
334
182k
    ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
335
58.2M
    for(i=0;i<n0;i++)
336
58.0M
      pcm[i]+=p[i];
337
52.6M
    for(;i<n1/2+n0/2;i++)
338
52.5M
      pcm[i]=p[i];
339
3.31M
  }else{
340
    /* small/small */
341
3.31M
    ogg_int32_t *pcm=v->pcm[j]+prevCenter;
342
3.31M
    ogg_int32_t *p=vb->pcm[j];
343
1.82G
    for(i=0;i<n0;i++)
344
1.82G
      pcm[i]+=p[i];
345
3.31M
  }
346
3.49M
      }
347
      
348
      /* the copy section */
349
4.35M
      {
350
4.35M
  ogg_int32_t *pcm=v->pcm[j]+thisCenter;
351
4.35M
  ogg_int32_t *p=vb->pcm[j]+n;
352
3.38G
  for(i=0;i<n;i++)
353
3.37G
    pcm[i]=p[i];
354
4.35M
      }
355
4.35M
    }
356
    
357
42.7k
    if(v->centerW)
358
22.8k
      v->centerW=0;
359
19.9k
    else
360
19.9k
      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
42.7k
    if(v->pcm_returned==-1){
367
5.68k
      v->pcm_returned=thisCenter;
368
5.68k
      v->pcm_current=thisCenter;
369
37.0k
    }else{
370
37.0k
      v->pcm_returned=prevCenter;
371
37.0k
      v->pcm_current=prevCenter+
372
37.0k
  ci->blocksizes[v->lW]/4+
373
37.0k
  ci->blocksizes[v->W]/4;
374
37.0k
    }
375
376
42.7k
  }
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
42.7k
  if(b->sample_count==-1){
390
18.4k
    b->sample_count=0;
391
24.2k
  }else{
392
24.2k
    b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
393
24.2k
  }
394
    
395
42.7k
  if(v->granulepos==-1){
396
40.2k
    if(vb->granulepos!=-1){ /* only set if we have a position to set to */
397
      
398
9.28k
      v->granulepos=vb->granulepos;
399
      
400
      /* is this a short page? */
401
9.28k
      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
5.28k
  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
5.28k
        if(extra<0)
411
257
          extra=0;
412
413
5.28k
  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
2.26k
          if(extra > v->pcm_current - v->pcm_returned)
424
1.98k
            extra = v->pcm_current - v->pcm_returned;
425
426
2.26k
    v->pcm_current-=extra;
427
3.02k
  }else{
428
    /* trim the beginning */
429
3.02k
    v->pcm_returned+=extra;
430
3.02k
    if(v->pcm_returned>v->pcm_current)
431
1.09k
      v->pcm_returned=v->pcm_current;
432
3.02k
  }
433
  
434
5.28k
      }
435
      
436
9.28k
    }
437
40.2k
  }else{
438
2.44k
    v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
439
2.44k
    if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
440
      
441
1.88k
      if(v->granulepos>vb->granulepos){
442
1.49k
  long extra=v->granulepos-vb->granulepos;
443
  
444
1.49k
  if(extra)
445
1.49k
    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
1.12k
            if(extra > v->pcm_current - v->pcm_returned)
452
831
              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
1.12k
            if(extra<0)
459
287
              extra=0;
460
461
1.12k
            v->pcm_current-=extra;
462
463
1.12k
    } /* else {Shouldn't happen *unless* the bitstream is out of
464
         spec.  Either way, believe the bitstream } */
465
1.49k
      } /* else {Shouldn't happen *unless* the bitstream is out of
466
     spec.  Either way, believe the bitstream } */
467
1.88k
      v->granulepos=vb->granulepos;
468
1.88k
    }
469
2.44k
  }
470
  
471
  /* Update, cleanup */
472
  
473
42.7k
  if(vb->eofflag)v->eofflag=1;
474
42.7k
  return(0);
475
44.4k
}
476
477
/* pcm==NULL indicates we just want the pending samples, no more */
478
1.67M
int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
479
1.67M
  vorbis_info *vi=v->vi;
480
1.67M
  if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
481
1.56M
    if(pcm){
482
1.52M
      int i;
483
325M
      for(i=0;i<vi->channels;i++)
484
323M
  v->pcmret[i]=v->pcm[i]+v->pcm_returned;
485
1.52M
      *pcm=v->pcmret;
486
1.52M
    }
487
1.56M
    return(v->pcm_current-v->pcm_returned);
488
1.56M
  }
489
113k
  return(0);
490
1.67M
}
491
492
1.52M
int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
493
1.52M
  if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
494
1.52M
  v->pcm_returned+=bytes;
495
1.52M
  return(0);
496
1.52M
}
497