Mercurial > mplayer.hg
comparison libaf/af_export.c @ 10892:2167ac4c1d72
Adding filter for exporting audio data to visual effect applications
author | anders |
---|---|
date | Sat, 20 Sep 2003 13:42:26 +0000 |
parents | |
children | dcca52fe32bd |
comparison
equal
deleted
inserted
replaced
10891:65ed62e138fa | 10892:2167ac4c1d72 |
---|---|
1 /* This audio filter exports the incomming signal to other processes | |
2 using memory mapping. Memory mapped area contains a header: | |
3 int nch, | |
4 int size, | |
5 unsigned long long counter (updated every time the contents of | |
6 the area changes), | |
7 the rest is payload (non-interleaved). | |
8 */ | |
9 | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <string.h> | |
13 #include <inttypes.h> | |
14 #include <unistd.h> | |
15 #include <sys/types.h> | |
16 #include <sys/mman.h> | |
17 #include <sys/types.h> | |
18 #include <sys/stat.h> | |
19 #include <fcntl.h> | |
20 | |
21 #include "af.h" | |
22 | |
23 extern char * get_path( char * filename ); | |
24 | |
25 | |
26 #define DEF_SZ 512 // default buffer size (in samples) | |
27 #define SHARED_FILE "mplayer-af_export" /* default file name | |
28 (relative to ~/.mplayer/ */ | |
29 | |
30 #define SIZE_HEADER (2 * sizeof(int) + sizeof(unsigned long long)) | |
31 | |
32 // Data for specific instances of this filter | |
33 typedef struct af_export_s | |
34 { | |
35 unsigned long long count; // Used for sync | |
36 void* buf[AF_NCH]; // Buffers for storing the data before it is exported | |
37 int sz; // Size of buffer in samples | |
38 int wi; // Write index | |
39 int fd; // File descriptor to shared memory area | |
40 char* filename; // File to export data | |
41 void* mmap_area; // MMap shared area | |
42 } af_export_t; | |
43 | |
44 | |
45 /* Initialization and runtime control | |
46 af audio filter instance | |
47 cmd control command | |
48 arg argument | |
49 */ | |
50 static int control(struct af_instance_s* af, int cmd, void* arg) | |
51 { | |
52 af_export_t* s = af->setup; | |
53 switch (cmd){ | |
54 case AF_CONTROL_REINIT:{ | |
55 int i=0; | |
56 int mapsize; | |
57 | |
58 // Free previous buffers | |
59 if (s->buf && s->buf[0]) | |
60 free(s->buf[0]); | |
61 | |
62 // unmap previous area | |
63 if(s->mmap_area) | |
64 munmap(s->mmap_area, SIZE_HEADER + (af->data->bps*s->sz*af->data->nch)); | |
65 // close previous file descriptor | |
66 if(s->fd) | |
67 close(s->fd); | |
68 | |
69 // Accept only int16_t as input fomat (which sucks) | |
70 af->data->rate = ((af_data_t*)arg)->rate; | |
71 af->data->nch = ((af_data_t*)arg)->nch; | |
72 af->data->format = AF_FORMAT_SI | AF_FORMAT_NE; | |
73 af->data->bps = 2; | |
74 | |
75 // If buffer length isn't set, set it to the default value | |
76 if(s->sz == 0) | |
77 s->sz = DEF_SZ; | |
78 | |
79 // Allocate new buffers (as one continous block) | |
80 s->buf[0] = calloc(DEF_SZ*af->data->nch, af->data->bps); | |
81 if(NULL == s->buf[0]) | |
82 af_msg(AF_MSG_FATAL, "[export] Out of memory\n"); | |
83 for(i = 1; i < af->data->nch; i++) | |
84 s->buf[i] = s->buf[0] + i*DEF_SZ*af->data->bps; | |
85 | |
86 // Init memory mapping | |
87 s->fd = open(s->filename, O_RDWR | O_CREAT | O_TRUNC, 0640); | |
88 af_msg(AF_MSG_INFO, "[export] Exporting to file: %s\n", s->filename); | |
89 if(s->fd < 0) | |
90 af_msg(AF_MSG_FATAL, "[export] Could not open/create file: %s\n", | |
91 s->filename); | |
92 | |
93 // header + buffer | |
94 mapsize = (SIZE_HEADER + (af->data->bps * s->sz * af->data->nch)); | |
95 | |
96 // grow file to needed size | |
97 for(i = 0; i < mapsize; i++){ | |
98 char null = 0; | |
99 write(s->fd, (void*) &null, 1); | |
100 } | |
101 | |
102 // mmap size | |
103 s->mmap_area = mmap(0, mapsize, PROT_READ|PROT_WRITE,MAP_SHARED, s->fd, 0); | |
104 if(s->mmap_area == NULL) | |
105 af_msg(AF_MSG_FATAL, "[export] Could not mmap file %s\n", s->filename); | |
106 af_msg(AF_MSG_INFO, "[export] Memory mapped to file: %s (%p)\n", | |
107 s->filename, s->mmap_area); | |
108 | |
109 // Initialize header | |
110 *((int*)s->mmap_area) = af->data->nch; | |
111 *((int*)s->mmap_area + 1) = s->sz * af->data->bps * af->data->nch; | |
112 msync(s->mmap_area, mapsize, MS_ASYNC); | |
113 | |
114 // Use test_output to return FALSE if necessary | |
115 return af_test_output(af, (af_data_t*)arg); | |
116 } | |
117 case AF_CONTROL_COMMAND_LINE:{ | |
118 int i=0; | |
119 char *str = arg; | |
120 | |
121 if (!str){ | |
122 if(s->filename) | |
123 free(s->filename); | |
124 | |
125 s->filename = get_path(SHARED_FILE); | |
126 return AF_OK; | |
127 } | |
128 | |
129 while((str[i]) && (str[i] != ':')) | |
130 i++; | |
131 | |
132 if(s->filename) | |
133 free(s->filename); | |
134 | |
135 s->filename = calloc(i + 1, sizeof(char)); | |
136 memcpy(s->filename, str, i); | |
137 s->filename[i] = 0; | |
138 | |
139 sscanf(str + i, "%d", &(s->sz)); | |
140 | |
141 return af->control(af, AF_CONTROL_EXPORT_SZ | AF_CONTROL_SET, &s->sz); | |
142 } | |
143 case AF_CONTROL_EXPORT_SZ | AF_CONTROL_SET: | |
144 s->sz = * (int *) arg; | |
145 if((s->sz <= 0) || (s->sz > 2048)) | |
146 af_msg( AF_MSG_ERROR, "[export] Buffer size must be between" | |
147 " 1 and 2048\n" ); | |
148 | |
149 return AF_OK; | |
150 case AF_CONTROL_EXPORT_SZ | AF_CONTROL_GET: | |
151 *(int*) arg = s->sz; | |
152 return AF_OK; | |
153 | |
154 } | |
155 return AF_UNKNOWN; | |
156 } | |
157 | |
158 /* Free allocated memory and clean up other stuff too. | |
159 af audio filter instance | |
160 */ | |
161 static void uninit( struct af_instance_s* af ) | |
162 { | |
163 int i; | |
164 if (af->data){ | |
165 free(af->data); | |
166 af->data = NULL; | |
167 } | |
168 | |
169 if(af->setup){ | |
170 af_export_t* s = af->setup; | |
171 if (s->buf && s->buf[0]) | |
172 free(s->buf[0]); | |
173 | |
174 // Free mmaped area | |
175 if(s->mmap_area) | |
176 munmap(s->mmap_area, sizeof(af_export_t)); | |
177 | |
178 if(s->fd > -1) | |
179 close(s->fd); | |
180 | |
181 if(s->filename) | |
182 free(s->filename); | |
183 | |
184 free(af->setup); | |
185 af->setup = NULL; | |
186 } | |
187 } | |
188 | |
189 /* Filter data through filter | |
190 af audio filter instance | |
191 data audio data | |
192 */ | |
193 static af_data_t* play( struct af_instance_s* af, af_data_t* data ) | |
194 { | |
195 af_data_t* c = data; // Current working data | |
196 af_export_t* s = af->setup; // Setup for this instance | |
197 int16_t* a = c->audio; // Incomming sound | |
198 int nch = c->nch; // Number of channels | |
199 int len = c->len/c->bps; // Number of sample in data chunk | |
200 int sz = s->sz; // buffer size (in samples) | |
201 int flag = 0; // Set to 1 if buffer is filled | |
202 | |
203 int ch, i; | |
204 | |
205 // Fill all buffers | |
206 for(ch = 0; ch < nch; ch++){ | |
207 int wi = s->wi; // Reset write index | |
208 int16_t* b = s->buf[ch]; // Current buffer | |
209 | |
210 // Copy data to export buffers | |
211 for(i = ch; i < len; i += nch){ | |
212 b[wi++] = a[i]; | |
213 if(wi >= sz){ // Don't write outside the end of the buffer | |
214 flag = 1; | |
215 break; | |
216 } | |
217 } | |
218 s->wi = wi % s->sz; | |
219 } | |
220 | |
221 // Export buffer to mmaped area | |
222 if(flag){ | |
223 // update buffer in mapped area | |
224 memcpy(s->mmap_area + SIZE_HEADER, s->buf[0], sz * c->bps * nch); | |
225 s->count++; // increment counter (to sync) | |
226 memcpy(s->mmap_area + SIZE_HEADER - sizeof(s->count), | |
227 &(s->count), sizeof(s->count)); | |
228 } | |
229 | |
230 // We don't modify data, just export it | |
231 return data; | |
232 } | |
233 | |
234 /* Allocate memory and set function pointers | |
235 af audio filter instance | |
236 returns AF_OK or AF_ERROR | |
237 */ | |
238 static int af_open( af_instance_t* af ) | |
239 { | |
240 af->control = control; | |
241 af->uninit = uninit; | |
242 af->play = play; | |
243 af->mul.n = 1; | |
244 af->mul.d = 1; | |
245 af->data = calloc(1, sizeof(af_data_t)); | |
246 af->setup = calloc(1, sizeof(af_export_t)); | |
247 if((af->data == NULL) || (af->setup == NULL)) | |
248 return AF_ERROR; | |
249 | |
250 ((af_export_t *)af->setup)->filename = get_path(SHARED_FILE); | |
251 | |
252 return AF_OK; | |
253 } | |
254 | |
255 // Description of this filter | |
256 af_info_t af_info_export = { | |
257 "Sound export filter", | |
258 "export", | |
259 "Anders; Gustavo Sverzut Barbieri <gustavo.barbieri@ic.unicamp.br>", | |
260 "", | |
261 AF_FLAGS_REENTRANT, | |
262 af_open | |
263 }; |