]> git.sesse.net Git - vlc/blob - src/audio_output/filters.c
* modules/demux/mpeg: Added DVB stream type for A/52 streams (0x6),
[vlc] / src / audio_output / filters.c
1 /*****************************************************************************
2  * filters.c : audio output filters management
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: filters.c,v 1.12 2002/10/20 12:23:48 massiot Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                            /* calloc(), malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31
32 #ifdef HAVE_ALLOCA_H
33 #   include <alloca.h> 
34 #endif
35
36 #include "audio_output.h"
37 #include "aout_internal.h"
38
39 /*****************************************************************************
40  * FindFilter: find an audio filter for a specific transformation
41  *****************************************************************************/
42 static aout_filter_t * FindFilter( aout_instance_t * p_aout,
43                              const audio_sample_format_t * p_input_format,
44                              const audio_sample_format_t * p_output_format )
45 {
46     aout_filter_t * p_filter = vlc_object_create( p_aout,
47                                                   sizeof(aout_filter_t) );
48
49     if ( p_filter == NULL ) return NULL;
50     vlc_object_attach( p_filter, p_aout );
51
52     memcpy( &p_filter->input, p_input_format, sizeof(audio_sample_format_t) );
53     memcpy( &p_filter->output, p_output_format,
54             sizeof(audio_sample_format_t) );
55     p_filter->p_module = module_Need( p_filter, "audio filter", NULL );
56     if ( p_filter->p_module == NULL )
57     {
58         vlc_object_detach( p_filter );
59         vlc_object_destroy( p_filter );
60         return NULL;
61     }
62
63     return p_filter;
64 }
65
66 /*****************************************************************************
67  * SplitConversion: split a conversion in two parts 
68  *****************************************************************************
69  * Returns the number of conversions required by the first part - 0 if only
70  * one conversion was asked.
71  * Beware : p_output_format can be modified during this function if the
72  * developer passed SplitConversion( toto, titi, titi, ... ). That is legal.
73  * SplitConversion( toto, titi, toto, ... ) isn't.
74  *****************************************************************************/
75 static int SplitConversion( aout_instance_t * p_aout,
76                              const audio_sample_format_t * p_input_format,
77                              const audio_sample_format_t * p_output_format,
78                              audio_sample_format_t * p_middle_format )
79 {
80     vlc_bool_t b_format =
81              (p_input_format->i_format != p_output_format->i_format);
82     vlc_bool_t b_rate = (p_input_format->i_rate != p_output_format->i_rate);
83     vlc_bool_t b_channels =
84              (p_input_format->i_channels != p_output_format->i_channels);
85     int i_nb_conversions = b_format + b_rate + b_channels;
86
87     if ( i_nb_conversions <= 1 ) return 0;
88
89     memcpy( p_middle_format, p_output_format, sizeof(audio_sample_format_t) );
90
91     if ( i_nb_conversions == 2 )
92     {
93         if ( !b_format || !b_channels )
94         {
95             p_middle_format->i_rate = p_input_format->i_rate;
96             return 1;
97         }
98
99         /* !b_rate */
100         p_middle_format->i_channels = p_input_format->i_channels;
101         return 1;
102     }
103
104     /* i_nb_conversion == 3 */
105     p_middle_format->i_rate = p_input_format->i_rate;
106     return 2;
107 }
108
109 /*****************************************************************************
110  * aout_FiltersCreatePipeline: create a filters pipeline to transform a sample
111  *                             format to another
112  *****************************************************************************
113  * TODO : allow the user to add/remove specific filters
114  *****************************************************************************/
115 int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
116                                 aout_filter_t ** pp_filters,
117                                 int * pi_nb_filters,
118                                 const audio_sample_format_t * p_input_format,
119                                 const audio_sample_format_t * p_output_format )
120 {
121     audio_sample_format_t temp_format;
122     int i_nb_conversions;
123
124     if ( AOUT_FMTS_IDENTICAL( p_input_format, p_output_format ) )
125     {
126         msg_Dbg( p_aout, "no need for any filter" );
127         *pi_nb_filters = 0;
128         return 0;
129     }
130
131     aout_FormatsPrint( p_aout, "filter(s)", p_input_format, p_output_format );
132
133     /* Try to find a filter to do the whole conversion. */
134     pp_filters[0] = FindFilter( p_aout, p_input_format, p_output_format );
135     if ( pp_filters[0] != NULL )
136     {
137         msg_Dbg( p_aout, "found a filter for the whole conversion" );
138         *pi_nb_filters = 1;
139         return 0;
140     }
141
142     /* We'll have to split the conversion. We always do the downmixing
143      * before the resampling, because the audio decoder can probably do it
144      * for us. */
145     i_nb_conversions = SplitConversion( p_aout, p_input_format,
146                                         p_output_format, &temp_format );
147     if ( !i_nb_conversions )
148     {
149         /* There was only one conversion to do, and we already failed. */
150         msg_Err( p_aout, "couldn't find a filter for the conversion" );
151         return -1;
152     }
153
154     pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
155     if ( pp_filters[0] == NULL && i_nb_conversions == 2 )
156     {
157         /* Try with only one conversion. */
158         SplitConversion( p_aout, p_input_format, &temp_format,
159                          &temp_format );
160         pp_filters[0] = FindFilter( p_aout, p_input_format,
161                                     &temp_format );
162     }
163     if ( pp_filters[0] == NULL )
164     {
165         msg_Err( p_aout,
166               "couldn't find a filter for the first part of the conversion" );
167         return -1;
168     }
169
170     /* We have the first stage of the conversion. Find a filter for
171      * the rest. */
172     pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
173                                 p_output_format );
174     if ( pp_filters[1] == NULL )
175     {
176         /* Try to split the conversion. */
177         i_nb_conversions = SplitConversion( p_aout,
178                                     &pp_filters[0]->output,
179                                     p_output_format, &temp_format );
180         if ( !i_nb_conversions )
181         {
182             vlc_object_detach( pp_filters[0] );
183             vlc_object_destroy( pp_filters[0] );
184             msg_Err( p_aout,
185               "couldn't find a filter for the second part of the conversion" );
186         }
187         pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
188                                     &temp_format );
189         pp_filters[2] = FindFilter( p_aout, &temp_format,
190                                     p_output_format );
191
192         if ( pp_filters[1] == NULL || pp_filters[2] == NULL )
193         {
194             vlc_object_detach( pp_filters[0] );
195             vlc_object_destroy( pp_filters[0] );
196             if ( pp_filters[1] != NULL )
197             {
198                 vlc_object_detach( pp_filters[1] );
199                 vlc_object_destroy( pp_filters[1] );
200             }
201             if ( pp_filters[2] != NULL )
202             {
203                 vlc_object_detach( pp_filters[2] );
204                 vlc_object_destroy( pp_filters[2] );
205             }
206             msg_Err( p_aout,
207                "couldn't find filters for the second part of the conversion" );
208         }
209         *pi_nb_filters = 3;
210     }
211     else
212     {
213         *pi_nb_filters = 2;
214     }
215
216     /* We have enough filters. */
217     msg_Dbg( p_aout, "found %d filters for the whole conversion",
218              *pi_nb_filters );
219     return 0;
220 }
221
222 /*****************************************************************************
223  * aout_FiltersDestroyPipeline: deallocate a filters pipeline
224  *****************************************************************************/
225 void aout_FiltersDestroyPipeline( aout_instance_t * p_aout,
226                                   aout_filter_t ** pp_filters,
227                                   int i_nb_filters )
228 {
229     int i;
230
231     for ( i = 0; i < i_nb_filters; i++ )
232     {
233         module_Unneed( pp_filters[i], pp_filters[i]->p_module );
234         vlc_object_detach( pp_filters[i] );
235         vlc_object_destroy( pp_filters[i] );
236     }
237 }
238
239 /*****************************************************************************
240  * aout_FiltersHintBuffers: fill in aout_alloc_t structures to optimize
241  *                          buffer allocations
242  *****************************************************************************/
243 void aout_FiltersHintBuffers( aout_instance_t * p_aout,
244                               aout_filter_t ** pp_filters,
245                               int i_nb_filters, aout_alloc_t * p_first_alloc )
246 {
247     int i;
248
249     for ( i = i_nb_filters - 1; i >= 0; i-- )
250     {
251         aout_filter_t * p_filter = pp_filters[i];
252
253         int i_output_size = p_filter->output.i_bytes_per_frame
254                              * p_filter->output.i_rate
255                              / p_filter->output.i_frame_length;
256         int i_input_size = p_filter->input.i_bytes_per_frame
257                              * p_filter->input.i_rate
258                              / p_filter->input.i_frame_length;
259
260         p_first_alloc->i_bytes_per_sec = __MAX( p_first_alloc->i_bytes_per_sec,
261                                                 i_output_size );
262
263         if ( p_filter->b_in_place )
264         {
265             p_first_alloc->i_bytes_per_sec = __MAX(
266                                          p_first_alloc->i_bytes_per_sec,
267                                          i_input_size );
268             p_filter->output_alloc.i_alloc_type = AOUT_ALLOC_NONE;
269         }
270         else
271         {
272             /* We're gonna need a buffer allocation. */
273             memcpy( &p_filter->output_alloc, p_first_alloc,
274                     sizeof(aout_alloc_t) );
275             p_first_alloc->i_alloc_type = AOUT_ALLOC_STACK;
276             p_first_alloc->i_bytes_per_sec = i_input_size;
277         }
278     }
279 }
280
281 /*****************************************************************************
282  * aout_FiltersPlay: play a buffer
283  *****************************************************************************/
284 void aout_FiltersPlay( aout_instance_t * p_aout,
285                        aout_filter_t ** pp_filters,
286                        int i_nb_filters, aout_buffer_t ** pp_input_buffer )
287 {
288     int i;
289
290     for ( i = 0; i < i_nb_filters; i++ )
291     {
292         aout_filter_t * p_filter = pp_filters[i];
293         aout_buffer_t * p_output_buffer;
294
295         aout_BufferAlloc( &p_filter->output_alloc,
296                           (mtime_t)(*pp_input_buffer)->i_nb_samples * 1000000
297                             / p_filter->input.i_rate, *pp_input_buffer,
298                           p_output_buffer );
299         if ( p_output_buffer == NULL )
300         {
301             msg_Err( p_aout, "out of memory" );
302             return;
303         }
304         /* Please note that p_output_buffer->i_nb_samples & i_nb_bytes
305          * shall be set by the filter plug-in. */
306
307         p_filter->pf_do_work( p_aout, p_filter, *pp_input_buffer,
308                               p_output_buffer );
309
310         if ( !p_filter->b_in_place )
311         {
312             aout_BufferFree( *pp_input_buffer );
313             *pp_input_buffer = p_output_buffer;
314         }
315     }
316 }
317