]> git.sesse.net Git - vlc/blob - src/audio_output/filters.c
module_need wants pointers and boolean so give NULL and false instead of 0.
[vlc] / src / audio_output / filters.c
1 /*****************************************************************************
2  * filters.c : audio output filters management
3  *****************************************************************************
4  * Copyright (C) 2002-2007 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_interface.h>
33
34 #ifdef HAVE_ALLOCA_H
35 #   include <alloca.h>
36 #endif
37
38 #include <vlc_aout.h>
39 #include "aout_internal.h"
40 #include <libvlc.h>
41
42 /*****************************************************************************
43  * FindFilter: find an audio filter for a specific transformation
44  *****************************************************************************/
45 static aout_filter_t * FindFilter( aout_instance_t * p_aout,
46                              const audio_sample_format_t * p_input_format,
47                              const audio_sample_format_t * p_output_format )
48 {
49     static const char typename[] = "audio output";
50     aout_filter_t * p_filter;
51
52     p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
53                                   VLC_OBJECT_GENERIC, typename );
54
55     if ( p_filter == NULL ) return NULL;
56     vlc_object_attach( p_filter, p_aout );
57
58     memcpy( &p_filter->input, p_input_format, sizeof(audio_sample_format_t) );
59     memcpy( &p_filter->output, p_output_format,
60             sizeof(audio_sample_format_t) );
61     p_filter->p_module = module_need( p_filter, "audio filter", NULL, false );
62     if ( p_filter->p_module == NULL )
63     {
64         vlc_object_detach( p_filter );
65         vlc_object_release( p_filter );
66         return NULL;
67     }
68
69     p_filter->b_continuity = false;
70
71     return p_filter;
72 }
73
74 /*****************************************************************************
75  * SplitConversion: split a conversion in two parts
76  *****************************************************************************
77  * Returns the number of conversions required by the first part - 0 if only
78  * one conversion was asked.
79  * Beware : p_output_format can be modified during this function if the
80  * developer passed SplitConversion( toto, titi, titi, ... ). That is legal.
81  * SplitConversion( toto, titi, toto, ... ) isn't.
82  *****************************************************************************/
83 static int SplitConversion( const audio_sample_format_t * p_input_format,
84                             const audio_sample_format_t * p_output_format,
85                             audio_sample_format_t * p_middle_format )
86 {
87     bool b_format =
88              (p_input_format->i_format != p_output_format->i_format);
89     bool b_rate = (p_input_format->i_rate != p_output_format->i_rate);
90     bool b_channels =
91         (p_input_format->i_physical_channels
92           != p_output_format->i_physical_channels)
93      || (p_input_format->i_original_channels
94           != p_output_format->i_original_channels);
95     int i_nb_conversions = b_format + b_rate + b_channels;
96
97     if ( i_nb_conversions <= 1 ) return 0;
98
99     memcpy( p_middle_format, p_output_format, sizeof(audio_sample_format_t) );
100
101     if ( i_nb_conversions == 2 )
102     {
103         if ( !b_format || !b_channels )
104         {
105             p_middle_format->i_rate = p_input_format->i_rate;
106             aout_FormatPrepare( p_middle_format );
107             return 1;
108         }
109
110         /* !b_rate */
111         p_middle_format->i_physical_channels
112              = p_input_format->i_physical_channels;
113         p_middle_format->i_original_channels
114              = p_input_format->i_original_channels;
115         aout_FormatPrepare( p_middle_format );
116         return 1;
117     }
118
119     /* i_nb_conversion == 3 */
120     p_middle_format->i_rate = p_input_format->i_rate;
121     aout_FormatPrepare( p_middle_format );
122     return 2;
123 }
124
125 static void ReleaseFilter( aout_filter_t * p_filter )
126 {
127     module_unneed( p_filter, p_filter->p_module );
128     vlc_object_detach( p_filter );
129     vlc_object_release( p_filter );
130 }
131
132 /*****************************************************************************
133  * aout_FiltersCreatePipeline: create a filters pipeline to transform a sample
134  *                             format to another
135  *****************************************************************************
136  * pi_nb_filters must be initialized before calling this function
137  *****************************************************************************/
138 int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
139                                 aout_filter_t ** pp_filters_start,
140                                 int * pi_nb_filters,
141                                 const audio_sample_format_t * p_input_format,
142                                 const audio_sample_format_t * p_output_format )
143 {
144     aout_filter_t** pp_filters = pp_filters_start + *pi_nb_filters;
145     audio_sample_format_t temp_format;
146     int i_nb_conversions;
147
148     if ( AOUT_FMTS_IDENTICAL( p_input_format, p_output_format ) )
149     {
150         msg_Dbg( p_aout, "no need for any filter" );
151         return 0;
152     }
153
154     aout_FormatsPrint( p_aout, "filter(s)", p_input_format, p_output_format );
155
156     if( *pi_nb_filters + 1 > AOUT_MAX_FILTERS )
157     {
158         msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
159         intf_UserFatal( p_aout, false, _("Audio filtering failed"),
160                         _("The maximum number of filters (%d) was reached."),
161                         AOUT_MAX_FILTERS );
162         return -1;
163     }
164
165     /* Try to find a filter to do the whole conversion. */
166     pp_filters[0] = FindFilter( p_aout, p_input_format, p_output_format );
167     if ( pp_filters[0] != NULL )
168     {
169         msg_Dbg( p_aout, "found a filter for the whole conversion" );
170         ++*pi_nb_filters;
171         return 0;
172     }
173
174     /* We'll have to split the conversion. We always do the downmixing
175      * before the resampling, because the audio decoder can probably do it
176      * for us. */
177     i_nb_conversions = SplitConversion( p_input_format,
178                                         p_output_format, &temp_format );
179     if ( !i_nb_conversions )
180     {
181         /* There was only one conversion to do, and we already failed. */
182         msg_Err( p_aout, "couldn't find a filter for the conversion" );
183         return -1;
184     }
185
186     pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
187     if ( pp_filters[0] == NULL && i_nb_conversions == 2 )
188     {
189         /* Try with only one conversion. */
190         SplitConversion( p_input_format, &temp_format, &temp_format );
191         pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
192     }
193     if ( pp_filters[0] == NULL )
194     {
195         msg_Err( p_aout,
196               "couldn't find a filter for the first part of the conversion" );
197         return -1;
198     }
199
200     /* We have the first stage of the conversion. Find a filter for
201      * the rest. */
202     if( *pi_nb_filters + 2 > AOUT_MAX_FILTERS )
203     {
204         ReleaseFilter( pp_filters[0] );
205         msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
206         intf_UserFatal( p_aout, false, _("Audio filtering failed"),
207                         _("The maximum number of filters (%d) was reached."),
208                         AOUT_MAX_FILTERS );
209         return -1;
210     }
211     pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
212                                 p_output_format );
213     if ( pp_filters[1] == NULL )
214     {
215         /* Try to split the conversion. */
216         i_nb_conversions = SplitConversion( &pp_filters[0]->output,
217                                            p_output_format, &temp_format );
218         if ( !i_nb_conversions )
219         {
220             ReleaseFilter( pp_filters[0] );
221             msg_Err( p_aout,
222               "couldn't find a filter for the second part of the conversion" );
223             return -1;
224         }
225         if( *pi_nb_filters + 3 > AOUT_MAX_FILTERS )
226         {
227             ReleaseFilter( pp_filters[0] );
228             msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
229             intf_UserFatal( p_aout, false, _("Audio filtering failed"),
230                             _("The maximum number of filters (%d) was reached."),
231                             AOUT_MAX_FILTERS );
232             return -1;
233         }
234         pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
235                                     &temp_format );
236         pp_filters[2] = FindFilter( p_aout, &temp_format,
237                                     p_output_format );
238
239         if ( pp_filters[1] == NULL || pp_filters[2] == NULL )
240         {
241             ReleaseFilter( pp_filters[0] );
242             if ( pp_filters[1] != NULL )
243             {
244                 ReleaseFilter( pp_filters[1] );
245             }
246             if ( pp_filters[2] != NULL )
247             {
248                 ReleaseFilter( pp_filters[2] );
249             }
250             msg_Err( p_aout,
251                "couldn't find filters for the second part of the conversion" );
252             return -1;
253         }
254         *pi_nb_filters += 3;
255         msg_Dbg( p_aout, "found 3 filters for the whole conversion" );
256     }
257     else
258     {
259         *pi_nb_filters += 2;
260         msg_Dbg( p_aout, "found 2 filters for the whole conversion" );
261     }
262
263     return 0;
264 }
265
266 /*****************************************************************************
267  * aout_FiltersDestroyPipeline: deallocate a filters pipeline
268  *****************************************************************************/
269 void aout_FiltersDestroyPipeline( aout_instance_t * p_aout,
270                                   aout_filter_t ** pp_filters,
271                                   int i_nb_filters )
272 {
273     int i;
274     (void)p_aout;
275
276     for ( i = 0; i < i_nb_filters; i++ )
277     {
278         aout_filter_t *p_filter = pp_filters[i];
279
280         module_unneed( p_filter, p_filter->p_module );
281         free( p_filter->p_owner );
282         vlc_object_detach( p_filter );
283         vlc_object_release( p_filter );
284     }
285 }
286
287 /*****************************************************************************
288  * aout_FiltersHintBuffers: fill in aout_alloc_t structures to optimize
289  *                          buffer allocations
290  *****************************************************************************/
291 void aout_FiltersHintBuffers( aout_instance_t * p_aout,
292                               aout_filter_t ** pp_filters,
293                               int i_nb_filters, aout_alloc_t * p_first_alloc )
294 {
295     int i;
296
297     (void)p_aout; /* unused */
298
299     for ( i = i_nb_filters - 1; i >= 0; i-- )
300     {
301         aout_filter_t * p_filter = pp_filters[i];
302
303         int i_output_size = p_filter->output.i_bytes_per_frame
304                              * p_filter->output.i_rate * AOUT_MAX_INPUT_RATE
305                              / p_filter->output.i_frame_length;
306         int i_input_size = p_filter->input.i_bytes_per_frame
307                              * p_filter->input.i_rate * AOUT_MAX_INPUT_RATE
308                              / p_filter->input.i_frame_length;
309
310         p_first_alloc->i_bytes_per_sec = __MAX( p_first_alloc->i_bytes_per_sec,
311                                                 i_output_size );
312
313         if ( p_filter->b_in_place )
314         {
315             p_first_alloc->i_bytes_per_sec = __MAX(
316                                          p_first_alloc->i_bytes_per_sec,
317                                          i_input_size );
318             p_filter->output_alloc.i_alloc_type = AOUT_ALLOC_NONE;
319         }
320         else
321         {
322             /* We're gonna need a buffer allocation. */
323             memcpy( &p_filter->output_alloc, p_first_alloc,
324                     sizeof(aout_alloc_t) );
325             p_first_alloc->i_alloc_type = AOUT_ALLOC_STACK;
326             p_first_alloc->i_bytes_per_sec = i_input_size;
327         }
328     }
329 }
330
331 /*****************************************************************************
332  * aout_FiltersPlay: play a buffer
333  *****************************************************************************/
334 void aout_FiltersPlay( aout_instance_t * p_aout,
335                        aout_filter_t ** pp_filters,
336                        int i_nb_filters, aout_buffer_t ** pp_input_buffer )
337 {
338     int i;
339
340     for( i = 0; i < i_nb_filters; i++ )
341     {
342         aout_filter_t * p_filter = pp_filters[i];
343         aout_buffer_t * p_output_buffer;
344
345         /* Resamplers can produce slightly more samples than (i_in_nb *
346          * p_filter->output.i_rate / p_filter->input.i_rate) so we need
347          * slightly bigger buffers. */
348         aout_BufferAlloc( &p_filter->output_alloc,
349                           ((mtime_t)(*pp_input_buffer)->i_nb_samples + 2)
350                           * 1000000 / p_filter->input.i_rate,
351                           *pp_input_buffer, p_output_buffer );
352         if( p_output_buffer == NULL )
353             return;
354
355         /* Please note that p_output_buffer->i_nb_samples & i_nb_bytes
356          * shall be set by the filter plug-in. */
357         if( (*pp_input_buffer)->i_nb_samples > 0 )
358         {
359             p_filter->pf_do_work( p_aout, p_filter, *pp_input_buffer,
360                                   p_output_buffer );
361         }
362         else
363         {
364             p_output_buffer->i_nb_bytes = 0;
365             p_output_buffer->i_nb_samples = 0;
366         }
367
368         if( !p_filter->b_in_place )
369         {
370             aout_BufferFree( *pp_input_buffer );
371             *pp_input_buffer = p_output_buffer;
372         }
373     }
374
375     assert( (*pp_input_buffer) == NULL || (*pp_input_buffer)->i_alloc_type != AOUT_ALLOC_STACK );
376 }
377
378 /*****************************************************************************
379  * aout_filter_RequestVout
380  *****************************************************************************/
381 vout_thread_t *aout_filter_RequestVout( aout_filter_t *p_filter,
382                                         vout_thread_t *p_vout, video_format_t *p_fmt )
383 {
384     if( !p_filter->request_vout.pf_request_vout )
385         return NULL;
386     return p_filter->request_vout.pf_request_vout( p_filter->request_vout.p_private, p_vout, p_fmt );
387 }
388