Coverage Report

Created: 2026-07-24 07:09

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