Mercurial > mplayer.hg
annotate libaf/af_channels.c @ 26360:a48df598c055
Split cfg-common.h into two separate header files. It was being included twice
with different definitions set that activated either the lower or the upper
half of the header. The effectively simulated using two different header files.
It is more straightforward to split the header instead.
author | diego |
---|---|
date | Fri, 11 Apr 2008 09:48:36 +0000 |
parents | b2402b4f0afa |
children | 72d0b1444141 |
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; | |
24888 | 151 af->mul = (double)af->data->nch / ((af_data_t*)arg)->nch; |
8607 | 152 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
|
153 case AF_CONTROL_COMMAND_LINE:{ |
d48a06d07afb
Adding commandline options for filters and fixing stupid bug in cfg
anders
parents:
7975
diff
changeset
|
154 int nch = 0; |
8607 | 155 int n = 0; |
156 // Check number of channels and number of routing pairs | |
157 sscanf(arg, "%i:%i%n", &nch, &s->nr, &n); | |
158 | |
159 // If router scan commandline for routing pairs | |
160 if(s->nr){ | |
161 char* cp = &((char*)arg)[n]; | |
162 int ch = 0; | |
163 // Sanity check | |
164 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
|
165 af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs must be" |
8607 | 166 " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); |
167 } | |
168 s->router = 1; | |
169 // Scan for pairs on commandline | |
170 while((*cp == ':') && (ch < s->nr)){ | |
171 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
|
172 af_msg(AF_MSG_VERBOSE,"[channels] Routing from channel %i to" |
8607 | 173 " channel %i\n",s->route[ch][FR],s->route[ch][TO]); |
174 cp = &cp[n]; | |
175 ch++; | |
176 } | |
177 } | |
178 | |
179 if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch)) | |
180 return AF_ERROR; | |
181 return AF_OK; | |
182 } | |
183 case AF_CONTROL_CHANNELS | AF_CONTROL_SET: | |
7568 | 184 // Reinit must be called after this function has been called |
185 | |
186 // Sanity check | |
12008 | 187 if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){ |
8607 | 188 af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be" |
189 " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]); | |
7568 | 190 return AF_ERROR; |
191 } | |
192 | |
193 af->data->nch=((int*)arg)[0]; | |
8607 | 194 if(!s->router) |
195 af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels" | |
196 " to %i\n",af->data->nch); | |
197 return AF_OK; | |
198 case AF_CONTROL_CHANNELS | AF_CONTROL_GET: | |
199 *(int*)arg = af->data->nch; | |
200 return AF_OK; | |
201 case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{ | |
202 int ch = ((af_control_ext_t*)arg)->ch; | |
203 int* route = ((af_control_ext_t*)arg)->arg; | |
204 s->route[ch][FR] = route[FR]; | |
205 s->route[ch][TO] = route[TO]; | |
206 return AF_OK; | |
207 } | |
208 case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{ | |
209 int ch = ((af_control_ext_t*)arg)->ch; | |
210 int* route = ((af_control_ext_t*)arg)->arg; | |
211 route[FR] = s->route[ch][FR]; | |
212 route[TO] = s->route[ch][TO]; | |
213 return AF_OK; | |
214 } | |
215 case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET: | |
216 s->nr = *(int*)arg; | |
217 return AF_OK; | |
218 case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET: | |
219 *(int*)arg = s->nr; | |
220 return AF_OK; | |
221 case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET: | |
222 s->router = *(int*)arg; | |
223 return AF_OK; | |
224 case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET: | |
225 *(int*)arg = s->router; | |
7568 | 226 return AF_OK; |
227 } | |
228 return AF_UNKNOWN; | |
229 } | |
230 | |
231 // Deallocate memory | |
232 static void uninit(struct af_instance_s* af) | |
233 { | |
22179 | 234 free(af->setup); |
235 if (af->data) | |
236 free(af->data->audio); | |
237 free(af->data); | |
7568 | 238 } |
239 | |
240 // Filter data through filter | |
241 static af_data_t* play(struct af_instance_s* af, af_data_t* data) | |
242 { | |
8607 | 243 af_data_t* c = data; // Current working data |
244 af_data_t* l = af->data; // Local data | |
245 af_channels_t* s = af->setup; | |
246 int i; | |
247 | |
7568 | 248 if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) |
249 return NULL; | |
250 | |
8607 | 251 // Reset unused channels |
24888 | 252 memset(l->audio,0,c->len / c->nch * l->nch); |
7568 | 253 |
8607 | 254 if(AF_OK == check_routes(s,c->nch,l->nch)) |
255 for(i=0;i<s->nr;i++) | |
256 copy(c->audio,l->audio,c->nch,s->route[i][FR], | |
257 l->nch,s->route[i][TO],c->len,c->bps); | |
7568 | 258 |
259 // Set output data | |
260 c->audio = l->audio; | |
24888 | 261 c->len = c->len / c->nch * l->nch; |
7568 | 262 c->nch = l->nch; |
263 | |
264 return c; | |
265 } | |
266 | |
267 // 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
|
268 static int af_open(af_instance_t* af){ |
7568 | 269 af->control=control; |
270 af->uninit=uninit; | |
271 af->play=play; | |
24888 | 272 af->mul=1; |
7568 | 273 af->data=calloc(1,sizeof(af_data_t)); |
8607 | 274 af->setup=calloc(1,sizeof(af_channels_t)); |
275 if((af->data == NULL) || (af->setup == NULL)) | |
7568 | 276 return AF_ERROR; |
277 return AF_OK; | |
278 } | |
279 | |
280 // Description of this filter | |
281 af_info_t af_info_channels = { | |
282 "Insert or remove channels", | |
283 "channels", | |
284 "Anders", | |
285 "", | |
7615 | 286 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
|
287 af_open |
7568 | 288 }; |