]> git.sesse.net Git - vlc/blob - modules/audio_filter/channel_mixer/dolby.c
vlc_plugin: fix non-LGPL plugins meta infos
[vlc] / modules / audio_filter / channel_mixer / dolby.c
1 /*****************************************************************************
2  * dolby.c : simple decoder for dolby surround encoded streams
3  *****************************************************************************
4  * Copyright (C) 2005-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Boris Dorès <babal@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the Free
11  * Software Foundation; either version 2 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program; if not, write to the Free Software Foundation, Inc., 51
21  * Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_aout.h>
36 #include <vlc_filter.h>
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static int  Create    ( vlc_object_t * );
42 static void Destroy   ( vlc_object_t * );
43
44 static block_t *DoWork( filter_t *, block_t * );
45
46 /*****************************************************************************
47  * Module descriptor
48  *****************************************************************************/
49 vlc_module_begin ()
50     set_description( N_("Simple decoder for Dolby Surround encoded streams") )
51     set_shortname( N_("Dolby Surround decoder") )
52     set_category( CAT_INPUT )
53     set_subcategory( SUBCAT_INPUT_ACODEC )
54     set_capability( "audio converter", 5 )
55     set_callbacks( Create, Destroy )
56 vlc_module_end ()
57
58 /*****************************************************************************
59  * Internal data structures
60  *****************************************************************************/
61 struct filter_sys_t
62 {
63     int i_left;
64     int i_center;
65     int i_right;
66     int i_rear_left;
67     int i_rear_center;
68     int i_rear_right;
69 };
70
71 /*****************************************************************************
72  * Create: allocate headphone downmixer
73  *****************************************************************************/
74 static int Create( vlc_object_t *p_this )
75 {
76     int i = 0;
77     int i_offset = 0;
78     filter_t * p_filter = (filter_t *)p_this;
79     filter_sys_t *p_sys;
80
81     /* Validate audio filter format */
82     if ( p_filter->fmt_in.audio.i_physical_channels != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
83        || ! ( p_filter->fmt_in.audio.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
84        || aout_FormatNbChannels( &p_filter->fmt_out.audio ) <= 2
85        || ( p_filter->fmt_in.audio.i_original_channels & ~AOUT_CHAN_DOLBYSTEREO )
86           != ( p_filter->fmt_out.audio.i_original_channels & ~AOUT_CHAN_DOLBYSTEREO ) )
87     {
88         return VLC_EGENERIC;
89     }
90
91     if ( p_filter->fmt_in.audio.i_rate != p_filter->fmt_out.audio.i_rate )
92     {
93         return VLC_EGENERIC;
94     }
95
96     if ( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32
97           || p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
98     {
99         return VLC_EGENERIC;
100     }
101
102     /* Allocate the memory needed to store the module's structure */
103     p_sys = p_filter->p_sys = malloc( sizeof(*p_sys) );
104     if( p_sys == NULL )
105         return VLC_ENOMEM;
106     p_sys->i_left = -1;
107     p_sys->i_center = -1;
108     p_sys->i_right = -1;
109     p_sys->i_rear_left = -1;
110     p_sys->i_rear_center = -1;
111     p_sys->i_rear_right = -1;
112
113     while ( pi_vlc_chan_order_wg4[i] )
114     {
115         if ( p_filter->fmt_out.audio.i_physical_channels & pi_vlc_chan_order_wg4[i] )
116         {
117             switch ( pi_vlc_chan_order_wg4[i] )
118             {
119                 case AOUT_CHAN_LEFT:
120                     p_sys->i_left = i_offset;
121                     break;
122                 case AOUT_CHAN_CENTER:
123                     p_sys->i_center = i_offset;
124                     break;
125                 case AOUT_CHAN_RIGHT:
126                     p_sys->i_right = i_offset;
127                     break;
128                 case AOUT_CHAN_REARLEFT:
129                     p_sys->i_rear_left = i_offset;
130                     break;
131                 case AOUT_CHAN_REARCENTER:
132                     p_sys->i_rear_center = i_offset;
133                     break;
134                 case AOUT_CHAN_REARRIGHT:
135                     p_sys->i_rear_right = i_offset;
136                     break;
137             }
138             ++i_offset;
139         }
140         ++i;
141     }
142
143     p_filter->pf_audio_filter = DoWork;
144
145     return VLC_SUCCESS;
146 }
147
148 /*****************************************************************************
149  * Destroy: deallocate resources associated with headphone downmixer
150  *****************************************************************************/
151 static void Destroy( vlc_object_t *p_this )
152 {
153     filter_t * p_filter = (filter_t *)p_this;
154     free( p_filter->p_sys );
155 }
156
157 /*****************************************************************************
158  * DoWork: convert a buffer
159  *****************************************************************************/
160 static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
161 {
162     filter_sys_t * p_sys = p_filter->p_sys;
163     float * p_in = (float*) p_in_buf->p_buffer;
164     size_t i_nb_samples = p_in_buf->i_nb_samples;
165     size_t i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_out.audio );
166     size_t i_nb_rear = 0;
167     size_t i;
168     block_t *p_out_buf = block_Alloc(
169                                 sizeof(float) * i_nb_samples * i_nb_channels );
170     if( !p_out_buf )
171         goto out;
172
173     float * p_out = (float*) p_out_buf->p_buffer;
174     p_out_buf->i_nb_samples = i_nb_samples;
175     p_out_buf->i_dts        = p_in_buf->i_dts;
176     p_out_buf->i_pts        = p_in_buf->i_pts;
177     p_out_buf->i_length     = p_in_buf->i_length;
178
179     memset( p_out, 0, p_out_buf->i_buffer );
180
181     if( p_sys->i_rear_left >= 0 )
182     {
183         ++i_nb_rear;
184     }
185     if( p_sys->i_rear_center >= 0 )
186     {
187         ++i_nb_rear;
188     }
189     if( p_sys->i_rear_right >= 0 )
190     {
191         ++i_nb_rear;
192     }
193
194     for( i = 0; i < i_nb_samples; ++i )
195     {
196         float f_left = p_in[ i * 2 ];
197         float f_right = p_in[ i * 2 + 1 ];
198         float f_rear = ( f_left - f_right ) / i_nb_rear;
199
200         if( p_sys->i_center >= 0 )
201         {
202             float f_center = f_left + f_right;
203             f_left -= f_center / 2;
204             f_right -= f_center / 2;
205
206             p_out[ i * i_nb_channels + p_sys->i_center ] = f_center;
207         }
208
209         if( p_sys->i_left >= 0 )
210         {
211             p_out[ i * i_nb_channels + p_sys->i_left ] = f_left;
212         }
213         if( p_sys->i_right >= 0 )
214         {
215             p_out[ i * i_nb_channels + p_sys->i_right ] = f_right;
216         }
217         if( p_sys->i_rear_left >= 0 )
218         {
219             p_out[ i * i_nb_channels + p_sys->i_rear_left ] = f_rear;
220         }
221         if( p_sys->i_rear_center >= 0 )
222         {
223             p_out[ i * i_nb_channels + p_sys->i_rear_center ] = f_rear;
224         }
225         if( p_sys->i_rear_right >= 0 )
226         {
227             p_out[ i * i_nb_channels + p_sys->i_rear_right ] = f_rear;
228         }
229     }
230 out:
231     block_Release( p_in_buf );
232     return p_out_buf;
233 }