1 /*
2 * Audio filter that adds and removes channels, according to the
3 * command line parameter channels. It is stupid and can only add
4 * silence or copy channels, not mix or filter.
5 *
6 * This file is part of MPlayer.
7 *
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <inttypes.h>
27
28 #include "libavutil/common.h"
29 #include "mp_msg.h"
30 #include "af.h"
31
32 #define FR 0
33 #define TO 1
34
35 typedef struct af_channels_s{
36 int route[AF_NCH][2];
37 int nr;
38 int router;
39 }af_channels_t;
40
41 // Local function for copying data
copy(void * in,void * out,int ins,int inos,int outs,int outos,int len,int bps)42 static void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps)
43 {
44 switch(bps){
45 case 1:{
46 int8_t* tin = (int8_t*)in;
47 int8_t* tout = (int8_t*)out;
48 tin += inos;
49 tout += outos;
50 len = len/ins;
51 while(len--){
52 *tout=*tin;
53 tin +=ins;
54 tout+=outs;
55 }
56 break;
57 }
58 case 2:{
59 int16_t* tin = (int16_t*)in;
60 int16_t* tout = (int16_t*)out;
61 tin += inos;
62 tout += outos;
63 len = len/(2*ins);
64 while(len--){
65 *tout=*tin;
66 tin +=ins;
67 tout+=outs;
68 }
69 break;
70 }
71 case 3:{
72 int8_t* tin = (int8_t*)in;
73 int8_t* tout = (int8_t*)out;
74 tin += 3 * inos;
75 tout += 3 * outos;
76 len = len / ( 3 * ins);
77 while (len--) {
78 tout[0] = tin[0];
79 tout[1] = tin[1];
80 tout[2] = tin[2];
81 tin += 3 * ins;
82 tout += 3 * outs;
83 }
84 break;
85 }
86 case 4:{
87 int32_t* tin = (int32_t*)in;
88 int32_t* tout = (int32_t*)out;
89 tin += inos;
90 tout += outos;
91 len = len/(4*ins);
92 while(len--){
93 *tout=*tin;
94 tin +=ins;
95 tout+=outs;
96 }
97 break;
98 }
99 case 8:{
100 int64_t* tin = (int64_t*)in;
101 int64_t* tout = (int64_t*)out;
102 tin += inos;
103 tout += outos;
104 len = len/(8*ins);
105 while(len--){
106 *tout=*tin;
107 tin +=ins;
108 tout+=outs;
109 }
110 break;
111 }
112 default:
113 mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] Unsupported number of bytes/sample: %i"
114 " please report this error on the MPlayer mailing list. \n",bps);
115 }
116 }
117
118 // Make sure the routes are sane
check_routes(af_channels_t * s,int nin,int nout)119 static int check_routes(af_channels_t* s, int nin, int nout)
120 {
121 int i;
122 if((s->nr < 1) || (s->nr > AF_NCH)){
123 mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of routing pairs must be"
124 " between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
125 return AF_ERROR;
126 }
127
128 for(i=0;i<s->nr;i++){
129 if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){
130 mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] Invalid routing in pair nr. %i.\n", i);
131 return AF_ERROR;
132 }
133 }
134 return AF_OK;
135 }
136
137 // Initialization and runtime control
control(struct af_instance_s * af,int cmd,void * arg)138 static int control(struct af_instance_s* af, int cmd, void* arg)
139 {
140 af_channels_t* s = af->setup;
141 switch(cmd){
142 case AF_CONTROL_REINIT:
143
144 // Set default channel assignment
145 if(!s->router){
146 int i;
147 // Make sure this filter isn't redundant
148 if(af->data->nch == ((af_data_t*)arg)->nch)
149 return AF_DETACH;
150
151 // If mono: fake stereo
152 if(((af_data_t*)arg)->nch == 1){
153 s->nr = FFMIN(af->data->nch,2);
154 for(i=0;i<s->nr;i++){
155 s->route[i][FR] = 0;
156 s->route[i][TO] = i;
157 }
158 }
159 else{
160 s->nr = FFMIN(af->data->nch, ((af_data_t*)arg)->nch);
161 for(i=0;i<s->nr;i++){
162 s->route[i][FR] = i;
163 s->route[i][TO] = i;
164 }
165 }
166 }
167
168 af->data->rate = ((af_data_t*)arg)->rate;
169 af->data->format = ((af_data_t*)arg)->format;
170 af->data->bps = ((af_data_t*)arg)->bps;
171 af->mul = (double)af->data->nch / ((af_data_t*)arg)->nch;
172 return check_routes(s,((af_data_t*)arg)->nch,af->data->nch);
173 case AF_CONTROL_COMMAND_LINE:{
174 int nch = 0;
175 int n = 0;
176 // Check number of channels and number of routing pairs
177 sscanf(arg, "%i:%i%n", &nch, &s->nr, &n);
178
179 // If router scan commandline for routing pairs
180 if(s->nr){
181 char* cp = &((char*)arg)[n];
182 int ch = 0;
183 // Sanity check
184 if((s->nr < 1) || (s->nr > AF_NCH)){
185 mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of routing pairs must be"
186 " between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
187 }
188 s->router = 1;
189 // Scan for pairs on commandline
190 while((*cp == ':') && (ch < s->nr)){
191 sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
192 mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Routing from channel %i to"
193 " channel %i\n",s->route[ch][FR],s->route[ch][TO]);
194 cp = &cp[n];
195 ch++;
196 }
197 }
198
199 if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch))
200 return AF_ERROR;
201 return AF_OK;
202 }
203 case AF_CONTROL_CHANNELS | AF_CONTROL_SET:
204 // Reinit must be called after this function has been called
205
206 // Sanity check
207 if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
208 mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of output channels must be"
209 " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
210 return AF_ERROR;
211 }
212
213 af->data->nch=((int*)arg)[0];
214 if(!s->router)
215 mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Changing number of channels"
216 " to %i\n",af->data->nch);
217 return AF_OK;
218 case AF_CONTROL_CHANNELS | AF_CONTROL_GET:
219 *(int*)arg = af->data->nch;
220 return AF_OK;
221 case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{
222 int ch = ((af_control_ext_t*)arg)->ch;
223 int* route = ((af_control_ext_t*)arg)->arg;
224 s->route[ch][FR] = route[FR];
225 s->route[ch][TO] = route[TO];
226 return AF_OK;
227 }
228 case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{
229 int ch = ((af_control_ext_t*)arg)->ch;
230 int* route = ((af_control_ext_t*)arg)->arg;
231 route[FR] = s->route[ch][FR];
232 route[TO] = s->route[ch][TO];
233 return AF_OK;
234 }
235 case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET:
236 s->nr = *(int*)arg;
237 return AF_OK;
238 case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET:
239 *(int*)arg = s->nr;
240 return AF_OK;
241 case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET:
242 s->router = *(int*)arg;
243 return AF_OK;
244 case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET:
245 *(int*)arg = s->router;
246 return AF_OK;
247 }
248 return AF_UNKNOWN;
249 }
250
251 // Deallocate memory
uninit(struct af_instance_s * af)252 static void uninit(struct af_instance_s* af)
253 {
254 free(af->setup);
255 if (af->data)
256 free(af->data->audio);
257 free(af->data);
258 }
259
260 // Filter data through filter
play(struct af_instance_s * af,af_data_t * data)261 static af_data_t* play(struct af_instance_s* af, af_data_t* data)
262 {
263 af_data_t* c = data; // Current working data
264 af_data_t* l = af->data; // Local data
265 af_channels_t* s = af->setup;
266 int i;
267
268 if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
269 return NULL;
270
271 // Reset unused channels
272 memset(l->audio,0,c->len / c->nch * l->nch);
273
274 if(AF_OK == check_routes(s,c->nch,l->nch))
275 for(i=0;i<s->nr;i++)
276 copy(c->audio,l->audio,c->nch,s->route[i][FR],
277 l->nch,s->route[i][TO],c->len,c->bps);
278
279 // Set output data
280 c->audio = l->audio;
281 c->len = c->len / c->nch * l->nch;
282 c->nch = l->nch;
283
284 return c;
285 }
286
287 // Allocate memory and set function pointers
af_open(af_instance_t * af)288 static int af_open(af_instance_t* af){
289 af->control=control;
290 af->uninit=uninit;
291 af->play=play;
292 af->mul=1;
293 af->data=calloc(1,sizeof(af_data_t));
294 af->setup=calloc(1,sizeof(af_channels_t));
295 if((af->data == NULL) || (af->setup == NULL))
296 return AF_ERROR;
297 return AF_OK;
298 }
299
300 // Description of this filter
301 const af_info_t af_info_channels = {
302 "Insert or remove channels",
303 "channels",
304 "Anders",
305 "",
306 AF_FLAGS_REENTRANT,
307 af_open
308 };
309