]> git.sesse.net Git - vlc/blob - modules/audio_filter/resampler/linear.c
Merge branch 'master' of git@git.videolan.org:vlc
[vlc] / modules / audio_filter / resampler / linear.c
1 /*****************************************************************************
2  * linear.c : linear interpolation resampler
3  *****************************************************************************
4  * Copyright (C) 2002, 2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *          Sigmund Augdal Helberg <dnumgis@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc/vlc.h>
34 #include <vlc_aout.h>
35 #include <vlc_filter.h>
36 #include <vlc_block.h>
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static int  Create    ( vlc_object_t * );
42 static void Close     ( vlc_object_t * );
43 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
44                         aout_buffer_t * );
45
46 static int  OpenFilter ( vlc_object_t * );
47 static void CloseFilter( vlc_object_t * );
48 static block_t *Resample( filter_t *, block_t * );
49
50 /*****************************************************************************
51  * Local structures
52  *****************************************************************************/
53 struct filter_sys_t
54 {
55     int32_t *p_prev_sample;       /* this filter introduces a 1 sample delay */
56
57     unsigned int i_remainder;                /* remainder of previous sample */
58
59     audio_date_t end_date;
60 };
61
62 /*****************************************************************************
63  * Module descriptor
64  *****************************************************************************/
65 vlc_module_begin();
66     set_description( _("Audio filter for linear interpolation resampling") );
67     set_category( CAT_AUDIO );
68     set_subcategory( SUBCAT_AUDIO_MISC );
69     set_capability( "audio filter", 5 );
70     set_callbacks( Create, Close );
71
72     add_submodule();
73     set_description( _("Audio filter for linear interpolation resampling") );
74     set_capability( "audio filter2", 5 );
75     set_callbacks( OpenFilter, CloseFilter );
76 vlc_module_end();
77
78 /*****************************************************************************
79  * Create: allocate linear resampler
80  *****************************************************************************/
81 static int Create( vlc_object_t *p_this )
82 {
83     aout_filter_t * p_filter = (aout_filter_t *)p_this;
84     struct filter_sys_t * p_sys;
85  
86     if ( p_filter->input.i_rate == p_filter->output.i_rate
87           || p_filter->input.i_format != p_filter->output.i_format
88           || p_filter->input.i_physical_channels
89               != p_filter->output.i_physical_channels
90           || p_filter->input.i_original_channels
91               != p_filter->output.i_original_channels
92           || p_filter->input.i_format != VLC_FOURCC('f','l','3','2') )
93     {
94         return VLC_EGENERIC;
95     }
96
97     /* Allocate the memory needed to store the module's structure */
98     p_sys = malloc( sizeof(filter_sys_t) );
99     p_filter->p_sys = (struct aout_filter_sys_t *)p_sys;
100     if( p_sys == NULL )
101     {
102         msg_Err( p_filter, "out of memory" );
103         return VLC_ENOMEM;
104     }
105     p_sys->p_prev_sample = malloc(
106         p_filter->input.i_channels * sizeof(int32_t) );
107     if( p_sys->p_prev_sample == NULL )
108     {
109         msg_Err( p_filter, "out of memory" );
110         return VLC_ENOMEM;
111     }
112     aout_DateInit( &p_sys->end_date, p_filter->output.i_rate );
113
114     p_filter->pf_do_work = DoWork;
115
116     /* We don't want a new buffer to be created because we're not sure we'll
117      * actually need to resample anything. */
118     p_filter->b_in_place = true;
119
120     return VLC_SUCCESS;
121 }
122
123 /*****************************************************************************
124  * Close: free our resources
125  *****************************************************************************/
126 static void Close( vlc_object_t * p_this )
127 {
128     aout_filter_t * p_filter = (aout_filter_t *)p_this;
129     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
130  
131     free( p_sys->p_prev_sample );
132     free( p_sys );
133 }
134
135 /*****************************************************************************
136  * DoWork: convert a buffer
137  *****************************************************************************/
138 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
139                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
140 {
141     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
142 #ifndef HAVE_ALLOCA
143     float *p_in_orig;
144 #endif
145     float *p_in, *p_out = (float *)p_out_buf->p_buffer;
146     float *p_prev_sample = (float *)p_sys->p_prev_sample;
147
148     int i_nb_channels = p_filter->input.i_channels;
149     int i_in_nb = p_in_buf->i_nb_samples;
150     int i_chan, i_in, i_out = 0;
151
152     /* Check if we really need to run the resampler */
153     if( p_aout->mixer.mixer.i_rate == p_filter->input.i_rate )
154     {
155         if( p_filter->b_continuity &&
156             p_in_buf->i_size >=
157               p_in_buf->i_nb_bytes + sizeof(float) * i_nb_channels )
158         {
159             /* output the whole thing with the last sample from last time */
160             memmove( ((float *)(p_in_buf->p_buffer)) + i_nb_channels,
161                      p_in_buf->p_buffer, p_in_buf->i_nb_bytes );
162             memcpy( p_in_buf->p_buffer, p_prev_sample,
163                     i_nb_channels * sizeof(float) );
164         }
165         p_filter->b_continuity = false;
166         return;
167     }
168
169 #ifdef HAVE_ALLOCA
170     p_in = (float *)alloca( p_in_buf->i_nb_bytes );
171 #else
172     p_in_orig = p_in = (float *)malloc( p_in_buf->i_nb_bytes );
173 #endif
174     if( p_in == NULL )
175     {
176         return;
177     }
178
179     p_aout->p_libvlc->pf_memcpy( p_in, p_in_buf->p_buffer, p_in_buf->i_nb_bytes );
180
181     /* Take care of the previous input sample (if any) */
182     if( !p_filter->b_continuity )
183     {
184         p_filter->b_continuity = true;
185         p_sys->i_remainder = 0;
186         aout_DateInit( &p_sys->end_date, p_filter->output.i_rate );
187     }
188     else
189     {
190         while( p_sys->i_remainder < p_filter->output.i_rate )
191         {
192             for( i_chan = i_nb_channels ; i_chan ; )
193             {
194                 i_chan--;
195                 p_out[i_chan] = p_prev_sample[i_chan];
196                 p_out[i_chan] += ( ( p_in[i_chan] - p_prev_sample[i_chan] )
197                                    * p_sys->i_remainder
198                                    / p_filter->output.i_rate );
199             }
200             p_out += i_nb_channels;
201               i_out++;
202
203             p_sys->i_remainder += p_filter->input.i_rate;
204         }
205         p_sys->i_remainder -= p_filter->output.i_rate;
206     }
207
208     /* Take care of the current input samples (minus last one) */
209     for( i_in = 0; i_in < i_in_nb - 1; i_in++ )
210     {
211         while( p_sys->i_remainder < p_filter->output.i_rate )
212         {
213             for( i_chan = i_nb_channels ; i_chan ; )
214             {
215                 i_chan--;
216                 p_out[i_chan] = p_in[i_chan];
217                 p_out[i_chan] += ( ( p_in[i_chan + i_nb_channels]
218                     - p_in[i_chan] )
219                     * p_sys->i_remainder / p_filter->output.i_rate );
220             }
221             p_out += i_nb_channels;
222               i_out++;
223
224             p_sys->i_remainder += p_filter->input.i_rate;
225         }
226
227         p_in += i_nb_channels;
228         p_sys->i_remainder -= p_filter->output.i_rate;
229     }
230
231     /* Backup the last input sample for next time */
232     for( i_chan = i_nb_channels ; i_chan ; )
233     {
234         i_chan--;
235         p_prev_sample[i_chan] = p_in[i_chan];
236     }
237
238     p_out_buf->i_nb_samples = i_out;
239     p_out_buf->start_date = p_in_buf->start_date;
240
241     if( p_in_buf->start_date !=
242         aout_DateGet( &p_sys->end_date ) )
243     {
244         aout_DateSet( &p_sys->end_date, p_in_buf->start_date );
245     }
246
247     p_out_buf->end_date = aout_DateIncrement( &p_sys->end_date,
248                                               p_out_buf->i_nb_samples );
249
250     p_out_buf->i_nb_bytes = p_out_buf->i_nb_samples *
251         i_nb_channels * sizeof(int32_t);
252
253 #ifndef HAVE_ALLOCA
254     free( p_in_orig );
255 #endif
256
257 }
258
259 /*****************************************************************************
260  * OpenFilter:
261  *****************************************************************************/
262 static int OpenFilter( vlc_object_t *p_this )
263 {
264     filter_t *p_filter = (filter_t *)p_this;
265     filter_sys_t *p_sys;
266     int i_out_rate  = p_filter->fmt_out.audio.i_rate;
267
268     if( p_filter->fmt_in.audio.i_rate == p_filter->fmt_out.audio.i_rate ||
269         p_filter->fmt_in.i_codec != VLC_FOURCC('f','l','3','2') )
270     {
271         return VLC_EGENERIC;
272     }
273  
274     /* Allocate the memory needed to store the module's structure */
275     p_filter->p_sys = p_sys = malloc( sizeof(struct filter_sys_t) );
276     if( p_sys == NULL )
277     {
278         msg_Err( p_filter, "out of memory" );
279         return VLC_ENOMEM;
280     }
281
282     p_sys->p_prev_sample = malloc(
283         p_filter->fmt_in.audio.i_channels * sizeof(int32_t) );
284     if( p_sys->p_prev_sample == NULL )
285     {
286         msg_Err( p_filter, "out of memory" );
287         free( p_sys );
288         return VLC_ENOMEM;
289     }
290     aout_DateInit( &p_sys->end_date, p_filter->fmt_in.audio.i_rate );
291
292     p_filter->pf_audio_filter = Resample;
293
294     msg_Dbg( p_this, "%4.4s/%iKHz/%i->%4.4s/%iKHz/%i",
295              (char *)&p_filter->fmt_in.i_codec,
296              p_filter->fmt_in.audio.i_rate,
297              p_filter->fmt_in.audio.i_channels,
298              (char *)&p_filter->fmt_out.i_codec,
299              p_filter->fmt_out.audio.i_rate,
300              p_filter->fmt_out.audio.i_channels);
301
302     p_filter->fmt_out = p_filter->fmt_in;
303     p_filter->fmt_out.audio.i_rate = i_out_rate;
304
305     return 0;
306 }
307
308 /*****************************************************************************
309  * CloseFilter : deallocate data structures
310  *****************************************************************************/
311 static void CloseFilter( vlc_object_t *p_this )
312 {
313     filter_t *p_filter = (filter_t *)p_this;
314     free( p_filter->p_sys->p_prev_sample );
315     free( p_filter->p_sys );
316 }
317
318 /*****************************************************************************
319  * Resample
320  *****************************************************************************/
321 static block_t *Resample( filter_t *p_filter, block_t *p_block )
322 {
323     aout_filter_t aout_filter;
324     aout_buffer_t in_buf, out_buf;
325     block_t *p_out;
326     int i_out_size;
327     int i_bytes_per_frame;
328
329     if( !p_block || !p_block->i_samples )
330     {
331         if( p_block ) p_block->pf_release( p_block );
332         return NULL;
333     }
334  
335     i_bytes_per_frame = p_filter->fmt_out.audio.i_channels *
336                   p_filter->fmt_out.audio.i_bitspersample / 8;
337  
338     i_out_size = i_bytes_per_frame * ( 1 + (p_block->i_samples *
339         p_filter->fmt_out.audio.i_rate / p_filter->fmt_in.audio.i_rate));
340
341     p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
342     if( !p_out )
343     {
344         msg_Warn( p_filter, "can't get output buffer" );
345         p_block->pf_release( p_block );
346         return NULL;
347     }
348
349     p_out->i_samples = i_out_size / i_bytes_per_frame;
350     p_out->i_dts = p_block->i_dts;
351     p_out->i_pts = p_block->i_pts;
352     p_out->i_length = p_block->i_length;
353
354     aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
355     aout_filter.input = p_filter->fmt_in.audio;
356     aout_filter.output = p_filter->fmt_out.audio;
357     aout_filter.b_continuity = false;
358
359     in_buf.p_buffer = p_block->p_buffer;
360     in_buf.i_nb_bytes = p_block->i_buffer;
361     in_buf.i_nb_samples = p_block->i_samples;
362     out_buf.p_buffer = p_out->p_buffer;
363     out_buf.i_nb_bytes = p_out->i_buffer;
364     out_buf.i_nb_samples = p_out->i_samples;
365
366     DoWork( (aout_instance_t *)p_filter, &aout_filter, &in_buf, &out_buf );
367
368     p_block->pf_release( p_block );
369  
370     p_out->i_buffer = out_buf.i_nb_bytes;
371     p_out->i_samples = out_buf.i_nb_samples;
372
373     return p_out;
374 }