diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/libtremor/block.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) | |
download | rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/libtremor/block.c')
-rw-r--r-- | lib/rbcodec/codecs/libtremor/block.c | 471 |
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 | |||
31 | static 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 | |||
41 | static ogg_int32_t* _pcmbp[CHANNELS] IBSS_ATTR; | ||
42 | static ogg_int32_t* _pcmret[CHANNELS] IBSS_ATTR; | ||
43 | /* save original pointers returned by malloc so we can free it easily */ | ||
44 | static 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 | |||
90 | int 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 | |||
99 | void *_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 */ | ||
123 | void _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 | |||
145 | int 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 | |||
153 | static 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); | ||
264 | abort_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 | |||
275 | int 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 | |||
294 | int 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 | |||
301 | void 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 | |||
340 | int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb) | ||
341 | ICODE_ATTR; | ||
342 | int 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 */ | ||
451 | int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm) ICODE_ATTR; | ||
452 | int 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 | |||
466 | int 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 | |||