summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libtremor/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libtremor/block.c')
-rw-r--r--lib/rbcodec/codecs/libtremor/block.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libtremor/block.c b/lib/rbcodec/codecs/libtremor/block.c
new file mode 100644
index 0000000000..b820f1cbc2
--- /dev/null
+++ b/lib/rbcodec/codecs/libtremor/block.c
@@ -0,0 +1,471 @@
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 "config-tremor.h"
19#include <stdio.h>
20#include <string.h>
21#include "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#include "ffmpeg_stuff.h"
29//#include <codecs/lib/codeclib.h>
30
31static int ilog(unsigned int v){
32 int ret=0;
33 if(v)--v;
34 while(v){
35 ret++;
36 v>>=1;
37 }
38 return(ret);
39}
40
41static ogg_int32_t* _pcmbp[CHANNELS] IBSS_ATTR;
42static ogg_int32_t* _pcmret[CHANNELS] IBSS_ATTR;
43/* save original pointers returned by malloc so we can free it easily */
44static ogg_int32_t* malloc_pointers[3] = {NULL};
45
46/* pcm accumulator examples (not exhaustive):
47
48 <-------------- lW ---------------->
49 <--------------- W ---------------->
50: .....|..... _______________ |
51: .''' | '''_--- | |\ |
52:.....''' |_____--- '''......| | \_______|
53:.................|__________________|_______|__|______|
54 |<------ Sl ------>| > Sr < |endW
55 |beginSl |endSl | |endSr
56 |beginW |endlW |beginSr
57
58
59 |< lW >|
60 <--------------- W ---------------->
61 | | .. ______________ |
62 | | ' `/ | ---_ |
63 |___.'___/`. | ---_____|
64 |_______|__|_______|_________________|
65 | >|Sl|< |<------ Sr ----->|endW
66 | | |endSl |beginSr |endSr
67 |beginW | |endlW
68 mult[0] |beginSl mult[n]
69
70 <-------------- lW ----------------->
71 |<--W-->|
72: .............. ___ | |
73: .''' |`/ \ | |
74:.....''' |/`....\|...|
75:.........................|___|___|___|
76 |Sl |Sr |endW
77 | | |endSr
78 | |beginSr
79 | |endSl
80 |beginSl
81 |beginW
82*/
83
84/* block abstraction setup *********************************************/
85
86#ifndef WORD_ALIGN
87#define WORD_ALIGN 8
88#endif
89
90int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
91 memset(vb,0,sizeof(*vb));
92 vb->vd=v;
93 vb->localalloc=0;
94 vb->localstore=NULL;
95
96 return(0);
97}
98
99void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
100 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
101 if(bytes+vb->localtop>vb->localalloc){
102 /* can't just _ogg_realloc... there are outstanding pointers */
103 if(vb->localstore){
104 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
105 vb->totaluse+=vb->localtop;
106 link->next=vb->reap;
107 link->ptr=vb->localstore;
108 vb->reap=link;
109 }
110 /* highly conservative */
111 vb->localalloc=bytes;
112 vb->localstore=_ogg_malloc(vb->localalloc);
113 vb->localtop=0;
114 }
115 {
116 void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
117 vb->localtop+=bytes;
118 return ret;
119 }
120}
121
122/* reap the chain, pull the ripcord */
123void _vorbis_block_ripcord(vorbis_block *vb){
124 /* reap the chain */
125 struct alloc_chain *reap=vb->reap;
126 while(reap){
127 struct alloc_chain *next=reap->next;
128 _ogg_free(reap->ptr);
129 memset(reap,0,sizeof(*reap));
130 _ogg_free(reap);
131 reap=next;
132 }
133 /* consolidate storage */
134 if(vb->totaluse){
135 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
136 vb->localalloc+=vb->totaluse;
137 vb->totaluse=0;
138 }
139
140 /* pull the ripcord */
141 vb->localtop=0;
142 vb->reap=NULL;
143}
144
145int vorbis_block_clear(vorbis_block *vb){
146 _vorbis_block_ripcord(vb);
147 if(vb->localstore)_ogg_free(vb->localstore);
148
149 memset(vb,0,sizeof(*vb));
150 return(0);
151}
152
153static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
154 int i;
155 long b_size[2];
156
157 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
158 private_state *b=NULL;
159
160 if(ci==NULL) return 1;
161
162 memset(v,0,sizeof(*v));
163 b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
164
165 v->vi=vi;
166 b->modebits=ilog(ci->modes);
167
168#ifdef TREMOR_USE_IRAM
169 /* allocate IRAM buffer for the PCM data generated by synthesis */
170 iram_malloc_init();
171
172 v->floors = iram_malloc(vi->channels*ci->blocksizes[1]/2*sizeof(ogg_int32_t));
173 v->residues[0] = iram_malloc(vi->channels*ci->blocksizes[1]/2*sizeof(ogg_int32_t));
174 /* if we can get away with it, put a double buffer into IRAM too, so that
175 overlap-add runs iram-to-iram and we avoid needing to memcpy */
176 v->residues[1] = iram_malloc(vi->channels*ci->blocksizes[1]/2*sizeof(ogg_int32_t));
177 if (v->residues[1] == NULL)
178 v->saved = iram_malloc(vi->channels*ci->blocksizes[1]/4*sizeof(ogg_int32_t));
179
180#endif
181
182 if (v->residues[0] == NULL) {
183 malloc_pointers[0] = _ogg_malloc(vi->channels*ci->blocksizes[1]/2*sizeof(ogg_int32_t));
184 v->residues[0] = malloc_pointers[0];
185 }
186
187 if (v->residues[1] == NULL && v->saved == NULL) {
188 malloc_pointers[1] = _ogg_malloc(vi->channels*ci->blocksizes[1]/2*sizeof(ogg_int32_t));
189 v->residues[1] = malloc_pointers[1];
190 }
191
192 if (v->floors == NULL) {
193 malloc_pointers[2] = _ogg_malloc(vi->channels*ci->blocksizes[1]/2*sizeof(ogg_int32_t));
194 v->floors = malloc_pointers[2];
195 }
196
197 /* needed for the first overlap/add */
198 if (v->saved) {
199 memset(v->saved, 0, vi->channels*ci->blocksizes[1]/4*sizeof(ogg_int32_t));
200 for (i = 0; i < vi->channels; i++)
201 v->saved_ptr[i] = v->saved + i*ci->blocksizes[1]/4;
202 } else {
203 memset(v->residues[1], 0, vi->channels*ci->blocksizes[1]/2*sizeof(ogg_int32_t));
204 for (i = 0; i < vi->channels; i++)
205 v->saved_ptr[i] = v->residues[1] + i*ci->blocksizes[1]/2;
206 }
207
208 /* Vorbis I uses only window type 0 */
209 b_size[0]=ci->blocksizes[0]/2;
210 b_size[1]=ci->blocksizes[1]/2;
211 b->window[0]=_vorbis_window(0,b_size[0]);
212 b->window[1]=_vorbis_window(0,b_size[1]);
213
214#ifdef TREMOR_USE_IRAM
215 /* allocate IRAM buffer for window tables too, if sufficient iram available */
216 /* give preference to the larger window over the smaller window
217 (on the assumption that both windows are equally likely used) */
218 LOOKUP_TNC *iramposw;
219 for(i=1; i>=0; i--){
220 iramposw=iram_malloc(b_size[i]*sizeof(LOOKUP_TNC));
221 if(iramposw!=NULL) {
222 memcpy(iramposw, b->window[i], b_size[i]*sizeof(LOOKUP_TNC));
223 b->window[i]=iramposw;
224 }
225 }
226#endif
227
228 /* finish the codebooks */
229 if(!ci->fullbooks){
230 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
231 for(i=0;i<ci->books;i++){
232 if(ci->book_param[i]==NULL)
233 goto abort_books;
234 if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
235 goto abort_books;
236 /* decode codebooks are now standalone after init */
237 vorbis_staticbook_destroy(ci->book_param[i]);
238 ci->book_param[i]=NULL;
239 }
240 }
241
242 v->pcm_storage=ci->blocksizes[1];
243 v->pcmret=_pcmret;
244 v->pcmb=_pcmbp;
245
246 _pcmbp[0]=NULL;
247 _pcmbp[1]=NULL;
248
249 /* all 1 (large block) or 0 (small block) */
250 /* explicitly set for the sake of clarity */
251 v->lW=0; /* previous window size */
252 v->W=0; /* current window size */
253
254 /* initialize all the mapping/backend lookups */
255 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
256 for(i=0;i<ci->modes;i++){
257 int mapnum=ci->mode_param[i]->mapping;
258 int maptype=ci->map_type[mapnum];
259 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
260 ci->map_param[mapnum]);
261 }
262
263 return(0);
264abort_books:
265 for(i=0;i<ci->books;i++){
266 if(ci->book_param[i]!=NULL){
267 vorbis_staticbook_destroy(ci->book_param[i]);
268 ci->book_param[i]=NULL;
269 }
270 }
271 vorbis_dsp_clear(v);
272 return -1;
273}
274
275int vorbis_synthesis_restart(vorbis_dsp_state *v){
276 vorbis_info *vi=v->vi;
277 codec_setup_info *ci;
278
279 if(!v->backend_state)return -1;
280 if(!vi)return -1;
281 ci=vi->codec_setup;
282 if(!ci)return -1;
283
284 v->pcm_current=0;
285
286 v->pcm_returned=-1;
287 v->granulepos=-1;
288 v->sequence=-1;
289 ((private_state *)(v->backend_state))->sample_count=-1;
290
291 return(0);
292}
293
294int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
295 if(_vds_init(v,vi))return 1;
296 vorbis_synthesis_restart(v);
297
298 return 0;
299}
300
301void vorbis_dsp_clear(vorbis_dsp_state *v){
302 int i;
303 if(v){
304 vorbis_info *vi=v->vi;
305 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
306 private_state *b=(private_state *)v->backend_state;
307
308 if(vi != NULL)
309 {
310 /* pcm buffer came from oggmalloc rather than iram */
311 for(i=0;i<3;i++)
312 if(malloc_pointers[i]) {
313 _ogg_free(malloc_pointers[i]);
314 malloc_pointers[i] = NULL;
315 }
316 }
317
318 /* free mode lookups; these are actually vorbis_look_mapping structs */
319 if(ci){
320 for(i=0;i<ci->modes;i++){
321 int mapnum=ci->mode_param[i]->mapping;
322 int maptype=ci->map_type[mapnum];
323 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
324 }
325 }
326
327 if(b){
328 if(b->mode)_ogg_free(b->mode);
329 _ogg_free(b);
330 }
331
332 memset(v,0,sizeof(*v));
333 }
334}
335
336/* Unlike in analysis, the window is only partially applied for each
337 block. The time domain envelope is not yet handled at the point of
338 calling (as it relies on the previous block). */
339
340int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb)
341 ICODE_ATTR;
342int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
343 vorbis_info *vi=v->vi;
344 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
345 private_state *b=v->backend_state;
346
347 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
348
349 v->lW=v->W;
350 v->W=vb->W;
351 v->nW=-1;
352
353 if((v->sequence==-1)||
354 (v->sequence+1 != vb->sequence)){
355 v->granulepos=-1; /* out of sequence; lose count */
356 b->sample_count=-1;
357 }
358
359 v->sequence=vb->sequence;
360 int n=ci->blocksizes[v->W]/2;
361 int ln=ci->blocksizes[v->lW]/2;
362
363 if(LIKELY(vb->pcmend != 0)){ /* no pcm to process if vorbis_synthesis_trackonly
364 was called on block */
365 window_overlap_add(ci->blocksizes[v->W], ci->blocksizes[v->lW],
366 ci->blocksizes[0], ci->blocksizes[1], vi->channels,
367 b->window[v->W & v->lW], v);
368 /* deal with initial packet state; we do this using the explicit
369 pcm_returned==-1 flag otherwise we're sensitive to first block
370 being short or long */
371
372 if(v->pcm_returned==-1){
373 v->pcm_returned=0;
374 v->pcm_current=0;
375 }else{
376 v->pcm_returned=0;
377 v->pcm_current=(n+ln)/2;
378 }
379 }
380
381 /* track the frame number... This is for convenience, but also
382 making sure our last packet doesn't end with added padding. If
383 the last packet is partial, the number of samples we'll have to
384 return will be past the vb->granulepos.
385
386 This is not foolproof! It will be confused if we begin
387 decoding at the last page after a seek or hole. In that case,
388 we don't have a starting point to judge where the last frame
389 is. For this reason, vorbisfile will always try to make sure
390 it reads the last two marked pages in proper sequence */
391
392 if(b->sample_count==-1){
393 b->sample_count=0;
394 }else{
395 b->sample_count+=(n+ln)/2;
396 }
397
398 if(v->granulepos==-1){
399 if(vb->granulepos!=-1){ /* only set if we have a position to set to */
400
401 v->granulepos=vb->granulepos;
402
403 /* is this a short page? */
404 if(b->sample_count>v->granulepos){
405 /* corner case; if this is both the first and last audio page,
406 then spec says the end is cut, not beginning */
407 if(vb->eofflag){
408 /* trim the end */
409 /* no preceeding granulepos; assume we started at zero (we'd
410 have to in a short single-page stream) */
411 /* granulepos could be -1 due to a seek, but that would result
412 in a long coun`t, not short count */
413
414 v->pcm_current-=(b->sample_count-v->granulepos);
415 }else{
416 /* trim the beginning */
417 v->pcm_returned+=(b->sample_count-v->granulepos);
418 if(v->pcm_returned>v->pcm_current)
419 v->pcm_returned=v->pcm_current;
420 }
421
422 }
423
424 }
425 }else{
426 v->granulepos+=(n+ln)/2;
427 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
428
429 if(v->granulepos>vb->granulepos){
430 long extra=v->granulepos-vb->granulepos;
431
432 if(extra)
433 if(vb->eofflag){
434 /* partial last frame. Strip the extra samples off */
435 v->pcm_current-=extra;
436 } /* else {Shouldn't happen *unless* the bitstream is out of
437 spec. Either way, believe the bitstream } */
438 } /* else {Shouldn't happen *unless* the bitstream is out of
439 spec. Either way, believe the bitstream } */
440 v->granulepos=vb->granulepos;
441 }
442 }
443
444 /* Update, cleanup */
445
446 if(vb->eofflag)v->eofflag=1;
447 return(0);
448}
449
450/* pcm==NULL indicates we just want the pending samples, no more */
451int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm) ICODE_ATTR;
452int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
453 vorbis_info *vi=v->vi;
454 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
455 if(pcm){
456 int i;
457 for(i=0;i<vi->channels;i++)
458 v->pcmret[i]=v->pcmb[i]+v->pcm_returned;
459 *pcm=v->pcmret;
460 }
461 return(v->pcm_current-v->pcm_returned);
462 }
463 return 0;
464}
465
466int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
467 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
468 v->pcm_returned+=bytes;
469 return(0);
470}
471