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