Mercurial > mplayer.hg
comparison libaf/af.c @ 7568:d08513b9fed6
Adding new audio output filter layer libaf
author | anders |
---|---|
date | Tue, 01 Oct 2002 06:45:08 +0000 |
parents | |
children | 8819fdf88b5d |
comparison
equal
deleted
inserted
replaced
7567:85e9956a6727 | 7568:d08513b9fed6 |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 | |
5 #ifdef HAVE_MALLOC_H | |
6 #include <malloc.h> | |
7 #endif | |
8 | |
9 #include "../config.h" | |
10 #include "../mp_msg.h" | |
11 | |
12 #include "af.h" | |
13 | |
14 // Static list of filters | |
15 extern af_info_t af_info_dummy; | |
16 extern af_info_t af_info_delay; | |
17 extern af_info_t af_info_channels; | |
18 extern af_info_t af_info_format; | |
19 extern af_info_t af_info_resample; | |
20 | |
21 static af_info_t* filter_list[]={ \ | |
22 &af_info_dummy,\ | |
23 &af_info_delay,\ | |
24 &af_info_channels,\ | |
25 &af_info_format,\ | |
26 &af_info_resample,\ | |
27 NULL \ | |
28 }; | |
29 | |
30 // Command line config switches | |
31 af_cfg_t af_cfg={\ | |
32 0,\ | |
33 0,\ | |
34 0,\ | |
35 0,\ | |
36 NULL,\ | |
37 }; | |
38 | |
39 | |
40 // Initialization types | |
41 #define SLOW 1 | |
42 #define FAST 2 | |
43 #define FORCE 3 | |
44 | |
45 // The first and last filter in the list | |
46 static af_instance_t* first=NULL; | |
47 static af_instance_t* last=NULL; | |
48 // Storage for input and output data formats (set by init) | |
49 static af_data_t input; | |
50 static af_data_t output; | |
51 | |
52 /* Find a filter in the static list of filters using it's name. This | |
53 function is used internally */ | |
54 af_info_t* af_find(char*name) | |
55 { | |
56 int i=0; | |
57 while(filter_list[i]){ | |
58 if(!strcmp(filter_list[i]->name,name)) | |
59 return filter_list[i]; | |
60 i++; | |
61 } | |
62 mp_msg(MSGT_AFILTER,MSGL_ERR,"Couldn't find audio filter '%s'\n",name); | |
63 return NULL; | |
64 } | |
65 | |
66 // Function for creating a new filter of type name | |
67 af_instance_t* af_create(char* name) | |
68 { | |
69 // Allocate space for the new filter and reset all pointers | |
70 af_instance_t* new=malloc(sizeof(af_instance_t)); | |
71 if(!new){ | |
72 mp_msg(MSGT_AFILTER,MSGL_ERR,"Could not allocate memory\n"); | |
73 return NULL; | |
74 } | |
75 memset(new,0,sizeof(af_instance_t)); | |
76 | |
77 // Find filter from name | |
78 new->info=af_find(name); | |
79 | |
80 // Initialize the new filter | |
81 if(new->info && (AF_OK==new->info->open(new))) | |
82 return new; | |
83 | |
84 free(new); | |
85 mp_msg(MSGT_AFILTER,MSGL_ERR,"Couldn't create audio filter '%s'\n",name); | |
86 return NULL; | |
87 } | |
88 | |
89 /* Create and insert a new filter of type name before the filter in the | |
90 argument. This function can be called during runtime, the return | |
91 value is the new filter */ | |
92 af_instance_t* af_prepend(af_instance_t* af, char* name) | |
93 { | |
94 // Create the new filter and make sure it is ok | |
95 af_instance_t* new=af_create(name); | |
96 if(!new) | |
97 return NULL; | |
98 // Update pointers | |
99 new->next=af; | |
100 if(af){ | |
101 new->prev=af->prev; | |
102 af->prev=new; | |
103 } | |
104 else | |
105 last=new; | |
106 if(new->prev) | |
107 new->prev->next=new; | |
108 else | |
109 first=new; | |
110 return new; | |
111 } | |
112 | |
113 /* Create and insert a new filter of type name after the filter in the | |
114 argument. This function can be called during runtime, the return | |
115 value is the new filter */ | |
116 af_instance_t* af_append(af_instance_t* af, char* name) | |
117 { | |
118 // Create the new filter and make sure it is OK | |
119 af_instance_t* new=af_create(name); | |
120 if(!new) | |
121 return NULL; | |
122 // Update pointers | |
123 new->prev=af; | |
124 if(af){ | |
125 new->next=af->next; | |
126 af->next=new; | |
127 } | |
128 else | |
129 first=new; | |
130 if(new->next) | |
131 new->next->prev=new; | |
132 else | |
133 last=new; | |
134 return new; | |
135 } | |
136 | |
137 // Uninit and remove the filter "af" | |
138 void af_remove(af_instance_t* af) | |
139 { | |
140 if(!af) return; | |
141 | |
142 // Detach pointers | |
143 if(af->prev) | |
144 af->prev->next=af->next; | |
145 else | |
146 first=af->next; | |
147 if(af->next) | |
148 af->next->prev=af->prev; | |
149 else | |
150 last=af->prev; | |
151 | |
152 // Uninitialize af and free memory | |
153 af->uninit(af); | |
154 free(af); | |
155 } | |
156 | |
157 /* Reinitializes all filters downstream from the filter given in the argument */ | |
158 int af_reinit(af_instance_t* af) | |
159 { | |
160 if(!af) | |
161 return AF_ERROR; | |
162 | |
163 do{ | |
164 af_data_t in; // Format of the input to current filter | |
165 int rv=0; // Return value | |
166 | |
167 // Check if this is the first filter | |
168 if(!af->prev) | |
169 memcpy(&in,&input,sizeof(af_data_t)); | |
170 else | |
171 memcpy(&in,af->prev->data,sizeof(af_data_t)); | |
172 // Reset just in case... | |
173 in.audio=NULL; | |
174 in.len=0; | |
175 | |
176 rv = af->control(af,AF_CONTROL_REINIT,&in); | |
177 switch(rv){ | |
178 case AF_OK: | |
179 break; | |
180 case AF_FALSE:{ // Configuration filter is needed | |
181 af_instance_t* new = NULL; | |
182 // Insert channels filter | |
183 if((af->prev?af->prev->data->nch:input.nch) != in.nch){ | |
184 // Create channels filter | |
185 if(NULL == (new = af_prepend(af,"channels"))) | |
186 return AF_ERROR; | |
187 // Set number of output channels | |
188 if(AF_OK != (rv = new->control(new,AF_CONTROL_CHANNELS,&in.nch))) | |
189 return rv; | |
190 // Initialize channels filter | |
191 if(!new->prev) | |
192 memcpy(&in,&input,sizeof(af_data_t)); | |
193 else | |
194 memcpy(&in,new->prev->data,sizeof(af_data_t)); | |
195 if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in))) | |
196 return rv; | |
197 } | |
198 // Insert format filter | |
199 if(((af->prev?af->prev->data->format:input.format) != in.format) || | |
200 ((af->prev?af->prev->data->bps:input.bps) != in.bps)){ | |
201 // Create format filter | |
202 if(NULL == (new = af_prepend(af,"format"))) | |
203 return AF_ERROR; | |
204 // Set output format | |
205 if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT,&in))) | |
206 return rv; | |
207 // Initialize format filter | |
208 if(!new->prev) | |
209 memcpy(&in,&input,sizeof(af_data_t)); | |
210 else | |
211 memcpy(&in,new->prev->data,sizeof(af_data_t)); | |
212 if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in))) | |
213 return rv; | |
214 } | |
215 if(!new) // Should _never_ happen | |
216 return AF_ERROR; | |
217 af=new; | |
218 break; | |
219 } | |
220 case AF_DETACH:{ // Filter is redundant and wants to be unloaded | |
221 af_instance_t* aft=af->prev; | |
222 af_remove(af); | |
223 if(aft) | |
224 af=aft; | |
225 else | |
226 af=first; // Restart configuration | |
227 break; | |
228 } | |
229 default: | |
230 mp_msg(MSGT_AFILTER,MSGL_ERR,"Reinit did not work, audio filter '%s' returned error code %i\n",af->info->name,rv); | |
231 return AF_ERROR; | |
232 } | |
233 af=af->next; | |
234 }while(af); | |
235 return AF_OK; | |
236 } | |
237 | |
238 /* Find filter in the dynamic filter list using it's name This | |
239 function is used for finding already initialized filters */ | |
240 af_instance_t* af_get(char* name) | |
241 { | |
242 af_instance_t* af=first; | |
243 while(af->next != NULL){ | |
244 if(!strcmp(af->info->name,name)) | |
245 return af; | |
246 af=af->next; | |
247 } | |
248 return NULL; | |
249 } | |
250 | |
251 // Uninit and remove all filters | |
252 void af_uninit() | |
253 { | |
254 while(first) | |
255 af_remove(first); | |
256 } | |
257 | |
258 /* Init read configuration and create filter list accordingly. In and | |
259 out contains the format of the current movie and the formate of the | |
260 preferred output respectively */ | |
261 int af_init(af_data_t* in, af_data_t* out) | |
262 { | |
263 int cfg=SLOW; // configuration type | |
264 int i=0; | |
265 | |
266 // Precaution in case caller is misbehaving | |
267 in->audio = out->audio = NULL; | |
268 in->len = out->len = 0; | |
269 | |
270 // Figure out how fast the machine is | |
271 if(af_cfg.force) | |
272 cfg=af_cfg.force; | |
273 else{ | |
274 # if defined(HAVE_SSE) || defined(HAVE_3DNOWEX) | |
275 cfg=FAST; | |
276 # else | |
277 cfg=SLOW; | |
278 # endif | |
279 } | |
280 | |
281 // Input and output configuration | |
282 memcpy(&input,in,sizeof(af_data_t)); | |
283 memcpy(&output,out,sizeof(af_data_t)); | |
284 | |
285 // Check if this is the first call | |
286 if(!first){ | |
287 // Add all filters in the list (if there are any) | |
288 if(!af_cfg.list){ | |
289 if(!af_append(first,"dummy")) // To make automatic format conversion work | |
290 return -1; | |
291 } | |
292 else{ | |
293 while(af_cfg.list[i]){ | |
294 if(!af_append(last,af_cfg.list[i++])) | |
295 return -1; | |
296 } | |
297 } | |
298 } | |
299 | |
300 // Init filters | |
301 if(AF_OK != af_reinit(first)) | |
302 return -1; | |
303 | |
304 // Check output format | |
305 if(cfg!=FORCE){ | |
306 af_instance_t* af = NULL; // New filter | |
307 // Check output frequency if not OK fix with resample | |
308 if(last->data->rate!=output.rate){ | |
309 if(NULL==(af=af_get("resample"))){ | |
310 if(cfg==SLOW){ | |
311 if(!strcmp(first->info->name,"format")) | |
312 af = af_append(first,"resample"); | |
313 else | |
314 af = af_prepend(first,"resample"); | |
315 } | |
316 else{ | |
317 if(!strcmp(last->info->name,"format")) | |
318 af = af_prepend(last,"resample"); | |
319 else | |
320 af = af_append(last,"resample"); | |
321 } | |
322 } | |
323 // Init the new filter | |
324 if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE,&output.rate))) | |
325 return -1; | |
326 if(AF_OK != af_reinit(af)) | |
327 return -1; | |
328 } | |
329 | |
330 // Check number of output channels fix if not OK | |
331 // If needed always inserted last -> easy to screw up other filters | |
332 if(last->data->nch!=output.nch){ | |
333 if(!strcmp(last->info->name,"format")) | |
334 af = af_prepend(last,"channels"); | |
335 else | |
336 af = af_append(last,"channels"); | |
337 // Init the new filter | |
338 if(!af || (AF_OK != af->control(af,AF_CONTROL_CHANNELS,&output.nch))) | |
339 return -1; | |
340 if(AF_OK != af_reinit(af)) | |
341 return -1; | |
342 } | |
343 | |
344 // Check output format fix if not OK | |
345 if((last->data->format != output.format) || (last->data->bps != output.bps)){ | |
346 if(strcmp(last->info->name,"format")) | |
347 af = af_append(last,"format"); | |
348 else | |
349 af = last; | |
350 // Init the new filter | |
351 if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT,&output))) | |
352 return -1; | |
353 if(AF_OK != af_reinit(af)) | |
354 return -1; | |
355 } | |
356 | |
357 // Re init again just in case | |
358 if(AF_OK != af_reinit(first)) | |
359 return -1; | |
360 | |
361 if((last->data->format != output.format) || (last->data->bps != output.bps) || | |
362 (last->data->nch!=output.nch) || (last->data->rate!=output.rate)){ | |
363 // Something is stuffed audio out will not work | |
364 mp_msg(MSGT_AFILTER,MSGL_ERR,"Unable to setup filter system can not meet sound-card demands, please report this error on MPlayer development mailing list. \n"); | |
365 af_uninit(); | |
366 return -1; | |
367 } | |
368 } | |
369 return 0; | |
370 } | |
371 | |
372 // Filter data chunk through the filters in the list | |
373 af_data_t* af_play(af_data_t* data) | |
374 { | |
375 af_instance_t* af=first; | |
376 // Iterate through all filters | |
377 do{ | |
378 data=af->play(af,data); | |
379 af=af->next; | |
380 }while(af); | |
381 return data; | |
382 } | |
383 | |
384 /* Helper function used to calculate the exact buffer length needed | |
385 when buffers are resized */ | |
386 inline int af_lencalc(frac_t mul, int len){ | |
387 register int q = len*mul.n; | |
388 return q/mul.d + q%mul.d; | |
389 } | |
390 | |
391 /* Calculate how long the output from the filters will be given the | |
392 input length "len" */ | |
393 int af_outputlen(int len) | |
394 { | |
395 af_instance_t* af=first; | |
396 frac_t mul = {1,1}; | |
397 // Iterate through all filters | |
398 do{ | |
399 mul.n *= af->mul.n; | |
400 mul.d *= af->mul.d; | |
401 af=af->next; | |
402 }while(af); | |
403 return af_lencalc(mul,len); | |
404 } | |
405 | |
406 /* Calculate how long the input to the filters should be to produce a | |
407 certain output length, i.e. the return value of this function is | |
408 the input length required to produce the output length "len". */ | |
409 int af_inputlen(int len) | |
410 { | |
411 af_instance_t* af=first; | |
412 frac_t mul = {1,1}; | |
413 // Iterate through all filters | |
414 do{ | |
415 mul.d *= af->mul.n; | |
416 mul.n *= af->mul.d; | |
417 af=af->next; | |
418 }while(af); | |
419 return af_lencalc(mul,len); | |
420 } | |
421 | |
422 /* Helper function called by the macro with the same name this | |
423 function should not be called directly */ | |
424 inline int af_resize_local_buffer(af_instance_t* af, af_data_t* data) | |
425 { | |
426 // Calculate new length | |
427 register int len = af_lencalc(af->mul,data->len); | |
428 mp_msg(MSGT_AFILTER,MSGL_V,"Reallocating memory in module %s, old len = %i, new len = %i\n",af->info->name,af->data->len,len); | |
429 // If there is a buffer free it | |
430 if(af->data->audio) | |
431 free(af->data->audio); | |
432 // Create new buffer and check that it is OK | |
433 af->data->audio = malloc(len); | |
434 if(!af->data->audio){ | |
435 mp_msg(MSGT_AFILTER,MSGL_ERR,"Could not allocate memory \n"); | |
436 return AF_ERROR; | |
437 } | |
438 af->data->len=len; | |
439 return AF_OK; | |
440 } |