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 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int Create ( vlc_object_t * );
41 static void Destroy ( vlc_object_t * );
43 static block_t *DoWork( filter_t *, block_t * );
45 /*****************************************************************************
47 *****************************************************************************/
49 set_description( N_("Simple decoder for Dolby Surround encoded streams") )
50 set_shortname( N_("Dolby Surround decoder") )
51 set_category( CAT_INPUT )
52 set_subcategory( SUBCAT_INPUT_ACODEC )
53 set_capability( "audio filter", 5 )
54 set_callbacks( Create, Destroy )
57 /*****************************************************************************
58 * Internal data structures
59 *****************************************************************************/
70 /* our internal channel order (WG-4 order) */
71 static const uint32_t pi_channels[] =
72 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
73 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
74 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
76 /*****************************************************************************
77 * Create: allocate headphone downmixer
78 *****************************************************************************/
79 static int Create( vlc_object_t *p_this )
83 filter_t * p_filter = (filter_t *)p_this;
86 /* Validate audio filter format */
87 if ( p_filter->fmt_in.audio.i_physical_channels != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
88 || ! ( p_filter->fmt_in.audio.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
89 || aout_FormatNbChannels( &p_filter->fmt_out.audio ) <= 2
90 || ( p_filter->fmt_in.audio.i_original_channels & ~AOUT_CHAN_DOLBYSTEREO )
91 != ( p_filter->fmt_out.audio.i_original_channels & ~AOUT_CHAN_DOLBYSTEREO ) )
96 if ( p_filter->fmt_in.audio.i_rate != p_filter->fmt_out.audio.i_rate )
101 if ( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32
102 || p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
107 /* Allocate the memory needed to store the module's structure */
108 p_sys = p_filter->p_sys = malloc( sizeof(*p_sys) );
112 p_sys->i_center = -1;
114 p_sys->i_rear_left = -1;
115 p_sys->i_rear_center = -1;
116 p_sys->i_rear_right = -1;
118 while ( pi_channels[i] )
120 if ( p_filter->fmt_out.audio.i_physical_channels & pi_channels[i] )
122 switch ( pi_channels[i] )
125 p_sys->i_left = i_offset;
127 case AOUT_CHAN_CENTER:
128 p_sys->i_center = i_offset;
130 case AOUT_CHAN_RIGHT:
131 p_sys->i_right = i_offset;
133 case AOUT_CHAN_REARLEFT:
134 p_sys->i_rear_left = i_offset;
136 case AOUT_CHAN_REARCENTER:
137 p_sys->i_rear_center = i_offset;
139 case AOUT_CHAN_REARRIGHT:
140 p_sys->i_rear_right = i_offset;
148 p_filter->pf_audio_filter = DoWork;
153 /*****************************************************************************
154 * Destroy: deallocate resources associated with headphone downmixer
155 *****************************************************************************/
156 static void Destroy( vlc_object_t *p_this )
158 filter_t * p_filter = (filter_t *)p_this;
159 free( p_filter->p_sys );
162 /*****************************************************************************
163 * DoWork: convert a buffer
164 *****************************************************************************/
165 static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
167 filter_sys_t * p_sys = p_filter->p_sys;
168 float * p_in = (float*) p_in_buf->p_buffer;
169 size_t i_nb_samples = p_in_buf->i_nb_samples;
170 size_t i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_out.audio );
171 size_t i_nb_rear = 0;
173 block_t *p_out_buf = filter_NewAudioBuffer( p_filter,
174 sizeof(float) * i_nb_samples * i_nb_channels );
178 float * p_out = (float*) p_out_buf->p_buffer;
179 p_out_buf->i_nb_samples = i_nb_samples;
180 p_out_buf->i_dts = p_in_buf->i_dts;
181 p_out_buf->i_pts = p_in_buf->i_pts;
182 p_out_buf->i_length = p_in_buf->i_length;
184 memset( p_out, 0, p_out_buf->i_buffer );
186 if( p_sys->i_rear_left >= 0 )
190 if( p_sys->i_rear_center >= 0 )
194 if( p_sys->i_rear_right >= 0 )
199 for( i = 0; i < i_nb_samples; ++i )
201 float f_left = p_in[ i * 2 ];
202 float f_right = p_in[ i * 2 + 1 ];
203 float f_rear = ( f_left - f_right ) / i_nb_rear;
205 if( p_sys->i_center >= 0 )
207 float f_center = f_left + f_right;
208 f_left -= f_center / 2;
209 f_right -= f_center / 2;
211 p_out[ i * i_nb_channels + p_sys->i_center ] = f_center;
214 if( p_sys->i_left >= 0 )
216 p_out[ i * i_nb_channels + p_sys->i_left ] = f_left;
218 if( p_sys->i_right >= 0 )
220 p_out[ i * i_nb_channels + p_sys->i_right ] = f_right;
222 if( p_sys->i_rear_left >= 0 )
224 p_out[ i * i_nb_channels + p_sys->i_rear_left ] = f_rear;
226 if( p_sys->i_rear_center >= 0 )
228 p_out[ i * i_nb_channels + p_sys->i_rear_center ] = f_rear;
230 if( p_sys->i_rear_right >= 0 )
232 p_out[ i * i_nb_channels + p_sys->i_rear_right ] = f_rear;
236 block_Release( p_in_buf );