]> git.sesse.net Git - vlc/blob - modules/audio_filter/converter/format.c
If the audio frame allocation fails, avoid leaking the video frame.
[vlc] / modules / audio_filter / converter / format.c
1 /*****************************************************************************
2  * format.c : PCM format converter
3  *****************************************************************************
4  * Copyright (C) 2002-2005 the VideoLAN team
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
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 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 General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, 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 <assert.h>
35
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_aout.h>
39 #include <vlc_block.h>
40 #include <vlc_filter.h>
41
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 static int  Open(vlc_object_t *);
46 static void Close(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 filter", 1)
53     set_callbacks(Open, Close)
54 vlc_module_end()
55
56 /*****************************************************************************
57  * Local prototypes
58  *****************************************************************************/
59
60 static block_t *Filter(filter_t *, block_t *);
61
62 typedef block_t *(*cvt_direct_t)(filter_t *, block_t *);
63 typedef void (*cvt_indirect_t)(block_t *, const block_t *);
64 typedef void (*cvt_swap_t)(block_t *);
65
66 struct filter_sys_t {
67     cvt_swap_t     pre;
68     cvt_direct_t   directs[2];
69     cvt_indirect_t indirects[2];
70     unsigned       indirects_ratio[2][2];
71     cvt_swap_t     post;
72 };
73
74 static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst);
75 static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst);
76 static cvt_swap_t FindSwap(vlc_fourcc_t *dst, vlc_fourcc_t src);
77
78 /* */
79 static int Open(vlc_object_t *object)
80 {
81     filter_t     *filter = (filter_t *)object;
82
83     const es_format_t *src = &filter->fmt_in;
84     es_format_t       *dst = &filter->fmt_out;
85
86     if (!AOUT_FMTS_SIMILAR(&src->audio, &dst->audio))
87         return VLC_EGENERIC;
88     if (src->i_codec == dst->i_codec)
89         return VLC_EGENERIC;
90
91     cvt_direct_t direct = FindDirect(src->i_codec, dst->i_codec);
92     if (direct) {
93         filter->pf_audio_filter = direct;
94         filter->p_sys = NULL;
95         goto end;
96     }
97
98     /* */
99     filter_sys_t *sys = malloc(sizeof(*sys));
100     if (!sys)
101         return VLC_ENOMEM;
102
103     /* Find the cost minimal conversion */
104     for (unsigned mask = 0; mask <= 0x07; mask++) {
105         memset(sys, 0, sizeof(*sys));
106
107         vlc_fourcc_t fsrc = src->i_codec;
108         vlc_fourcc_t fdst = dst->i_codec;
109
110         if (mask & 0x01) {
111             sys->pre = FindSwap(&fsrc, fsrc);
112             if (!sys->pre)
113                 continue;
114         }
115         if (mask & 0x02) {
116             sys->post = FindSwap(&fdst, fdst);
117             if (!sys->post)
118                 continue;
119         }
120
121         const bool has_middle = mask & 0x04;
122         for (int i = 0; fsrc != fdst && i < 1 + has_middle; i++) {
123             /* XXX Hardcoded middle format: native 16 bits */
124             vlc_fourcc_t ftarget = has_middle && i == 0 ? VLC_CODEC_S16N : fdst;
125             sys->directs[i] = FindDirect(fsrc, ftarget);
126             if (!sys->directs[i]) {
127                 sys->indirects[i] = FindIndirect(fsrc, ftarget);
128                 if (!sys->indirects[i])
129                     break;
130                 sys->indirects_ratio[i][0] = aout_BitsPerSample(fsrc) / 8;
131                 sys->indirects_ratio[i][1] = aout_BitsPerSample(ftarget) / 8;
132             }
133             fsrc = ftarget;
134         }
135         if (fsrc != fdst)
136             continue;
137
138         /* We have a full conversion */
139         filter->pf_audio_filter = Filter;
140         filter->p_sys = sys;
141         goto end;
142     }
143     free(sys);
144     return VLC_EGENERIC;
145
146 end:
147     dst->audio = src->audio;
148     dst->audio.i_format = dst->i_codec;
149     aout_FormatPrepare(&dst->audio);
150
151     msg_Dbg(filter, "%4.4s->%4.4s, bits per sample: %i->%i",
152             (char *)&src->i_codec, (char *)&dst->i_codec,
153             src->audio.i_bitspersample, dst->audio.i_bitspersample);
154     return VLC_SUCCESS;
155 }
156
157 /* */
158 static void Close(vlc_object_t *object)
159 {
160     filter_t *filter = (filter_t *)object;
161     free(filter->p_sys);
162 }
163
164 /* */
165 static block_t *Filter(filter_t *filter, block_t *block)
166 {
167     filter_sys_t *sys = filter->p_sys;
168
169     if (sys->pre)
170         sys->pre(block);
171
172     for (int i = 0; i < 2; i++) {
173         if (sys->directs[i]) {
174             block = sys->directs[i](filter, block);
175         } else if (sys->indirects[i]) {
176             int dst_size = sys->indirects_ratio[i][1] *
177                            (block->i_buffer / sys->indirects_ratio[i][0]);
178             block_t *out = filter_NewAudioBuffer(filter, dst_size);
179             if (!out) {
180                 block_Release(block);
181                 return NULL;
182             }
183             out->i_nb_samples = block->i_nb_samples;
184             out->i_dts        = block->i_dts;
185             out->i_pts        = block->i_pts;
186             out->i_length     = block->i_length;
187             out->i_rate       = block->i_rate;
188
189             sys->indirects[i](out, block);
190
191             block_Release(block);
192             block = out;
193         }
194     }
195
196     if (sys->post)
197         sys->post(block);
198     return block;
199 }
200
201 /* */
202 static block_t *S16toS8(filter_t *filter, block_t *b)
203 {
204     VLC_UNUSED(filter);
205     int16_t *src = (int16_t *)b->p_buffer;
206     int8_t  *dst = (int8_t *)src;
207     for (int i = b->i_buffer / 2; i--;)
208         *dst++ = (*src++) >> 8;
209
210     b->i_buffer /= 2;
211     return b;
212 }
213 static block_t *S16toU8(filter_t *filter, block_t *b)
214 {
215     VLC_UNUSED(filter);
216     int16_t *src = (int16_t *)b->p_buffer;
217     uint8_t *dst = (uint8_t *)src;
218     for (int i = b->i_buffer / 2; i--;)
219         *dst++ = ((*src++) + 32768) >> 8;
220
221     b->i_buffer /= 2;
222     return b;
223 }
224 static block_t *U16toS8(filter_t *filter, block_t *b)
225 {
226     VLC_UNUSED(filter);
227     uint16_t *src = (uint16_t *)b->p_buffer;
228     int8_t   *dst = (int8_t *)src;
229     for (int i = b->i_buffer / 2; i--;)
230         *dst++ = ((int)(*src++) - 32768) >> 8;
231
232     b->i_buffer /= 2;
233     return b;
234 }
235 static block_t *U16toU8(filter_t *filter, block_t *b)
236 {
237     VLC_UNUSED(filter);
238     uint16_t *src = (uint16_t *)b->p_buffer;
239     uint8_t  *dst = (uint8_t *)src;
240     for (int i = b->i_buffer / 2; i--;)
241         *dst++ = (*src++) >> 8;
242
243     b->i_buffer /= 2;
244     return b;
245 }
246
247 static block_t *S16toU16(filter_t *filter, block_t *b)
248 {
249     VLC_UNUSED(filter);
250     int16_t *src = (int16_t *)b->p_buffer;
251     uint16_t *dst = (uint16_t *)src;
252     for (int i = b->i_buffer / 2; i--;)
253         *dst++ = (*src++) + 32768;
254
255     return b;
256 }
257
258 static block_t *U16toS16(filter_t *filter, block_t *b)
259 {
260     VLC_UNUSED(filter);
261     uint16_t *src = (uint16_t *)b->p_buffer;
262     int16_t  *dst = (int16_t *)src;
263     for (int i = b->i_buffer / 2; i--;)
264         *dst++ = (int)(*src++) - 32768;
265
266     return b;
267 }
268
269 static block_t *S8toU8(filter_t *filter, block_t *b)
270 {
271     VLC_UNUSED(filter);
272     int8_t  *src = (int8_t *)b->p_buffer;
273     uint8_t *dst = (uint8_t *)src;
274     for (int i = b->i_buffer; i--;)
275         *dst++ = ((*src++) + 128);
276
277     return b;
278 }
279 static block_t *U8toS8(filter_t *filter, block_t *b)
280 {
281     VLC_UNUSED(filter);
282     uint8_t *src = (uint8_t *)b->p_buffer;
283     int8_t  *dst = (int8_t *)src;
284     for (int i = b->i_buffer; i--;)
285         *dst++ = ((*src++) - 128);
286
287     return b;
288 }
289 static block_t *S24toS16(filter_t *filter, block_t *b)
290 {
291     VLC_UNUSED(filter);
292     uint8_t *src = (uint8_t *)b->p_buffer;
293     uint8_t *dst = (uint8_t *)src;
294     for (int i = b->i_buffer / 3; i--;) {
295 #ifdef WORDS_BIGENDIAN
296         *dst++ = *src++;
297         *dst++ = *src++;
298         src++;
299 #else
300         src++;
301         *dst++ = *src++;
302         *dst++ = *src++;
303 #endif
304     }
305
306     b->i_buffer = b->i_buffer * 2 / 3;
307     return b;
308 }
309 static block_t *S32toS16(filter_t *filter, block_t *b)
310 {
311     VLC_UNUSED(filter);
312     int32_t *src = (int32_t *)b->p_buffer;
313     int16_t *dst = (int16_t *)src;
314     for (int i = b->i_buffer / 4; i--;)
315         *dst++ = (*src++) >> 16;
316
317     b->i_buffer /= 2;
318     return b;
319 }
320 static block_t *Fl32toS16(filter_t *filter, block_t *b)
321 {
322     VLC_UNUSED(filter);
323     float   *src = (float *)b->p_buffer;
324     int16_t *dst = (int16_t *)src;
325     for (int i = b->i_buffer / 4; i--;) {
326 #if 0
327         /* Slow version. */
328         if (*src >= 1.0) *dst = 32767;
329         else if (*src < -1.0) *dst = -32768;
330         else *dst = *src * 32768.0;
331         src++; dst++;
332 #else
333         /* This is walken's trick based on IEEE float format. */
334         union { float f; int32_t i; } u;
335         u.f = *src++ + 384.0;
336         if (u.i > 0x43c07fff)
337             *dst++ = 32767;
338         else if (u.i < 0x43bf8000)
339             *dst++ = -32768;
340         else
341             *dst++ = u.i - 0x43c00000;
342 #endif
343     }
344
345     b->i_buffer /= 2;
346     return b;
347 }
348 static block_t *Fl64toS16(filter_t *filter, block_t *b)
349 {
350     VLC_UNUSED(filter);
351     double  *src = (double *)b->p_buffer;
352     int16_t *dst = (int16_t *)src;
353     for (int i = b->i_buffer / 8; i--;) {
354         const double v = *src++;
355         /* Slow version. */
356         if (v >= 1.0)
357             *dst++ = 32767;
358         else if (v < -1.0)
359             *dst++ = -32768;
360         else
361             *dst++ = v * 32768.0;
362     }
363
364     b->i_buffer /= 4;
365     return b;
366 }
367 static block_t *S32toFl32(filter_t *filter, block_t *b)
368 {
369     VLC_UNUSED(filter);
370     int32_t *src = (int32_t*)b->p_buffer;
371     float   *dst = (float *)src;
372     for (int i = b->i_buffer / 4; i--;)
373         *dst++ = (float)(*src++) / 2147483648.0;
374     return b;
375 }
376 static block_t *Fi32toFl32(filter_t *filter, block_t *b)
377 {
378     VLC_UNUSED(filter);
379     vlc_fixed_t *src = (vlc_fixed_t *)b->p_buffer;
380     float       *dst = (float *)src;
381     for (int i = b->i_buffer / 4; i--;)
382         *dst++ = *src++ / (float)FIXED32_ONE;
383     return b;
384 }
385 static block_t *Fi32toS16(filter_t *filter, block_t *b)
386 {
387     VLC_UNUSED(filter);
388     vlc_fixed_t *src = (vlc_fixed_t *)b->p_buffer;
389     int16_t     *dst = (int16_t *)src;
390     for (int i = b->i_buffer / 4; i--;) {
391         const vlc_fixed_t v = *src++;
392         if (v >= FIXED32_ONE)
393             *dst++ = INT16_MAX;
394         else if (v <= -FIXED32_ONE)
395             *dst++ = INT16_MIN;
396         else
397             *dst++ = v >> (32 - FIXED32_FRACBITS);
398     }
399     b->i_buffer /= 2;
400     return b;
401 }
402
403 /* */
404 static void X8toX16(block_t *bdst, const block_t *bsrc)
405 {
406     uint8_t  *src = (uint8_t *)bsrc->p_buffer;
407     uint16_t *dst = (uint16_t *)bdst->p_buffer;
408     for (int i = bsrc->i_buffer; i--;)
409         *dst++ = (*src++) << 8;
410 }
411 static void S8toU16(block_t *bdst, const block_t *bsrc)
412 {
413     int8_t   *src = (int8_t *)bsrc->p_buffer;
414     uint16_t *dst = (uint16_t *)bdst->p_buffer;
415     for (int i = bsrc->i_buffer; i--;)
416         *dst++ = ((*src++) + 128) << 8;
417 }
418 static void U8toS16(block_t *bdst, const block_t *bsrc)
419 {
420     uint8_t *src = (uint8_t *)bsrc->p_buffer;
421     int16_t *dst = (int16_t *)bdst->p_buffer;
422     for (int i = bsrc->i_buffer; i--;)
423         *dst++ = ((*src++) - 128) << 8;
424 }
425
426 static void S16toS24(block_t *bdst, const block_t *bsrc)
427 {
428     uint8_t *src = (uint8_t *)bsrc->p_buffer;
429     uint8_t *dst = (uint8_t *)bdst->p_buffer;
430
431     for (int i = bsrc->i_buffer / 2; i--;) {
432 #ifdef WORDS_BIGENDIAN
433         *dst++ = *src++;
434         *dst++ = *src++;
435         *dst++ = 0;
436 #else
437         *dst++ = 0;
438         *dst++ = *src++;
439         *dst++ = *src++;
440 #endif
441     }
442 }
443 static void S16toS32(block_t *bdst, const block_t *bsrc)
444 {
445     int16_t *src = (int16_t *)bsrc->p_buffer;
446     int32_t *dst = (int32_t *)bdst->p_buffer;
447     for (int i = bsrc->i_buffer / 2; i--;)
448         *dst++ = *src++ << 16;
449 }
450 static void S16toFl32(block_t *bdst, const block_t *bsrc)
451 {
452     int16_t *src = (int16_t *)bsrc->p_buffer;
453     float *dst = (float *)bdst->p_buffer;
454     for (int i = bsrc->i_buffer / 2; i--;) {
455 #if 0
456         /* Slow version */
457         *dst++ = (float)*src++ / 32768.0;
458 #else
459         /* This is walken's trick based on IEEE float format. On my PIII
460          * this takes 16 seconds to perform one billion conversions, instead
461          * of 19 seconds for the above division. */
462         union { float f; int32_t i; } u;
463         u.i = *src++ + 0x43c00000;
464         *dst++ = u.f - 384.0;
465 #endif
466     }
467 }
468 static void S24toFl32(block_t *bdst, const block_t *bsrc)
469 {
470     uint8_t *src = bsrc->p_buffer;
471     float   *dst = (float *)bdst->p_buffer;
472     for (int i = bsrc->i_buffer / 3; i--;) {
473 #ifdef WORDS_BIGENDIAN
474         int32_t v = (src[0] << 24) | (src[1] << 16) | (src[2] <<  8);
475 #else
476         int32_t v = (src[0] <<  8) | (src[1] << 16) | (src[2] << 24);
477 #endif
478         src += 3;
479         *dst++ = v / 2147483648.0;
480     }
481 }
482
483 /* */
484 #define XCHG(type, a, b) \
485     do { type _tmp = a; a = b; b = _tmp; } while(0)
486 static void Swap64(block_t *b)
487 {
488     uint8_t *data = (uint8_t *)b->p_buffer;
489     for (size_t i = 0; i < b->i_buffer / 8; i++) {
490         XCHG(uint8_t, data[0], data[7]);
491         XCHG(uint8_t, data[1], data[6]);
492         XCHG(uint8_t, data[2], data[5]);
493         XCHG(uint8_t, data[3], data[4]);
494         data += 8;
495     }
496 }
497 static void Swap32(block_t *b)
498 {
499     uint8_t *data = (uint8_t *)b->p_buffer;
500     for (size_t i = 0; i < b->i_buffer / 4; i++) {
501         XCHG(uint8_t, data[0], data[3]);
502         XCHG(uint8_t, data[1], data[2]);
503         data += 4;
504     }
505 }
506 static void Swap24(block_t *b)
507 {
508     uint8_t *data = (uint8_t *)b->p_buffer;
509     for (size_t i = 0; i < b->i_buffer / 3; i++) {
510         XCHG(uint8_t, data[0], data[2]);
511         data += 3;
512     }
513 }
514 static void Swap16(block_t *b)
515 {
516     uint8_t *data = (uint8_t *)b->p_buffer;
517     for (size_t i = 0; i < b->i_buffer / 2; i++) {
518         XCHG(uint8_t, data[0], data[1]);
519         data += 2;
520     }
521 }
522
523 /* */
524 static const struct {
525     vlc_fourcc_t src;
526     vlc_fourcc_t dst;
527     cvt_direct_t convert;
528 } cvt_directs[] = {
529     { VLC_CODEC_FL64, VLC_CODEC_S16N,   Fl64toS16 },
530     { VLC_CODEC_FI32, VLC_CODEC_FL32,   Fi32toFl32 },
531     { VLC_CODEC_FI32, VLC_CODEC_S16N,   Fi32toS16 },
532     { VLC_CODEC_S32N, VLC_CODEC_FL32,   S32toFl32 },
533
534     { VLC_CODEC_S24N, VLC_CODEC_S16N,   S24toS16 },
535     { VLC_CODEC_S32N, VLC_CODEC_S32N,   S32toS16 },
536     { VLC_CODEC_FL32, VLC_CODEC_S16N,   Fl32toS16 },
537
538     { VLC_CODEC_S16N, VLC_CODEC_S8,     S16toS8 },
539     { VLC_CODEC_S16N, VLC_CODEC_U8,     S16toU8 },
540     { VLC_CODEC_S16N, VLC_CODEC_U16N,   S16toU16 },
541
542     { VLC_CODEC_U16N, VLC_CODEC_S8,     U16toS8 },
543     { VLC_CODEC_U16N, VLC_CODEC_U8,     U16toU8 },
544     { VLC_CODEC_U16N, VLC_CODEC_S16N,   U16toS16 },
545
546     { VLC_CODEC_U8,   VLC_CODEC_S8,     U8toS8 },
547     { VLC_CODEC_S8,   VLC_CODEC_U8,     S8toU8 },
548     { 0, 0, NULL }
549 };
550
551 static const struct {
552     vlc_fourcc_t   src;
553     vlc_fourcc_t   dst;
554     cvt_indirect_t convert;
555 } cvt_indirects[] = {
556     { VLC_CODEC_S24N, VLC_CODEC_FL32, S24toFl32 },
557
558     { VLC_CODEC_S16N, VLC_CODEC_S24N, S16toS24 },
559     { VLC_CODEC_S16N, VLC_CODEC_S32N, S16toS32 },
560     { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl32 },
561
562     { VLC_CODEC_S8,   VLC_CODEC_S16N, X8toX16 },
563     { VLC_CODEC_S8,   VLC_CODEC_U16N, S8toU16 },
564
565     { VLC_CODEC_U8,   VLC_CODEC_U16N, X8toX16 },
566     { VLC_CODEC_U8,   VLC_CODEC_S16N, U8toS16 },
567     { 0, 0, NULL }
568 };
569 static const struct {
570     vlc_fourcc_t a;
571     vlc_fourcc_t b;
572     cvt_swap_t   convert;
573 } cvt_swaps[] = {
574     { VLC_CODEC_F64L, VLC_CODEC_F64B, Swap64 },
575     { VLC_CODEC_F32L, VLC_CODEC_F32B, Swap32 },
576     { VLC_CODEC_S32L, VLC_CODEC_S32B, Swap32 },
577     { VLC_CODEC_U32L, VLC_CODEC_U32B, Swap32 },
578     { VLC_CODEC_S24L, VLC_CODEC_S24B, Swap24 },
579     { VLC_CODEC_U24L, VLC_CODEC_U24B, Swap24 },
580     { VLC_CODEC_S16L, VLC_CODEC_S16B, Swap16 },
581     { VLC_CODEC_U16L, VLC_CODEC_U16B, Swap16 },
582     { 0, 0, NULL }
583 };
584
585 static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst)
586 {
587     for (int i = 0; cvt_directs[i].convert; i++) {
588         if (cvt_directs[i].src == src &&
589             cvt_directs[i].dst == dst)
590             return cvt_directs[i].convert;
591     }
592     return NULL;
593 }
594 static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst)
595 {
596     for (int i = 0; cvt_indirects[i].convert; i++) {
597         if (cvt_indirects[i].src == src &&
598             cvt_indirects[i].dst == dst)
599             return cvt_indirects[i].convert;
600     }
601     return NULL;
602 }
603 static cvt_swap_t FindSwap(vlc_fourcc_t *dst, vlc_fourcc_t src)
604 {
605     for (int i = 0; cvt_swaps[i].convert; i++) {
606         if (cvt_swaps[i].a == src) {
607             *dst = cvt_swaps[i].b;
608             return cvt_swaps[i].convert;
609         } else if (cvt_swaps[i].b == src) {
610             *dst = cvt_swaps[i].a;
611             return cvt_swaps[i].convert;
612         }
613     }
614     return NULL;
615 }
616