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