]> git.sesse.net Git - vlc/blob - modules/audio_filter/converter/a52tofloat32.c
* modules/audio_filter/converter/*: a couple of fixes for transcoding.
[vlc] / modules / audio_filter / converter / a52tofloat32.c
1 /*****************************************************************************
2  * a52tofloat32.c: ATSC A/52 aka AC-3 decoder plugin for VLC.
3  *   This plugin makes use of liba52 to decode A/52 audio
4  *   (http://liba52.sf.net/).
5  *****************************************************************************
6  * Copyright (C) 2001, 2002 VideoLAN
7  * $Id$
8  *
9  * Authors: Gildas Bazin <gbazin@videolan.org>
10  *          Christophe Massiot <massiot@via.ecp.fr>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <vlc/vlc.h>
31
32 #include <stdlib.h>                                      /* malloc(), free() */
33 #include <string.h>                                              /* strdup() */
34 #ifdef HAVE_STDINT_H
35 #   include <stdint.h>                                         /* int16_t .. */
36 #elif HAVE_INTTYPES_H
37 #   include <inttypes.h>                                       /* int16_t .. */
38 #endif
39
40 #ifdef HAVE_UNISTD_H
41 #   include <unistd.h>
42 #endif
43
44 #ifdef USE_A52DEC_TREE                                 /* liba52 header file */
45 #   include "include/a52.h"
46 #else
47 #   include "a52dec/a52.h"
48 #endif
49
50 #include <vlc/decoder.h>
51 #include "aout_internal.h"
52 #include "vlc_filter.h"
53
54 /*****************************************************************************
55  * Local prototypes
56  *****************************************************************************/
57 static int  Create    ( vlc_object_t * );
58 static void Destroy   ( vlc_object_t * );
59 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,  
60                         aout_buffer_t * );
61 static int  Open      ( vlc_object_t *, filter_sys_t *,
62                         audio_format_t, audio_format_t );
63
64 static int  OpenFilter ( vlc_object_t * );
65 static void CloseFilter( vlc_object_t * );
66 static block_t *Convert( filter_t *, block_t * );
67
68 /*****************************************************************************
69  * Local structures
70  *****************************************************************************/
71 struct filter_sys_t
72 {
73     a52_state_t * p_liba52; /* liba52 internal structure */
74     vlc_bool_t b_dynrng; /* see below */
75     int i_flags; /* liba52 flags, see a52dec/doc/liba52.txt */
76     vlc_bool_t b_dontwarn;
77     int i_nb_channels; /* number of float32 per sample */
78 };
79
80 /*****************************************************************************
81  * Module descriptor
82  *****************************************************************************/
83 #define DYNRNG_TEXT N_("A/52 dynamic range compression")
84 #define DYNRNG_LONGTEXT N_( \
85     "Dynamic range compression makes the loud sounds softer, and the soft " \
86     "sounds louder, so you can more easily listen to the stream in a noisy " \
87     "environment without disturbing anyone. If you disable the dynamic range "\
88     "compression the playback will be more adapted to a movie theater or a " \
89     "listening room.")
90
91 vlc_module_begin();
92     set_description( _("ATSC A/52 (AC-3) audio decoder") );
93     add_bool( "a52-dynrng", 1, NULL, DYNRNG_TEXT, DYNRNG_LONGTEXT, VLC_FALSE );
94     set_capability( "audio filter", 100 );
95     set_callbacks( Create, Destroy );
96
97     add_submodule();
98     set_description( _("ATSC A/52 (AC-3) audio decoder") );
99     set_capability( "audio filter2", 100 );
100     set_callbacks( OpenFilter, CloseFilter );
101 vlc_module_end();
102
103 /*****************************************************************************
104  * Create: 
105  *****************************************************************************/
106 static int Create( vlc_object_t *p_this )
107 {
108     aout_filter_t *p_filter = (aout_filter_t *)p_this;
109     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
110     int i_ret;
111
112     if ( p_filter->input.i_format != VLC_FOURCC('a','5','2',' ')
113           || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
114     {
115         return -1;
116     }
117
118     if ( p_filter->input.i_rate != p_filter->output.i_rate )
119     {
120         return -1;
121     }
122
123     /* Allocate the memory needed to store the module's structure */
124     p_sys = malloc( sizeof(filter_sys_t) );
125     p_filter->p_sys = (struct aout_filter_sys_t *)p_sys;
126     if( p_sys == NULL )
127     {
128         msg_Err( p_filter, "out of memory" );
129         return -1;
130     }
131
132     i_ret = Open( VLC_OBJECT(p_filter), p_sys,
133                   p_filter->input, p_filter->output );
134
135     p_filter->pf_do_work = DoWork;
136     p_filter->b_in_place = 0;
137
138     return i_ret;
139 }
140
141 /*****************************************************************************
142  * Open: 
143  *****************************************************************************/
144 static int Open( vlc_object_t *p_this, filter_sys_t *p_sys,
145                  audio_format_t input, audio_format_t output )
146 {
147     p_sys->b_dynrng = config_GetInt( p_this, "a52-dynrng" );
148     p_sys->b_dontwarn = 0;
149
150     /* We'll do our own downmixing, thanks. */
151     p_sys->i_nb_channels = aout_FormatNbChannels( &output );
152     switch ( (output.i_physical_channels & AOUT_CHAN_PHYSMASK)
153               & ~AOUT_CHAN_LFE )
154     {
155     case AOUT_CHAN_CENTER:
156         if ( (output.i_original_channels & AOUT_CHAN_CENTER)
157               || (output.i_original_channels
158                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
159         {
160             p_sys->i_flags = A52_MONO;
161         }
162         else if ( output.i_original_channels & AOUT_CHAN_LEFT )
163         {
164             p_sys->i_flags = A52_CHANNEL1;
165         }
166         else
167         {
168             p_sys->i_flags = A52_CHANNEL2;
169         }
170         break;
171
172     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT:
173         if ( output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
174         {
175             p_sys->i_flags = A52_DOLBY;
176         }
177         else if ( input.i_original_channels == AOUT_CHAN_CENTER )
178         {
179             p_sys->i_flags = A52_MONO;
180         }
181         else if ( input.i_original_channels & AOUT_CHAN_DUALMONO )
182         {
183             p_sys->i_flags = A52_CHANNEL;
184         }
185         else if ( !(output.i_original_channels & AOUT_CHAN_RIGHT) )
186         {
187             p_sys->i_flags = A52_CHANNEL1;
188         }
189         else if ( !(output.i_original_channels & AOUT_CHAN_LEFT) )
190         {
191             p_sys->i_flags = A52_CHANNEL2;
192         }
193         else
194         {
195             p_sys->i_flags = A52_STEREO;
196         }
197         break;
198
199     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER:
200         p_sys->i_flags = A52_3F;
201         break;
202
203     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER:
204         p_sys->i_flags = A52_2F1R;
205         break;
206
207     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
208           | AOUT_CHAN_REARCENTER:
209         p_sys->i_flags = A52_3F1R;
210         break;
211
212     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
213           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
214         p_sys->i_flags = A52_2F2R;
215         break;
216
217     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
218           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
219         p_sys->i_flags = A52_3F2R;
220         break;
221
222     default:
223         msg_Warn( p_this, "unknown sample format!" );
224         free( p_sys );
225         return VLC_EGENERIC;
226     }
227     if ( output.i_physical_channels & AOUT_CHAN_LFE )
228     {
229         p_sys->i_flags |= A52_LFE;
230     }
231     p_sys->i_flags |= A52_ADJUST_LEVEL;
232
233     /* Initialize liba52 */
234     p_sys->p_liba52 = a52_init( 0 );
235     if( p_sys->p_liba52 == NULL )
236     {
237         msg_Err( p_this, "unable to initialize liba52" );
238         free( p_sys );
239         return VLC_EGENERIC;
240     }
241
242     return VLC_SUCCESS;
243 }
244
245 /*****************************************************************************
246  * Interleave: helper function to interleave channels
247  *****************************************************************************/
248 static void Interleave( float * p_out, const float * p_in, int i_nb_channels )
249 {
250     /* We do not only have to interleave, but also reorder the channels
251      * Channel reordering according to number of output channels of libA52
252      * The reordering needs to be different for different channel configurations
253      * (3F2R, 1F2R etc), so this is only temporary.
254      * The WG-4 order is appropriate for stereo, quadrophonia, and 5.1 surround.
255      *
256      * 6 channel mode
257      * channel  liba52 order    WG-4 order
258      * 0        LFE             // L
259      * 1        L               // R
260      * 2        C               // LS
261      * 3        R               // RS
262      * 4        LS              // C
263      * 5        RS              // LFE
264      *
265      * The liba52 moves channels to the front if there are unused spaces, so
266      * there is no gap between channels. The translation table says which
267      * channel of the new stream is taken from which original channel [use
268      * the new channel as the array index, use the number you get from the
269      * array to address the original channel].
270      */
271
272     static const int translation[7][6] =
273     {{ 0, 0, 0, 0, 0, 0 },      /* 0 channels (rarely used) */
274     { 0, 0, 0, 0, 0, 0 },       /* 1 ch */
275     { 0, 1, 0, 0, 0, 0 },       /* 2 */
276     { 1, 2, 0, 0, 0, 0 },       /* 3 */
277     { 1, 3, 2, 0, 0, 0 },       /* 4 */
278     { 1, 3, 4, 2, 0, 0 },       /* 5 */
279     { 1, 3, 4, 5, 2, 0 }};      /* 6 */
280
281     int i, j;
282     for ( j = 0; j < i_nb_channels; j++ )
283     {
284         for ( i = 0; i < 256; i++ )
285         {
286             p_out[i * i_nb_channels + j] = p_in[translation[i_nb_channels][j]
287                                                  * 256 + i];
288         }
289     }
290 }
291
292 /*****************************************************************************
293  * Duplicate: helper function to duplicate a unique channel
294  *****************************************************************************/
295 static void Duplicate( float * p_out, const float * p_in )
296 {
297     int i;
298
299     for ( i = 256; i--; )
300     {
301         *p_out++ = *p_in;
302         *p_out++ = *p_in;
303         p_in++;
304     }
305 }
306
307 /*****************************************************************************
308  * Exchange: helper function to exchange left & right channels
309  *****************************************************************************/
310 static void Exchange( float * p_out, const float * p_in )
311 {
312     int i;
313     const float * p_first = p_in + 256;
314     const float * p_second = p_in;
315
316     for ( i = 0; i < 256; i++ )
317     {
318         *p_out++ = *p_first++;
319         *p_out++ = *p_second++;
320     }
321 }
322
323 /*****************************************************************************
324  * DoWork: decode an ATSC A/52 frame.
325  *****************************************************************************/
326 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
327                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
328 {
329     filter_sys_t    *p_sys = (filter_sys_t *)p_filter->p_sys;
330     sample_t        i_sample_level = 1;
331     int             i_flags = p_sys->i_flags;
332     int             i_bytes_per_block = 256 * p_sys->i_nb_channels
333                       * sizeof(float);
334     int             i;
335
336     /* Do the actual decoding now. */
337     a52_frame( p_sys->p_liba52, p_in_buf->p_buffer,
338                &i_flags, &i_sample_level, 0 );
339
340     if ( (i_flags & A52_CHANNEL_MASK) != (p_sys->i_flags & A52_CHANNEL_MASK)
341           && !p_sys->b_dontwarn )
342     {
343         msg_Warn( p_filter,
344                   "liba52 couldn't do the requested downmix 0x%x->0x%x",
345                   p_sys->i_flags  & A52_CHANNEL_MASK,
346                   i_flags & A52_CHANNEL_MASK );
347
348         p_sys->b_dontwarn = 1;
349     }
350
351     if( !p_sys->b_dynrng )
352     {
353         a52_dynrng( p_sys->p_liba52, NULL, NULL );
354     }
355
356     for ( i = 0; i < 6; i++ )
357     {
358         sample_t * p_samples;
359
360         if( a52_block( p_sys->p_liba52 ) )
361         {
362             msg_Warn( p_filter, "a52_block failed for block %d", i );
363         }
364
365         p_samples = a52_samples( p_sys->p_liba52 );
366
367         if ( ((p_sys->i_flags & A52_CHANNEL_MASK) == A52_CHANNEL1
368                || (p_sys->i_flags & A52_CHANNEL_MASK) == A52_CHANNEL2
369                || (p_sys->i_flags & A52_CHANNEL_MASK) == A52_MONO)
370               && (p_filter->output.i_physical_channels 
371                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
372         {
373             Duplicate( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
374                        p_samples );
375         }
376         else if ( p_filter->output.i_original_channels
377                     & AOUT_CHAN_REVERSESTEREO )
378         {
379             Exchange( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
380                       p_samples );
381         }
382         else
383         {
384             /* Interleave the *$£%ù samples. */
385             Interleave( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
386                         p_samples, p_sys->i_nb_channels );
387         }
388     }
389
390     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
391     p_out_buf->i_nb_bytes = i_bytes_per_block * 6;
392 }
393
394 /*****************************************************************************
395  * Destroy : deallocate data structures
396  *****************************************************************************/
397 static void Destroy( vlc_object_t *p_this )
398 {
399     aout_filter_t *p_filter = (aout_filter_t *)p_this;
400     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
401
402     a52_free( p_sys->p_liba52 );
403     free( p_sys );
404 }
405
406 /*****************************************************************************
407  * OpenFilter: 
408  *****************************************************************************/
409 static int OpenFilter( vlc_object_t *p_this )
410 {
411     filter_t *p_filter = (filter_t *)p_this;
412     filter_sys_t *p_sys;
413     int i_ret;
414
415     if( p_filter->fmt_in.i_codec != VLC_FOURCC('a','5','2',' ')  )
416     {
417         return VLC_EGENERIC;
418     }
419
420     p_filter->fmt_out.audio.i_format =
421         p_filter->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
422
423     /* Allocate the memory needed to store the module's structure */
424     p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
425     if( p_sys == NULL )
426     {
427         msg_Err( p_filter, "out of memory" );
428         return VLC_EGENERIC;
429     }
430
431     /* Allocate the memory needed to store the module's structure */
432     p_filter->p_sys = p_sys = malloc( sizeof(filter_sys_t) );
433     if( p_sys == NULL )
434     {
435         msg_Err( p_filter, "out of memory" );
436         return VLC_EGENERIC;
437     }
438
439     i_ret = Open( VLC_OBJECT(p_filter), p_sys,
440                   p_filter->fmt_in.audio, p_filter->fmt_out.audio );
441
442     p_filter->pf_audio_filter = Convert;
443
444     return i_ret;
445 }
446
447 /*****************************************************************************
448  * CloseFilter : deallocate data structures
449  *****************************************************************************/
450 static void CloseFilter( vlc_object_t *p_this )
451 {
452     filter_t *p_filter = (filter_t *)p_this;
453     filter_sys_t *p_sys = p_filter->p_sys;
454
455     a52_free( p_sys->p_liba52 );
456     free( p_sys );
457 }
458
459 static block_t *Convert( filter_t *p_filter, block_t *p_block )
460 {
461     aout_filter_t aout_filter;
462     aout_buffer_t in_buf, out_buf;
463     block_t *p_out;
464     int i_out_size;
465
466     if( !p_block || !p_block->i_samples )
467     {
468         if( p_block ) p_block->pf_release( p_block );
469         return NULL;
470     }
471
472     i_out_size = p_block->i_samples *
473       p_filter->fmt_out.audio.i_bitspersample *
474         p_filter->fmt_out.audio.i_channels / 8;
475
476     p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
477     if( !p_out )
478     {
479         msg_Warn( p_filter, "can't get output buffer" );
480         p_block->pf_release( p_block );
481         return NULL;
482     }
483
484     p_out->i_samples = p_block->i_samples;
485     p_out->i_dts = p_block->i_dts;
486     p_out->i_pts = p_block->i_pts;
487     p_out->i_length = p_block->i_length;
488
489     aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
490     aout_filter.input = p_filter->fmt_in.audio;
491     aout_filter.input.i_format = p_filter->fmt_in.i_codec;
492     aout_filter.output = p_filter->fmt_out.audio;
493     aout_filter.output.i_format = p_filter->fmt_out.i_codec;
494
495     in_buf.p_buffer = p_block->p_buffer;
496     in_buf.i_nb_bytes = p_block->i_buffer;
497     in_buf.i_nb_samples = p_block->i_samples;
498     out_buf.p_buffer = p_out->p_buffer;
499     out_buf.i_nb_bytes = p_out->i_buffer;
500     out_buf.i_nb_samples = p_out->i_samples;
501
502     DoWork( (aout_instance_t *)p_filter, &aout_filter, &in_buf, &out_buf );
503
504     p_out->i_buffer = out_buf.i_nb_bytes;
505     p_out->i_samples = out_buf.i_nb_samples;
506
507     p_block->pf_release( p_block );
508
509     return p_out;
510 }