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