]> git.sesse.net Git - vlc/blob - modules/audio_filter/converter/format.c
bb5525292d66d0c398a852567ff9c1186866f595
[vlc] / modules / audio_filter / converter / format.c
1 /*****************************************************************************
2  * format.c : PCM format converter
3  *****************************************************************************
4  * Copyright (C) 2002-2005 VLC authors and VideoLAN
5  * Copyright (C) 2010 Laurent Aimar
6  * $Id$
7  *
8  * Authors: Christophe Massiot <massiot@via.ecp.fr>
9  *          Gildas Bazin <gbazin@videolan.org>
10  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34 #include <math.h>
35 #include <assert.h>
36
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include <vlc_aout.h>
40 #include <vlc_block.h>
41 #include <vlc_filter.h>
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 static int  Open(vlc_object_t *);
47
48 vlc_module_begin()
49     set_description(N_("Audio filter for PCM format conversion"))
50     set_category(CAT_AUDIO)
51     set_subcategory(SUBCAT_AUDIO_MISC)
52     set_capability("audio converter", 1)
53     set_callbacks(Open, NULL)
54 vlc_module_end()
55
56 /*****************************************************************************
57  * Local prototypes
58  *****************************************************************************/
59
60 typedef block_t *(*cvt_t)(filter_t *, block_t *);
61 static cvt_t FindConversion(vlc_fourcc_t src, vlc_fourcc_t dst);
62
63 static int Open(vlc_object_t *object)
64 {
65     filter_t     *filter = (filter_t *)object;
66
67     const es_format_t *src = &filter->fmt_in;
68     es_format_t       *dst = &filter->fmt_out;
69
70     if (!AOUT_FMTS_SIMILAR(&src->audio, &dst->audio))
71         return VLC_EGENERIC;
72     if (src->i_codec == dst->i_codec)
73         return VLC_EGENERIC;
74
75     filter->pf_audio_filter = FindConversion(src->i_codec, dst->i_codec);
76     if (filter->pf_audio_filter == NULL)
77         return VLC_EGENERIC;
78
79     msg_Dbg(filter, "%4.4s->%4.4s, bits per sample: %i->%i",
80             (char *)&src->i_codec, (char *)&dst->i_codec,
81             src->audio.i_bitspersample, dst->audio.i_bitspersample);
82     return VLC_SUCCESS;
83 }
84
85
86 /*** from U8 ***/
87 static block_t *U8toS16(filter_t *filter, block_t *bsrc)
88 {
89     block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
90     if (unlikely(bdst == NULL))
91         goto out;
92
93     block_CopyProperties(bdst, bsrc);
94     uint8_t *src = (uint8_t *)bsrc->p_buffer;
95     int16_t *dst = (int16_t *)bdst->p_buffer;
96     for (size_t i = bsrc->i_buffer; i--;)
97         *dst++ = ((*src++) - 128) << 8;
98 out:
99     block_Release(bsrc);
100     VLC_UNUSED(filter);
101     return bdst;
102 }
103
104 static block_t *U8toFl32(filter_t *filter, block_t *bsrc)
105 {
106     block_t *bdst = block_Alloc(bsrc->i_buffer * 4);
107     if (unlikely(bdst == NULL))
108         goto out;
109
110     block_CopyProperties(bdst, bsrc);
111     uint8_t *src = (uint8_t *)bsrc->p_buffer;
112     float   *dst = (float *)bdst->p_buffer;
113     for (size_t i = bsrc->i_buffer; i--;)
114         *dst++ = ((float)((*src++) - 128)) / 128.f;
115 out:
116     block_Release(bsrc);
117     VLC_UNUSED(filter);
118     return bdst;
119 }
120
121 static block_t *U8toS32(filter_t *filter, block_t *bsrc)
122 {
123     block_t *bdst = block_Alloc(bsrc->i_buffer * 4);
124     if (unlikely(bdst == NULL))
125         goto out;
126
127     block_CopyProperties(bdst, bsrc);
128     uint8_t *src = (uint8_t *)bsrc->p_buffer;
129     int32_t *dst = (int32_t *)bdst->p_buffer;
130     for (size_t i = bsrc->i_buffer; i--;)
131         *dst++ = ((*src++) - 128) << 24;
132 out:
133     block_Release(bsrc);
134     VLC_UNUSED(filter);
135     return bdst;
136 }
137
138 static block_t *U8toFl64(filter_t *filter, block_t *bsrc)
139 {
140     block_t *bdst = block_Alloc(bsrc->i_buffer * 8);
141     if (unlikely(bdst == NULL))
142         goto out;
143
144     block_CopyProperties(bdst, bsrc);
145     uint8_t *src = (uint8_t *)bsrc->p_buffer;
146     double  *dst = (double *)bdst->p_buffer;
147     for (size_t i = bsrc->i_buffer; i--;)
148         *dst++ = ((double)((*src++) - 128)) / 128.;
149 out:
150     block_Release(bsrc);
151     VLC_UNUSED(filter);
152     return bdst;
153 }
154
155
156 /*** from S16N ***/
157 static block_t *S16toU8(filter_t *filter, block_t *b)
158 {
159     VLC_UNUSED(filter);
160     int16_t *src = (int16_t *)b->p_buffer;
161     uint8_t *dst = (uint8_t *)src;
162     for (size_t i = b->i_buffer / 2; i--;)
163         *dst++ = ((*src++) + 32768) >> 8;
164
165     b->i_buffer /= 2;
166     return b;
167 }
168
169 static block_t *S16toFl32(filter_t *filter, block_t *bsrc)
170 {
171     block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
172     if (unlikely(bdst == NULL))
173         goto out;
174
175     block_CopyProperties(bdst, bsrc);
176     int16_t *src = (int16_t *)bsrc->p_buffer;
177     float   *dst = (float *)bdst->p_buffer;
178     for (size_t i = bsrc->i_buffer / 2; i--;)
179 #if 0
180         /* Slow version */
181         *dst++ = (float)*src++ / 32768.f;
182 #else
183     {   /* This is Walken's trick based on IEEE float format. On my PIII
184          * this takes 16 seconds to perform one billion conversions, instead
185          * of 19 seconds for the above division. */
186         union { float f; int32_t i; } u;
187         u.i = *src++ + 0x43c00000;
188         *dst++ = u.f - 384.f;
189     }
190 #endif
191 out:
192     block_Release(bsrc);
193     VLC_UNUSED(filter);
194     return bdst;
195 }
196
197 static block_t *S16toS32(filter_t *filter, block_t *bsrc)
198 {
199     block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
200     if (unlikely(bdst == NULL))
201         goto out;
202
203     block_CopyProperties(bdst, bsrc);
204     int16_t *src = (int16_t *)bsrc->p_buffer;
205     int32_t *dst = (int32_t *)bdst->p_buffer;
206     for (int i = bsrc->i_buffer / 2; i--;)
207         *dst++ = *src++ << 16;
208 out:
209     block_Release(bsrc);
210     VLC_UNUSED(filter);
211     return bdst;
212 }
213
214 static block_t *S16toFl64(filter_t *filter, block_t *bsrc)
215 {
216     block_t *bdst = block_Alloc(bsrc->i_buffer * 4);
217     if (unlikely(bdst == NULL))
218         goto out;
219
220     block_CopyProperties(bdst, bsrc);
221     int16_t *src = (int16_t *)bsrc->p_buffer;
222     float   *dst = (float *)bdst->p_buffer;
223     for (size_t i = bsrc->i_buffer / 2; i--;)
224         *dst++ = (double)*src++ / 32768.;
225 out:
226     block_Release(bsrc);
227     VLC_UNUSED(filter);
228     return bdst;
229 }
230
231
232 /*** from FL32 ***/
233 static block_t *Fl32toU8(filter_t *filter, block_t *b)
234 {
235     float   *src = (float *)b->p_buffer;
236     uint8_t *dst = (uint8_t *)src;
237     for (size_t i = b->i_buffer / 4; i--;)
238     {
239         float s = *(src++) * 128.f;
240         if (s >= 127.f)
241             *(dst++) = 255;
242         else
243         if (s <= -128.f)
244             *(dst++) = 0;
245         else
246             *(dst++) = lroundf(s) + 128;
247     }
248     b->i_buffer /= 4;
249     VLC_UNUSED(filter);
250     return b;
251 }
252
253 static block_t *Fl32toS16(filter_t *filter, block_t *b)
254 {
255     VLC_UNUSED(filter);
256     float   *src = (float *)b->p_buffer;
257     int16_t *dst = (int16_t *)src;
258     for (int i = b->i_buffer / 4; i--;) {
259 #if 0
260         /* Slow version. */
261         if (*src >= 1.0) *dst = 32767;
262         else if (*src < -1.0) *dst = -32768;
263         else *dst = lroundf(*src * 32768.f);
264         src++; dst++;
265 #else
266         /* This is Walken's trick based on IEEE float format. */
267         union { float f; int32_t i; } u;
268         u.f = *src++ + 384.f;
269         if (u.i > 0x43c07fff)
270             *dst++ = 32767;
271         else if (u.i < 0x43bf8000)
272             *dst++ = -32768;
273         else
274             *dst++ = u.i - 0x43c00000;
275 #endif
276     }
277     b->i_buffer /= 2;
278     return b;
279 }
280
281 static block_t *Fl32toS32(filter_t *filter, block_t *b)
282 {
283     float   *src = (float *)b->p_buffer;
284     int32_t *dst = (int32_t *)src;
285     for (size_t i = b->i_buffer / 4; i--;)
286     {
287         float s = *(src++) * 2147483648.f;
288         if (s >= 2147483647.f)
289             *(dst++) = 2147483647;
290         else
291         if (s <= -2147483648.f)
292             *(dst++) = -2147483648;
293         else
294             *(dst++) = lroundf(s);
295     }
296     VLC_UNUSED(filter);
297     return b;
298 }
299
300 static block_t *Fl32toFl64(filter_t *filter, block_t *bsrc)
301 {
302     block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
303     if (unlikely(bdst == NULL))
304         goto out;
305
306     block_CopyProperties(bdst, bsrc);
307     float  *src = (float *)bsrc->p_buffer;
308     double *dst = (double *)bdst->p_buffer;
309     for (size_t i = bsrc->i_buffer / 4; i--;)
310         *(dst++) = *(src++);
311 out:
312     block_Release(bsrc);
313     VLC_UNUSED(filter);
314     return bdst;
315 }
316
317
318 /*** from S32N ***/
319 static block_t *S32toU8(filter_t *filter, block_t *b)
320 {
321     VLC_UNUSED(filter);
322     int32_t *src = (int32_t *)b->p_buffer;
323     uint8_t *dst = (uint8_t *)src;
324     for (size_t i = b->i_buffer / 4; i--;)
325         *dst++ = ((*src++) >> 24) + 128;
326
327     b->i_buffer /= 4;
328     return b;
329 }
330
331 static block_t *S32toS16(filter_t *filter, block_t *b)
332 {
333     VLC_UNUSED(filter);
334     int32_t *src = (int32_t *)b->p_buffer;
335     int16_t *dst = (int16_t *)src;
336     for (size_t i = b->i_buffer / 4; i--;)
337         *dst++ = (*src++) >> 16;
338
339     b->i_buffer /= 2;
340     return b;
341 }
342
343 static block_t *S32toFl32(filter_t *filter, block_t *b)
344 {
345     VLC_UNUSED(filter);
346     int32_t *src = (int32_t*)b->p_buffer;
347     float   *dst = (float *)src;
348     for (int i = b->i_buffer / 4; i--;)
349         *dst++ = (float)(*src++) / 2147483648.f;
350     return b;
351 }
352
353 static block_t *S32toFl64(filter_t *filter, block_t *bsrc)
354 {
355     block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
356     if (unlikely(bdst == NULL))
357         goto out;
358
359     block_CopyProperties(bdst, bsrc);
360     int32_t *src = (int32_t*)bsrc->p_buffer;
361     double  *dst = (double *)bdst->p_buffer;
362     for (size_t i = bsrc->i_buffer / 4; i--;)
363         *dst++ = (double)(*src++) / 2147483648.;
364 out:
365     VLC_UNUSED(filter);
366     block_Release(bsrc);
367     return bdst;
368 }
369
370
371 /*** from FL64 ***/
372 static block_t *Fl64toU8(filter_t *filter, block_t *b)
373 {
374     double  *src = (double *)b->p_buffer;
375     uint8_t *dst = (uint8_t *)src;
376     for (size_t i = b->i_buffer / 8; i--;)
377     {
378         float s = *(src++) * 128.;
379         if (s >= 127.f)
380             *(dst++) = 255;
381         else
382         if (s <= -128.f)
383             *(dst++) = 0;
384         else
385             *(dst++) = lround(s) + 128;
386     }
387     b->i_buffer /= 8;
388     VLC_UNUSED(filter);
389     return b;
390 }
391
392 static block_t *Fl64toS16(filter_t *filter, block_t *b)
393 {
394     VLC_UNUSED(filter);
395     double  *src = (double *)b->p_buffer;
396     int16_t *dst = (int16_t *)src;
397     for (size_t i = b->i_buffer / 8; i--;) {
398         const double v = *src++ * 32768.;
399         /* Slow version. */
400         if (v >= 32767.)
401             *dst++ = 32767;
402         else if (v < -32768.)
403             *dst++ = -32768;
404         else
405             *dst++ = lround(v);
406     }
407     b->i_buffer /= 4;
408     return b;
409 }
410
411 static block_t *Fl64toFl32(filter_t *filter, block_t *b)
412 {
413     double *src = (double *)b->p_buffer;
414     float  *dst = (float *)src;
415     for (size_t i = b->i_buffer / 8; i--;)
416         *(dst++) = *(src++);
417
418     VLC_UNUSED(filter);
419     return b;
420 }
421
422 static block_t *Fl64toS32(filter_t *filter, block_t *b)
423 {
424     double  *src = (double *)b->p_buffer;
425     int32_t *dst = (int32_t *)src;
426     for (size_t i = b->i_buffer / 8; i--;)
427     {
428         float s = *(src++) * 2147483648.;
429         if (s >= 2147483647.f)
430             *(dst++) = 2147483647;
431         else
432         if (s <= -2147483648.f)
433             *(dst++) = -2147483648;
434         else
435             *(dst++) = lround(s);
436     }
437     VLC_UNUSED(filter);
438     return b;
439 }
440
441
442 /* */
443 /* */
444 static const struct {
445     vlc_fourcc_t src;
446     vlc_fourcc_t dst;
447     cvt_t convert;
448 } cvt_directs[] = {
449     { VLC_CODEC_U8,   VLC_CODEC_S16N, U8toS16    },
450     { VLC_CODEC_U8,   VLC_CODEC_FL32, U8toFl32   },
451     { VLC_CODEC_U8,   VLC_CODEC_S32N, U8toS32    },
452     { VLC_CODEC_U8,   VLC_CODEC_FL64, U8toFl64   },
453
454     { VLC_CODEC_S16N, VLC_CODEC_U8,   S16toU8    },
455     { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl32  },
456     { VLC_CODEC_S16N, VLC_CODEC_S32N, S16toS32   },
457     { VLC_CODEC_S16N, VLC_CODEC_FL64, S16toFl64  },
458
459     { VLC_CODEC_FL32, VLC_CODEC_U8,   Fl32toU8   },
460     { VLC_CODEC_FL32, VLC_CODEC_S16N, Fl32toS16  },
461     { VLC_CODEC_FL32, VLC_CODEC_S32N, Fl32toS32  },
462     { VLC_CODEC_FL32, VLC_CODEC_FL64, Fl32toFl64 },
463
464     { VLC_CODEC_S32N, VLC_CODEC_U8,   S32toU8    },
465     { VLC_CODEC_S32N, VLC_CODEC_S16N, S32toS16   },
466     { VLC_CODEC_S32N, VLC_CODEC_FL32, S32toFl32  },
467     { VLC_CODEC_S32N, VLC_CODEC_FL64, S32toFl64  },
468
469     { VLC_CODEC_FL64, VLC_CODEC_U8,   Fl64toU8   },
470     { VLC_CODEC_FL64, VLC_CODEC_S16N, Fl64toS16  },
471     { VLC_CODEC_FL64, VLC_CODEC_FL32, Fl64toFl32 },
472     { VLC_CODEC_FL64, VLC_CODEC_S32N, Fl64toS32  },
473
474     { 0, 0, NULL }
475 };
476
477 static cvt_t FindConversion(vlc_fourcc_t src, vlc_fourcc_t dst)
478 {
479     for (int i = 0; cvt_directs[i].convert; i++) {
480         if (cvt_directs[i].src == src &&
481             cvt_directs[i].dst == dst)
482             return cvt_directs[i].convert;
483     }
484     return NULL;
485 }