1 /*****************************************************************************
2 * dolby.c : simple decoder for dolby surround encoded streams
3 *****************************************************************************
4 * Copyright (C) 2005-2009 the VideoLAN team
7 * Authors: Boris Dorès <babal@via.ecp.fr>
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)
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
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
38 /*****************************************************************************
40 *****************************************************************************/
41 static int Create ( vlc_object_t * );
42 static void Destroy ( vlc_object_t * );
44 static block_t *DoWork( filter_t *, block_t * );
46 /*****************************************************************************
48 *****************************************************************************/
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 )
58 /*****************************************************************************
59 * Internal data structures
60 *****************************************************************************/
71 /*****************************************************************************
72 * Create: allocate headphone downmixer
73 *****************************************************************************/
74 static int Create( vlc_object_t *p_this )
78 filter_t * p_filter = (filter_t *)p_this;
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 ) )
91 if ( p_filter->fmt_in.audio.i_rate != p_filter->fmt_out.audio.i_rate )
96 if ( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32
97 || p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
102 /* Allocate the memory needed to store the module's structure */
103 p_sys = p_filter->p_sys = malloc( sizeof(*p_sys) );
107 p_sys->i_center = -1;
109 p_sys->i_rear_left = -1;
110 p_sys->i_rear_center = -1;
111 p_sys->i_rear_right = -1;
113 while ( pi_vlc_chan_order_wg4[i] )
115 if ( p_filter->fmt_out.audio.i_physical_channels & pi_vlc_chan_order_wg4[i] )
117 switch ( pi_vlc_chan_order_wg4[i] )
120 p_sys->i_left = i_offset;
122 case AOUT_CHAN_CENTER:
123 p_sys->i_center = i_offset;
125 case AOUT_CHAN_RIGHT:
126 p_sys->i_right = i_offset;
128 case AOUT_CHAN_REARLEFT:
129 p_sys->i_rear_left = i_offset;
131 case AOUT_CHAN_REARCENTER:
132 p_sys->i_rear_center = i_offset;
134 case AOUT_CHAN_REARRIGHT:
135 p_sys->i_rear_right = i_offset;
143 p_filter->pf_audio_filter = DoWork;
148 /*****************************************************************************
149 * Destroy: deallocate resources associated with headphone downmixer
150 *****************************************************************************/
151 static void Destroy( vlc_object_t *p_this )
153 filter_t * p_filter = (filter_t *)p_this;
154 free( p_filter->p_sys );
157 /*****************************************************************************
158 * DoWork: convert a buffer
159 *****************************************************************************/
160 static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
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;
168 block_t *p_out_buf = block_Alloc(
169 sizeof(float) * i_nb_samples * i_nb_channels );
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;
179 memset( p_out, 0, p_out_buf->i_buffer );
181 if( p_sys->i_rear_left >= 0 )
185 if( p_sys->i_rear_center >= 0 )
189 if( p_sys->i_rear_right >= 0 )
194 for( i = 0; i < i_nb_samples; ++i )
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;
200 if( p_sys->i_center >= 0 )
202 float f_center = f_left + f_right;
203 f_left -= f_center / 2;
204 f_right -= f_center / 2;
206 p_out[ i * i_nb_channels + p_sys->i_center ] = f_center;
209 if( p_sys->i_left >= 0 )
211 p_out[ i * i_nb_channels + p_sys->i_left ] = f_left;
213 if( p_sys->i_right >= 0 )
215 p_out[ i * i_nb_channels + p_sys->i_right ] = f_right;
217 if( p_sys->i_rear_left >= 0 )
219 p_out[ i * i_nb_channels + p_sys->i_rear_left ] = f_rear;
221 if( p_sys->i_rear_center >= 0 )
223 p_out[ i * i_nb_channels + p_sys->i_rear_center ] = f_rear;
225 if( p_sys->i_rear_right >= 0 )
227 p_out[ i * i_nb_channels + p_sys->i_rear_right ] = f_rear;
231 block_Release( p_in_buf );