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