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
9.94k
static int ilog(unsigned int v){
30
9.94k
  int ret=0;
31
9.94k
  if(v)--v;
32
10.8k
  while(v){
33
872
    ret++;
34
872
    v>>=1;
35
872
  }
36
9.94k
  return(ret);
37
9.94k
}
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
11.3M
#define WORD_ALIGN 8
81
#endif
82
83
9.81k
int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
84
9.81k
  memset(vb,0,sizeof(*vb));
85
9.81k
  vb->vd=v;
86
9.81k
  vb->localalloc=0;
87
9.81k
  vb->localstore=NULL;
88
  
89
9.81k
  return(0);
90
9.81k
}
91
92
5.69M
void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
93
5.69M
  bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
94
5.69M
  if(bytes+vb->localtop>vb->localalloc){
95
    /* can't just _ogg_realloc... there are outstanding pointers */
96
496k
    if(vb->localstore){
97
489k
      struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
98
489k
      vb->totaluse+=vb->localtop;
99
489k
      link->next=vb->reap;
100
489k
      link->ptr=vb->localstore;
101
489k
      vb->reap=link;
102
489k
    }
103
    /* highly conservative */
104
496k
    vb->localalloc=bytes;
105
496k
    vb->localstore=_ogg_malloc(vb->localalloc);
106
496k
    vb->localtop=0;
107
496k
  }
108
5.69M
  {
109
5.69M
    void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
110
5.69M
    vb->localtop+=bytes;
111
5.69M
    return ret;
112
5.69M
  }
113
5.69M
}
114
115
/* reap the chain, pull the ripcord */
116
140k
void _vorbis_block_ripcord(vorbis_block *vb){
117
  /* reap the chain */
118
140k
  struct alloc_chain *reap=vb->reap;
119
630k
  while(reap){
120
489k
    struct alloc_chain *next=reap->next;
121
489k
    _ogg_free(reap->ptr);
122
489k
    memset(reap,0,sizeof(*reap));
123
489k
    _ogg_free(reap);
124
489k
    reap=next;
125
489k
  }
126
  /* consolidate storage */
127
140k
  if(vb->totaluse){
128
7.76k
    vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
129
7.76k
    vb->localalloc+=vb->totaluse;
130
7.76k
    vb->totaluse=0;
131
7.76k
  }
132
133
  /* pull the ripcord */
134
140k
  vb->localtop=0;
135
140k
  vb->reap=NULL;
136
140k
}
137
138
12.2k
int vorbis_block_clear(vorbis_block *vb){
139
12.2k
  _vorbis_block_ripcord(vb);
140
12.2k
  if(vb->localstore)_ogg_free(vb->localstore);
141
142
12.2k
  memset(vb,0,sizeof(*vb));
143
12.2k
  return(0);
144
12.2k
}
145
146
11.1k
static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
147
11.1k
  int i;
148
11.1k
  codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
149
11.1k
  private_state *b=NULL;
150
151
11.1k
  if(ci==NULL) return 1;
152
153
9.94k
  memset(v,0,sizeof(*v));
154
9.94k
  b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
155
156
9.94k
  v->vi=vi;
157
9.94k
  b->modebits=ilog(ci->modes);
158
159
  /* Vorbis I uses only window type 0 */
160
9.94k
  b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
161
9.94k
  b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
162
163
  /* finish the codebooks */
164
9.94k
  if(!ci->fullbooks){
165
9.94k
    ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
166
23.3k
    for(i=0;i<ci->books;i++){
167
13.4k
      if(ci->book_param[i]==NULL)
168
0
        goto abort_books;
169
13.4k
      if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
170
131
        goto abort_books;
171
      /* decode codebooks are now standalone after init */
172
13.3k
      vorbis_staticbook_destroy(ci->book_param[i]);
173
13.3k
      ci->book_param[i]=NULL;
174
13.3k
    }
175
9.94k
  }
176
177
9.81k
  v->pcm_storage=ci->blocksizes[1];
178
9.81k
  v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
179
9.81k
  v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
180
760k
  for(i=0;i<vi->channels;i++)
181
750k
    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.81k
  v->lW=0; /* previous window size */
186
9.81k
  v->W=0;  /* current window size */
187
188
  /* initialize all the mapping/backend lookups */
189
9.81k
  b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
190
20.6k
  for(i=0;i<ci->modes;i++){
191
10.8k
    int mapnum=ci->mode_param[i]->mapping;
192
10.8k
    int maptype=ci->map_type[mapnum];
193
10.8k
    b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
194
10.8k
           ci->map_param[mapnum]);
195
10.8k
  }
196
9.81k
  return 0;
197
131
abort_books:
198
1.80k
  for(i=0;i<ci->books;i++){
199
1.67k
    if(ci->book_param[i]!=NULL){
200
959
      vorbis_staticbook_destroy(ci->book_param[i]);
201
959
      ci->book_param[i]=NULL;
202
959
    }
203
1.67k
  }
204
131
  vorbis_dsp_clear(v);
205
131
  return -1;
206
9.94k
}
207
208
9.81k
int vorbis_synthesis_restart(vorbis_dsp_state *v){
209
9.81k
  vorbis_info *vi=v->vi;
210
9.81k
  codec_setup_info *ci;
211
212
9.81k
  if(!v->backend_state)return -1;
213
9.81k
  if(!vi)return -1;
214
9.81k
  ci=vi->codec_setup;
215
9.81k
  if(!ci)return -1;
216
217
9.81k
  v->centerW=ci->blocksizes[1]/2;
218
9.81k
  v->pcm_current=v->centerW;
219
  
220
9.81k
  v->pcm_returned=-1;
221
9.81k
  v->granulepos=-1;
222
9.81k
  v->sequence=-1;
223
9.81k
  ((private_state *)(v->backend_state))->sample_count=-1;
224
225
9.81k
  return(0);
226
9.81k
}
227
228
11.1k
int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
229
11.1k
  if(_vds_init(v,vi))return 1;
230
9.81k
  vorbis_synthesis_restart(v);
231
232
9.81k
  return 0;
233
11.1k
}
234
235
12.3k
void vorbis_dsp_clear(vorbis_dsp_state *v){
236
12.3k
  int i;
237
12.3k
  if(v){
238
12.3k
    vorbis_info *vi=v->vi;
239
12.3k
    codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
240
12.3k
    private_state *b=(private_state *)v->backend_state;
241
242
12.3k
    if(v->pcm){
243
760k
      for(i=0;i<vi->channels;i++)
244
750k
  if(v->pcm[i])_ogg_free(v->pcm[i]);
245
9.81k
      _ogg_free(v->pcm);
246
9.81k
      if(v->pcmret)_ogg_free(v->pcmret);
247
9.81k
    }
248
249
    /* free mode lookups; these are actually vorbis_look_mapping structs */
250
12.3k
    if(ci){
251
21.1k
      for(i=0;i<ci->modes;i++){
252
11.1k
  int mapnum=ci->mode_param[i]->mapping;
253
11.1k
  int maptype=ci->map_type[mapnum];
254
11.1k
  if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
255
11.1k
      }
256
9.94k
    }
257
258
12.3k
    if(b){
259
9.94k
      if(b->mode)_ogg_free(b->mode);    
260
9.94k
      _ogg_free(b);
261
9.94k
    }
262
    
263
12.3k
    memset(v,0,sizeof(*v));
264
12.3k
  }
265
12.3k
}
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
55.8k
int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
272
55.8k
  vorbis_info *vi=v->vi;
273
55.8k
  codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
274
55.8k
  private_state *b=v->backend_state;
275
55.8k
  int i,j;
276
277
55.8k
  if(v->pcm_current>v->pcm_returned  && v->pcm_returned!=-1)return(OV_EINVAL);
278
279
54.2k
  v->lW=v->W;
280
54.2k
  v->W=vb->W;
281
54.2k
  v->nW=-1;
282
283
54.2k
  if((v->sequence==-1)||
284
47.7k
     (v->sequence+1 != vb->sequence)){
285
27.8k
    v->granulepos=-1; /* out of sequence; lose count */
286
27.8k
    b->sample_count=-1;
287
27.8k
  }
288
289
54.2k
  v->sequence=vb->sequence;
290
  
291
54.2k
  if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly 
292
                   was called on block */
293
54.2k
    int n=ci->blocksizes[v->W]/2;
294
54.2k
    int n0=ci->blocksizes[0]/2;
295
54.2k
    int n1=ci->blocksizes[1]/2;
296
    
297
54.2k
    int thisCenter;
298
54.2k
    int prevCenter;
299
    
300
54.2k
    if(v->centerW){
301
29.1k
      thisCenter=n1;
302
29.1k
      prevCenter=0;
303
29.1k
    }else{
304
25.0k
      thisCenter=0;
305
25.0k
      prevCenter=n1;
306
25.0k
    }
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
5.43M
    for(j=0;j<vi->channels;j++){
315
      /* the overlap/add section */
316
5.38M
      if(v->lW){
317
1.04M
  if(v->W){
318
    /* large/large */
319
1.03M
    ogg_int32_t *pcm=v->pcm[j]+prevCenter;
320
1.03M
    ogg_int32_t *p=vb->pcm[j];
321
1.43G
    for(i=0;i<n1;i++)
322
1.43G
      pcm[i]+=p[i];
323
1.03M
  }else{
324
    /* large/small */
325
11.2k
    ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
326
11.2k
    ogg_int32_t *p=vb->pcm[j];
327
12.7M
    for(i=0;i<n0;i++)
328
12.7M
      pcm[i]+=p[i];
329
11.2k
  }
330
4.33M
      }else{
331
4.33M
  if(v->W){
332
    /* small/large */
333
236k
    ogg_int32_t *pcm=v->pcm[j]+prevCenter;
334
236k
    ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
335
63.6M
    for(i=0;i<n0;i++)
336
63.4M
      pcm[i]+=p[i];
337
93.2M
    for(;i<n1/2+n0/2;i++)
338
92.9M
      pcm[i]=p[i];
339
4.09M
  }else{
340
    /* small/small */
341
4.09M
    ogg_int32_t *pcm=v->pcm[j]+prevCenter;
342
4.09M
    ogg_int32_t *p=vb->pcm[j];
343
2.09G
    for(i=0;i<n0;i++)
344
2.08G
      pcm[i]+=p[i];
345
4.09M
  }
346
4.33M
      }
347
      
348
      /* the copy section */
349
5.38M
      {
350
5.38M
  ogg_int32_t *pcm=v->pcm[j]+thisCenter;
351
5.38M
  ogg_int32_t *p=vb->pcm[j]+n;
352
3.78G
  for(i=0;i<n;i++)
353
3.78G
    pcm[i]=p[i];
354
5.38M
      }
355
5.38M
    }
356
    
357
54.2k
    if(v->centerW)
358
29.1k
      v->centerW=0;
359
25.0k
    else
360
25.0k
      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
54.2k
    if(v->pcm_returned==-1){
367
6.86k
      v->pcm_returned=thisCenter;
368
6.86k
      v->pcm_current=thisCenter;
369
47.3k
    }else{
370
47.3k
      v->pcm_returned=prevCenter;
371
47.3k
      v->pcm_current=prevCenter+
372
47.3k
  ci->blocksizes[v->lW]/4+
373
47.3k
  ci->blocksizes[v->W]/4;
374
47.3k
    }
375
376
54.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
54.2k
  if(b->sample_count==-1){
390
27.8k
    b->sample_count=0;
391
27.8k
  }else{
392
26.3k
    b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
393
26.3k
  }
394
    
395
54.2k
  if(v->granulepos==-1){
396
51.2k
    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
51.2k
  }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
54.2k
  if(vb->eofflag)v->eofflag=1;
474
54.2k
  return(0);
475
55.8k
}
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
327M
      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
122k
  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