Mercurial > mplayer.hg
annotate tremor/block.c @ 23410:a25e0a8adab5
Adding myself to the authors page.
author | mhoffman |
---|---|
date | Thu, 31 May 2007 04:15:29 +0000 |
parents | cd6b211be811 |
children | 8dfda4d651ec |
rev | line source |
---|---|
14280 | 1 /******************************************************************** |
2 * * | |
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * | |
4 * * | |
19251
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
5 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
6 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * |
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
7 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
8 * * |
14280 | 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.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 static int ilog(unsigned int v){ | |
30 int ret=0; | |
31 if(v)--v; | |
32 while(v){ | |
33 ret++; | |
34 v>>=1; | |
35 } | |
36 return(ret); | |
37 } | |
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 #define WORD_ALIGN 8 | |
81 #endif | |
82 | |
83 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){ | |
84 memset(vb,0,sizeof(*vb)); | |
85 vb->vd=v; | |
86 vb->localalloc=0; | |
87 vb->localstore=NULL; | |
88 | |
89 return(0); | |
90 } | |
91 | |
92 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){ | |
93 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1); | |
94 if(bytes+vb->localtop>vb->localalloc){ | |
95 /* can't just _ogg_realloc... there are outstanding pointers */ | |
96 if(vb->localstore){ | |
97 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link)); | |
98 vb->totaluse+=vb->localtop; | |
99 link->next=vb->reap; | |
100 link->ptr=vb->localstore; | |
101 vb->reap=link; | |
102 } | |
103 /* highly conservative */ | |
104 vb->localalloc=bytes; | |
105 vb->localstore=_ogg_malloc(vb->localalloc); | |
106 vb->localtop=0; | |
107 } | |
108 { | |
109 void *ret=(void *)(((char *)vb->localstore)+vb->localtop); | |
110 vb->localtop+=bytes; | |
111 return ret; | |
112 } | |
113 } | |
114 | |
115 /* reap the chain, pull the ripcord */ | |
116 void _vorbis_block_ripcord(vorbis_block *vb){ | |
117 /* reap the chain */ | |
118 struct alloc_chain *reap=vb->reap; | |
119 while(reap){ | |
120 struct alloc_chain *next=reap->next; | |
121 _ogg_free(reap->ptr); | |
122 memset(reap,0,sizeof(*reap)); | |
123 _ogg_free(reap); | |
124 reap=next; | |
125 } | |
126 /* consolidate storage */ | |
127 if(vb->totaluse){ | |
128 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc); | |
129 vb->localalloc+=vb->totaluse; | |
130 vb->totaluse=0; | |
131 } | |
132 | |
133 /* pull the ripcord */ | |
134 vb->localtop=0; | |
135 vb->reap=NULL; | |
136 } | |
137 | |
138 int vorbis_block_clear(vorbis_block *vb){ | |
139 _vorbis_block_ripcord(vb); | |
140 if(vb->localstore)_ogg_free(vb->localstore); | |
141 | |
142 memset(vb,0,sizeof(*vb)); | |
143 return(0); | |
144 } | |
145 | |
146 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){ | |
147 int i; | |
148 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | |
149 backend_lookup_state *b=NULL; | |
150 | |
151 memset(v,0,sizeof(*v)); | |
152 b=(backend_lookup_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b))); | |
153 | |
154 v->vi=vi; | |
155 b->modebits=ilog(ci->modes); | |
156 | |
157 /* Vorbis I uses only window type 0 */ | |
158 b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2); | |
159 b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2); | |
160 | |
161 /* finish the codebooks */ | |
162 if(!ci->fullbooks){ | |
163 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); | |
164 for(i=0;i<ci->books;i++){ | |
165 vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]); | |
166 /* decode codebooks are now standalone after init */ | |
167 vorbis_staticbook_destroy(ci->book_param[i]); | |
168 ci->book_param[i]=NULL; | |
169 } | |
170 } | |
171 | |
172 v->pcm_storage=ci->blocksizes[1]; | |
173 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm)); | |
174 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret)); | |
175 for(i=0;i<vi->channels;i++) | |
176 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i])); | |
177 | |
178 /* all 1 (large block) or 0 (small block) */ | |
179 /* explicitly set for the sake of clarity */ | |
180 v->lW=0; /* previous window size */ | |
181 v->W=0; /* current window size */ | |
182 | |
183 /* all vector indexes */ | |
184 v->centerW=ci->blocksizes[1]/2; | |
185 | |
186 v->pcm_current=v->centerW; | |
187 | |
188 /* initialize all the mapping/backend lookups */ | |
189 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode)); | |
190 for(i=0;i<ci->modes;i++){ | |
191 int mapnum=ci->mode_param[i]->mapping; | |
192 int maptype=ci->map_type[mapnum]; | |
193 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i], | |
194 ci->map_param[mapnum]); | |
195 } | |
196 | |
197 v->pcm_returned=-1; | |
198 v->granulepos=-1; | |
199 v->sequence=-1; | |
200 | |
201 return(0); | |
202 } | |
203 | |
204 void vorbis_dsp_clear(vorbis_dsp_state *v){ | |
205 int i; | |
206 if(v){ | |
207 vorbis_info *vi=v->vi; | |
208 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL); | |
209 backend_lookup_state *b=(backend_lookup_state *)v->backend_state; | |
210 | |
211 if(v->pcm){ | |
212 for(i=0;i<vi->channels;i++) | |
213 if(v->pcm[i])_ogg_free(v->pcm[i]); | |
214 _ogg_free(v->pcm); | |
215 if(v->pcmret)_ogg_free(v->pcmret); | |
216 } | |
217 | |
218 /* free mode lookups; these are actually vorbis_look_mapping structs */ | |
219 if(ci){ | |
220 for(i=0;i<ci->modes;i++){ | |
221 int mapnum=ci->mode_param[i]->mapping; | |
222 int maptype=ci->map_type[mapnum]; | |
223 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]); | |
224 } | |
225 } | |
226 | |
227 if(b){ | |
228 if(b->mode)_ogg_free(b->mode); | |
229 _ogg_free(b); | |
230 } | |
231 | |
232 memset(v,0,sizeof(*v)); | |
233 } | |
234 } | |
235 | |
236 /* Unlike in analysis, the window is only partially applied for each | |
237 block. The time domain envelope is not yet handled at the point of | |
238 calling (as it relies on the previous block). */ | |
239 | |
240 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ | |
241 vorbis_info *vi=v->vi; | |
242 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | |
243 int i,j; | |
244 | |
245 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL); | |
246 | |
247 v->lW=v->W; | |
248 v->W=vb->W; | |
249 v->nW=-1; | |
250 | |
251 if(v->sequence+1 != vb->sequence)v->granulepos=-1; /* out of sequence; | |
252 lose count */ | |
253 | |
254 v->sequence=vb->sequence; | |
255 | |
256 { | |
257 int n=ci->blocksizes[v->W]/2; | |
258 int n0=ci->blocksizes[0]/2; | |
259 int n1=ci->blocksizes[1]/2; | |
260 | |
261 int thisCenter; | |
262 int prevCenter; | |
263 | |
264 if(v->centerW){ | |
265 thisCenter=n1; | |
266 prevCenter=0; | |
267 }else{ | |
268 thisCenter=0; | |
269 prevCenter=n1; | |
270 } | |
271 | |
272 /* v->pcm is now used like a two-stage double buffer. We don't want | |
273 to have to constantly shift *or* adjust memory usage. Don't | |
274 accept a new block until the old is shifted out */ | |
275 | |
276 /* overlap/add PCM */ | |
277 | |
278 for(j=0;j<vi->channels;j++){ | |
279 /* the overlap/add section */ | |
280 if(v->lW){ | |
281 if(v->W){ | |
282 /* large/large */ | |
283 ogg_int32_t *pcm=v->pcm[j]+prevCenter; | |
284 ogg_int32_t *p=vb->pcm[j]; | |
285 for(i=0;i<n1;i++) | |
286 pcm[i]+=p[i]; | |
287 }else{ | |
288 /* large/small */ | |
289 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2; | |
290 ogg_int32_t *p=vb->pcm[j]; | |
291 for(i=0;i<n0;i++) | |
292 pcm[i]+=p[i]; | |
293 } | |
294 }else{ | |
295 if(v->W){ | |
296 /* small/large */ | |
297 ogg_int32_t *pcm=v->pcm[j]+prevCenter; | |
298 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2; | |
299 for(i=0;i<n0;i++) | |
300 pcm[i]+=p[i]; | |
301 for(;i<n1/2+n0/2;i++) | |
302 pcm[i]=p[i]; | |
303 }else{ | |
304 /* small/small */ | |
305 ogg_int32_t *pcm=v->pcm[j]+prevCenter; | |
306 ogg_int32_t *p=vb->pcm[j]; | |
307 for(i=0;i<n0;i++) | |
308 pcm[i]+=p[i]; | |
309 } | |
310 } | |
311 | |
312 /* the copy section */ | |
313 { | |
314 ogg_int32_t *pcm=v->pcm[j]+thisCenter; | |
315 ogg_int32_t *p=vb->pcm[j]+n; | |
316 for(i=0;i<n;i++) | |
317 pcm[i]=p[i]; | |
318 } | |
319 } | |
320 | |
321 if(v->centerW) | |
322 v->centerW=0; | |
323 else | |
324 v->centerW=n1; | |
325 | |
326 /* deal with initial packet state; we do this using the explicit | |
327 pcm_returned==-1 flag otherwise we're sensitive to first block | |
328 being short or long */ | |
329 | |
330 if(v->pcm_returned==-1){ | |
331 v->pcm_returned=thisCenter; | |
332 v->pcm_current=thisCenter; | |
333 }else{ | |
334 v->pcm_returned=prevCenter; | |
335 v->pcm_current=prevCenter+ | |
336 ci->blocksizes[v->lW]/4+ | |
337 ci->blocksizes[v->W]/4; | |
338 } | |
339 | |
340 /* track the frame number... This is for convenience, but also | |
341 making sure our last packet doesn't end with added padding. If | |
342 the last packet is partial, the number of samples we'll have to | |
343 return will be past the vb->granulepos. | |
344 | |
345 This is not foolproof! It will be confused if we begin | |
346 decoding at the last page after a seek or hole. In that case, | |
347 we don't have a starting point to judge where the last frame | |
348 is. For this reason, vorbisfile will always try to make sure | |
349 it reads the last two marked pages in proper sequence */ | |
350 | |
351 if(v->granulepos==-1) | |
352 if(vb->granulepos==-1){ | |
353 v->granulepos=0; | |
354 }else{ | |
355 v->granulepos=vb->granulepos; | |
356 } | |
357 else{ | |
358 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; | |
359 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){ | |
360 | |
361 if(v->granulepos>vb->granulepos){ | |
362 long extra=v->granulepos-vb->granulepos; | |
363 | |
364 if(vb->eofflag){ | |
365 /* partial last frame. Strip the extra samples off */ | |
366 v->pcm_current-=extra; | |
367 }else if(vb->sequence == 1){ | |
368 /* ^^^ argh, this can be 1 from seeking! */ | |
369 | |
370 | |
371 /* partial first frame. Discard extra leading samples */ | |
372 v->pcm_returned+=extra; | |
373 if(v->pcm_returned>v->pcm_current) | |
374 v->pcm_returned=v->pcm_current; | |
375 | |
376 } | |
377 | |
378 }/* else{ Shouldn't happen *unless* the bitstream is out of | |
379 spec. Either way, believe the bitstream } */ | |
380 v->granulepos=vb->granulepos; | |
381 } | |
382 } | |
383 | |
384 /* Update, cleanup */ | |
385 | |
386 if(vb->eofflag)v->eofflag=1; | |
387 } | |
388 | |
389 return(0); | |
390 } | |
391 | |
392 /* pcm==NULL indicates we just want the pending samples, no more */ | |
393 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){ | |
394 vorbis_info *vi=v->vi; | |
395 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){ | |
396 if(pcm){ | |
397 int i; | |
398 for(i=0;i<vi->channels;i++) | |
399 v->pcmret[i]=v->pcm[i]+v->pcm_returned; | |
400 *pcm=v->pcmret; | |
401 } | |
402 return(v->pcm_current-v->pcm_returned); | |
403 } | |
404 return(0); | |
405 } | |
406 | |
407 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){ | |
408 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL); | |
409 v->pcm_returned+=bytes; | |
410 return(0); | |
411 } | |
412 |