1 /*****************************************************************************
2 * dolby.c : simple decoder for dolby surround encoded streams
3 *****************************************************************************
4 * Copyright (C) 2005-2009 the VideoLAN team
5 * $Id: 5e4f966a09158e1023c69a52f91cd8e0f549f0b1 $
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 *****************************************************************************/
Create(vlc_object_t * p_this)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_chan_mode & AOUT_CHANMODE_DOLBYSTEREO )
84 || p_filter->fmt_out.audio.i_channels <= 2
85 || ( p_filter->fmt_in.audio.i_chan_mode & ~AOUT_CHANMODE_DOLBYSTEREO )
86 != ( p_filter->fmt_out.audio.i_chan_mode & ~AOUT_CHANMODE_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 *****************************************************************************/
Destroy(vlc_object_t * p_this)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 *****************************************************************************/
DoWork(filter_t * p_filter,block_t * p_in_buf)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 }
234