Mercurial > mplayer.hg
annotate libaf/af_channels.c @ 22865:441582f3ed87
simplified function prototypes to avoid casts but keep external API compatibility
author | ben |
---|---|
date | Sun, 01 Apr 2007 12:39:06 +0000 |
parents | 904e3f3f8bee |
children | b2402b4f0afa |
rev | line source |
---|---|
7568 | 1 /* Audio filter that adds and removes channels, according to the |
2 command line parameter channels. It is stupid and can only add | |
3 silence or copy channels not mix or filter. | |
4 */ | |
5 #include <stdio.h> | |
6 #include <stdlib.h> | |
7 #include <string.h> | |
7975 | 8 #include <inttypes.h> |
7568 | 9 |
10 #include "af.h" | |
11 | |
8607 | 12 #define FR 0 |
13 #define TO 1 | |
14 | |
15 typedef struct af_channels_s{ | |
16 int route[AF_NCH][2]; | |
17 int nr; | |
18 int router; | |
19 }af_channels_t; | |
20 | |
7568 | 21 // Local function for copying data |
8711
906f7a2dc085
sig 11 fix in reinit and resample + spelling error fixes
anders
parents:
8607
diff
changeset
|
22 static void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps) |
7568 | 23 { |
24 switch(bps){ | |
25 case 1:{ | |
26 int8_t* tin = (int8_t*)in; | |
27 int8_t* tout = (int8_t*)out; | |
28 tin += inos; | |
29 tout += outos; | |
30 len = len/ins; | |
31 while(len--){ | |
32 *tout=*tin; | |
33 tin +=ins; | |
34 tout+=outs; | |
35 } | |
36 break; | |
37 } | |
38 case 2:{ | |
39 int16_t* tin = (int16_t*)in; | |
40 int16_t* tout = (int16_t*)out; | |
41 tin += inos; | |
42 tout += outos; | |
43 len = len/(2*ins); | |
44 while(len--){ | |
45 *tout=*tin; | |
46 tin +=ins; | |
47 tout+=outs; | |
48 } | |
49 break; | |
50 } | |
12913 | 51 case 3:{ |
52 int8_t* tin = (int8_t*)in; | |
53 int8_t* tout = (int8_t*)out; | |
54 tin += 3 * inos; | |
55 tout += 3 * outos; | |
56 len = len / ( 3 * ins); | |
57 while (len--) { | |
58 tout[0] = tin[0]; | |
59 tout[1] = tin[1]; | |
60 tout[2] = tin[2]; | |
61 tin += 3 * ins; | |
62 tout += 3 * outs; | |
63 } | |
64 break; | |
65 } | |
7568 | 66 case 4:{ |
67 int32_t* tin = (int32_t*)in; | |
68 int32_t* tout = (int32_t*)out; | |
69 tin += inos; | |
70 tout += outos; | |
71 len = len/(4*ins); | |
72 while(len--){ | |
73 *tout=*tin; | |
74 tin +=ins; | |
75 tout+=outs; | |
76 } | |
77 break; | |
78 } | |
79 case 8:{ | |
80 int64_t* tin = (int64_t*)in; | |
81 int64_t* tout = (int64_t*)out; | |
82 tin += inos; | |
83 tout += outos; | |
84 len = len/(8*ins); | |
85 while(len--){ | |
86 *tout=*tin; | |
87 tin +=ins; | |
88 tout+=outs; | |
89 } | |
90 break; | |
91 } | |
92 default: | |
8607 | 93 af_msg(AF_MSG_ERROR,"[channels] Unsupported number of bytes/sample: %i" |
94 " please report this error on the MPlayer mailing list. \n",bps); | |
7568 | 95 } |
96 } | |
97 | |
8607 | 98 // Make sure the routes are sane |
99 static int check_routes(af_channels_t* s, int nin, int nout) | |
100 { | |
101 int i; | |
102 if((s->nr < 1) || (s->nr > AF_NCH)){ | |
8711
906f7a2dc085
sig 11 fix in reinit and resample + spelling error fixes
anders
parents:
8607
diff
changeset
|
103 af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs must be" |
8607 | 104 " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); |
105 return AF_ERROR; | |
106 } | |
107 | |
108 for(i=0;i<s->nr;i++){ | |
109 if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){ | |
110 af_msg(AF_MSG_ERROR,"[channels] Invalid routing in pair nr. %i.\n", i); | |
111 return AF_ERROR; | |
112 } | |
113 } | |
114 return AF_OK; | |
115 } | |
116 | |
7568 | 117 // Initialization and runtime control |
118 static int control(struct af_instance_s* af, int cmd, void* arg) | |
119 { | |
8607 | 120 af_channels_t* s = af->setup; |
7568 | 121 switch(cmd){ |
122 case AF_CONTROL_REINIT: | |
8607 | 123 |
124 // Set default channel assignment | |
125 if(!s->router){ | |
126 int i; | |
127 // Make sure this filter isn't redundant | |
128 if(af->data->nch == ((af_data_t*)arg)->nch) | |
129 return AF_DETACH; | |
130 | |
131 // If mono: fake stereo | |
132 if(((af_data_t*)arg)->nch == 1){ | |
133 s->nr = min(af->data->nch,2); | |
134 for(i=0;i<s->nr;i++){ | |
135 s->route[i][FR] = 0; | |
136 s->route[i][TO] = i; | |
137 } | |
138 } | |
139 else{ | |
140 s->nr = min(af->data->nch, ((af_data_t*)arg)->nch); | |
141 for(i=0;i<s->nr;i++){ | |
142 s->route[i][FR] = i; | |
143 s->route[i][TO] = i; | |
144 } | |
145 } | |
146 } | |
7568 | 147 |
148 af->data->rate = ((af_data_t*)arg)->rate; | |
149 af->data->format = ((af_data_t*)arg)->format; | |
150 af->data->bps = ((af_data_t*)arg)->bps; | |
151 af->mul.n = af->data->nch; | |
152 af->mul.d = ((af_data_t*)arg)->nch; | |
14433
95bb94a930a3
always cancel down fractions (frac_t) to avoid overflows and playback
reimar
parents:
12913
diff
changeset
|
153 af_frac_cancel(&af->mul); |
8607 | 154 return check_routes(s,((af_data_t*)arg)->nch,af->data->nch); |
7998
d48a06d07afb
Adding commandline options for filters and fixing stupid bug in cfg
anders
parents:
7975
diff
changeset
|
155 case AF_CONTROL_COMMAND_LINE:{ |
d48a06d07afb
Adding commandline options for filters and fixing stupid bug in cfg
anders
parents:
7975
diff
changeset
|
156 int nch = 0; |
8607 | 157 int n = 0; |
158 // Check number of channels and number of routing pairs | |
159 sscanf(arg, "%i:%i%n", &nch, &s->nr, &n); | |
160 | |
161 // If router scan commandline for routing pairs | |
162 if(s->nr){ | |
163 char* cp = &((char*)arg)[n]; | |
164 int ch = 0; | |
165 // Sanity check | |
166 if((s->nr < 1) || (s->nr > AF_NCH)){ | |
8711
906f7a2dc085
sig 11 fix in reinit and resample + spelling error fixes
anders
parents:
8607
diff
changeset
|
167 af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs must be" |
8607 | 168 " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); |
169 } | |
170 s->router = 1; | |
171 // Scan for pairs on commandline | |
172 while((*cp == ':') && (ch < s->nr)){ | |
173 sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n); | |
8711
906f7a2dc085
sig 11 fix in reinit and resample + spelling error fixes
anders
parents:
8607
diff
changeset
|
174 af_msg(AF_MSG_VERBOSE,"[channels] Routing from channel %i to" |
8607 | 175 " channel %i\n",s->route[ch][FR],s->route[ch][TO]); |
176 cp = &cp[n]; | |
177 ch++; | |
178 } | |
179 } | |
180 | |
181 if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch)) | |
182 return AF_ERROR; | |
183 return AF_OK; | |
184 } | |
185 case AF_CONTROL_CHANNELS | AF_CONTROL_SET: | |
7568 | 186 // Reinit must be called after this function has been called |
187 | |
188 // Sanity check | |
12008 | 189 if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){ |
8607 | 190 af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be" |
191 " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]); | |
7568 | 192 return AF_ERROR; |
193 } | |
194 | |
195 af->data->nch=((int*)arg)[0]; | |
8607 | 196 if(!s->router) |
197 af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels" | |
198 " to %i\n",af->data->nch); | |
199 return AF_OK; | |
200 case AF_CONTROL_CHANNELS | AF_CONTROL_GET: | |
201 *(int*)arg = af->data->nch; | |
202 return AF_OK; | |
203 case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{ | |
204 int ch = ((af_control_ext_t*)arg)->ch; | |
205 int* route = ((af_control_ext_t*)arg)->arg; | |
206 s->route[ch][FR] = route[FR]; | |
207 s->route[ch][TO] = route[TO]; | |
208 return AF_OK; | |
209 } | |
210 case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{ | |
211 int ch = ((af_control_ext_t*)arg)->ch; | |
212 int* route = ((af_control_ext_t*)arg)->arg; | |
213 route[FR] = s->route[ch][FR]; | |
214 route[TO] = s->route[ch][TO]; | |
215 return AF_OK; | |
216 } | |
217 case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET: | |
218 s->nr = *(int*)arg; | |
219 return AF_OK; | |
220 case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET: | |
221 *(int*)arg = s->nr; | |
222 return AF_OK; | |
223 case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET: | |
224 s->router = *(int*)arg; | |
225 return AF_OK; | |
226 case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET: | |
227 *(int*)arg = s->router; | |
7568 | 228 return AF_OK; |
229 } | |
230 return AF_UNKNOWN; | |
231 } | |
232 | |
233 // Deallocate memory | |
234 static void uninit(struct af_instance_s* af) | |
235 { | |
22179 | 236 free(af->setup); |
237 if (af->data) | |
238 free(af->data->audio); | |
239 free(af->data); | |
7568 | 240 } |
241 | |
242 // Filter data through filter | |
243 static af_data_t* play(struct af_instance_s* af, af_data_t* data) | |
244 { | |
8607 | 245 af_data_t* c = data; // Current working data |
246 af_data_t* l = af->data; // Local data | |
247 af_channels_t* s = af->setup; | |
248 int i; | |
249 | |
7568 | 250 if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) |
251 return NULL; | |
252 | |
8607 | 253 // Reset unused channels |
254 memset(l->audio,0,(c->len*af->mul.n)/af->mul.d); | |
7568 | 255 |
8607 | 256 if(AF_OK == check_routes(s,c->nch,l->nch)) |
257 for(i=0;i<s->nr;i++) | |
258 copy(c->audio,l->audio,c->nch,s->route[i][FR], | |
259 l->nch,s->route[i][TO],c->len,c->bps); | |
7568 | 260 |
261 // Set output data | |
262 c->audio = l->audio; | |
7590 | 263 c->len = (c->len*af->mul.n)/af->mul.d; |
7568 | 264 c->nch = l->nch; |
265 | |
266 return c; | |
267 } | |
268 | |
269 // Allocate memory and set function pointers | |
22746
fd6f824ef894
Rename open to af_open so as not to conflict with a previous header definition.
diego
parents:
22179
diff
changeset
|
270 static int af_open(af_instance_t* af){ |
7568 | 271 af->control=control; |
272 af->uninit=uninit; | |
273 af->play=play; | |
274 af->mul.n=1; | |
275 af->mul.d=1; | |
276 af->data=calloc(1,sizeof(af_data_t)); | |
8607 | 277 af->setup=calloc(1,sizeof(af_channels_t)); |
278 if((af->data == NULL) || (af->setup == NULL)) | |
7568 | 279 return AF_ERROR; |
280 return AF_OK; | |
281 } | |
282 | |
283 // Description of this filter | |
284 af_info_t af_info_channels = { | |
285 "Insert or remove channels", | |
286 "channels", | |
287 "Anders", | |
288 "", | |
7615 | 289 AF_FLAGS_REENTRANT, |
22746
fd6f824ef894
Rename open to af_open so as not to conflict with a previous header definition.
diego
parents:
22179
diff
changeset
|
290 af_open |
7568 | 291 }; |