]> git.sesse.net Git - vlc/blob - src/audio_output/filters.c
Audio output 3. Expect major breakages.
[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.1 2002/08/07 21:36:56 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 #ifdef HAVE_ALLOCA_H
30 #   include <alloca.h> 
31 #endif
32
33 #include <vlc/vlc.h>
34
35 #include "audio_output.h"
36 #include "aout_internal.h"
37
38 /*****************************************************************************
39  * aout_FiltersCreatePipeline: create a filters pipeline to transform a sample
40  *                             format to another
41  *****************************************************************************
42  * TODO : allow the user to add/remove specific filters
43  *****************************************************************************/
44 int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
45                                 aout_filter_t ** pp_filters,
46                                 int * pi_nb_filters,
47                                 audio_sample_format_t * p_input_format,
48                                 audio_sample_format_t * p_output_format )
49 {
50     if ( AOUT_FMTS_IDENTICAL( p_input_format, p_output_format ) )
51     {
52         msg_Dbg( p_aout, "no need for any filter" );
53         *pi_nb_filters = 0;
54         return 0;
55     }
56
57     pp_filters[0] = vlc_object_create( p_aout, sizeof(aout_filter_t) );
58     if ( pp_filters[0] == NULL )
59     {
60         return -1;
61     }
62     vlc_object_attach( pp_filters[0], p_aout );
63
64     /* Try to find a filter to do the whole conversion. */
65     memcpy( &pp_filters[0]->input, p_input_format,
66             sizeof(audio_sample_format_t) );
67     memcpy( &pp_filters[0]->output, p_output_format,
68             sizeof(audio_sample_format_t) );
69     pp_filters[0]->p_module = module_Need( pp_filters[0], "audio filter",
70                                            NULL );
71     if ( pp_filters[0]->p_module != NULL )
72     {
73         msg_Dbg( p_aout, "found a filter for the whole conversion" );
74         *pi_nb_filters = 1;
75         return 0;
76     }
77
78     /* Split the conversion : format | rate, or rate | format. */
79     pp_filters[0]->output.i_format = pp_filters[0]->input.i_format;
80     pp_filters[0]->p_module = module_Need( pp_filters[0], "audio filter",
81                                            NULL );
82     if ( pp_filters[0]->p_module == NULL )
83     {
84         /* Then, start with the format conversion. */
85         memcpy( &pp_filters[0]->output, p_output_format,
86                 sizeof(audio_sample_format_t) );
87         pp_filters[0]->output.i_rate = pp_filters[0]->input.i_rate;
88         pp_filters[0]->p_module = module_Need( pp_filters[0], "audio filter",
89                                                NULL );
90         if ( pp_filters[0]->p_module == NULL )
91         {
92             msg_Err( p_aout, "couldn't find a filter for any conversion" );
93             vlc_object_detach_all( pp_filters[0] );
94             vlc_object_destroy( pp_filters[0] );
95             return -1;
96         }
97     }
98
99     /* Find a filter for the rest. */
100     pp_filters[1] = vlc_object_create( p_aout, sizeof(aout_filter_t) );
101     if ( pp_filters[1] == NULL )
102     {
103         vlc_object_detach_all( pp_filters[0] );
104         vlc_object_destroy( pp_filters[0] );
105         return -1;
106     }
107     vlc_object_attach( pp_filters[1], p_aout );
108
109     memcpy( &pp_filters[1]->input, &pp_filters[0]->output,
110             sizeof(audio_sample_format_t) );
111     memcpy( &pp_filters[1]->output, p_output_format,
112             sizeof(audio_sample_format_t) );
113     pp_filters[1]->p_module = module_Need( pp_filters[1], "audio filter",
114                                            NULL );
115     if ( pp_filters[1]->p_module == NULL )
116     {
117         msg_Err( p_aout,
118                  "couldn't find a filter for the 2nd part of the conversion" );
119         vlc_object_detach_all( pp_filters[0] );
120         vlc_object_destroy( pp_filters[0] );
121         vlc_object_detach_all( pp_filters[1] );
122         vlc_object_destroy( pp_filters[1] );
123         return -1;
124     }
125
126     msg_Dbg( p_aout, "filter pipeline made of two filters" );
127     *pi_nb_filters = 2;
128
129     return 0;
130 }
131
132 /*****************************************************************************
133  * aout_FiltersDestroyPipeline: deallocate a filters pipeline
134  *****************************************************************************/
135 void aout_FiltersDestroyPipeline( aout_instance_t * p_aout,
136                                   aout_filter_t ** pp_filters,
137                                   int i_nb_filters )
138 {
139     int i;
140
141     for ( i = 0; i < i_nb_filters; i++ )
142     {
143         module_Unneed( pp_filters[i], pp_filters[i]->p_module );
144         vlc_object_detach_all( pp_filters[i] );
145         vlc_object_destroy( pp_filters[i] );
146     }
147 }
148
149 /*****************************************************************************
150  * aout_FiltersHintBuffers: fill in aout_alloc_t structures to optimize
151  *                          buffer allocations
152  *****************************************************************************/
153 void aout_FiltersHintBuffers( aout_instance_t * p_aout,
154                               aout_filter_t ** pp_filters,
155                               int i_nb_filters, aout_alloc_t * p_first_alloc )
156 {
157     int i;
158
159     for ( i = i_nb_filters - 1; i >= 0; i-- )
160     {
161         aout_filter_t * p_filter = pp_filters[i];
162
163         int i_output_size = aout_FormatToBytes( &p_filter->output )
164                              * p_filter->output.i_rate;
165         int i_input_size = aout_FormatToBytes( &p_filter->input )
166                              * p_filter->input.i_rate;
167
168         p_first_alloc->i_bytes_per_sec = __MAX( p_first_alloc->i_bytes_per_sec,
169                                                 i_output_size );
170
171         if ( p_filter->b_in_place )
172         {
173             p_first_alloc->i_bytes_per_sec = __MAX(
174                                          p_first_alloc->i_bytes_per_sec,
175                                          i_input_size );
176         }
177         else
178         {
179             /* We're gonna need a buffer allocation. */
180             memcpy( &p_filter->output_alloc, p_first_alloc,
181                     sizeof(aout_alloc_t) );
182             p_first_alloc->i_alloc_type = AOUT_ALLOC_STACK;
183             p_first_alloc->i_bytes_per_sec = i_input_size;
184         }
185     }
186 }
187
188 /*****************************************************************************
189  * aout_FiltersPlay: play a buffer
190  *****************************************************************************/
191 void aout_FiltersPlay( aout_instance_t * p_aout,
192                        aout_filter_t ** pp_filters,
193                        int i_nb_filters, aout_buffer_t ** pp_input_buffer )
194 {
195     int i;
196
197     for ( i = 0; i < i_nb_filters; i++ )
198     {
199         aout_filter_t * p_filter = pp_filters[i];
200         aout_buffer_t * p_output_buffer;
201
202         aout_BufferAlloc( &p_filter->output_alloc,
203                           (u64)((*pp_input_buffer)->i_nb_samples * 1000000)
204                             / p_filter->output.i_rate, *pp_input_buffer,
205                           p_output_buffer );
206         if ( p_output_buffer == NULL )
207         {
208             msg_Err( p_aout, "out of memory" );
209             return;
210         }
211         /* Please note that p_output_buffer->i_nb_samples shall be set by
212          * the filter plug-in. */
213
214         p_filter->pf_do_work( p_aout, p_filter, *pp_input_buffer,
215                               p_output_buffer );
216
217         if ( !p_filter->b_in_place )
218         {
219             aout_BufferFree( *pp_input_buffer );
220             *pp_input_buffer = p_output_buffer;
221         }
222     }
223 }
224