Coverage Report

Created: 2026-09-03 07:05

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