]> git.sesse.net Git - mlt/blob - src/modules/resample/filter_resample.c
Add service locks for parallelism.
[mlt] / src / modules / resample / filter_resample.c
1 /*
2  * filter_resample.c -- adjust audio sample frequency
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <framework/mlt_filter.h>
22 #include <framework/mlt_frame.h>
23 #include <framework/mlt_log.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <samplerate.h>
28 #include <string.h>
29
30 #define BUFFER_LEN 20480
31 #define RESAMPLE_TYPE SRC_SINC_FASTEST
32
33 /** Get the audio.
34 */
35
36 static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
37 {
38         // Get the filter service
39         mlt_filter filter = mlt_frame_pop_audio( frame );
40
41         // Get the filter properties
42         mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
43
44         // Get the resample information
45         int output_rate = mlt_properties_get_int( filter_properties, "frequency" );
46         int error = 0;
47
48         // If no resample frequency is specified, default to requested value
49         if ( output_rate == 0 )
50                 output_rate = *frequency;
51
52         // Get the producer's audio
53         if ( *format != mlt_audio_s16 )
54                 *format = mlt_audio_float;
55         mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
56
57         // Return now if no work to do
58         if ( output_rate != *frequency )
59         {
60                 // Do not convert to float unless we need to change the rate
61                 if ( *format != mlt_audio_float )
62                 {
63                         *format = mlt_audio_float;
64                         mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
65                 }
66
67                 mlt_service_lock( MLT_FILTER_SERVICE(filter) );
68
69                 float *input_buffer = mlt_properties_get_data( filter_properties, "input_buffer", NULL );
70                 float *output_buffer = mlt_properties_get_data( filter_properties, "output_buffer", NULL );
71                 SRC_DATA data;
72                 data.data_in = input_buffer;
73                 data.data_out = output_buffer;
74                 data.src_ratio = ( float ) output_rate / ( float ) *frequency;
75                 data.input_frames = *samples;
76                 data.output_frames = BUFFER_LEN / *channels;
77                 data.end_of_input = 0;
78
79                 SRC_STATE *state = mlt_properties_get_data( filter_properties, "state", NULL );
80                 if ( !state || mlt_properties_get_int( filter_properties, "channels" ) != *channels )
81                 {
82                         // Recreate the resampler if the number of channels changed
83                         state = src_new( RESAMPLE_TYPE, *channels, &error );
84                         mlt_properties_set_data( filter_properties, "state", state, 0, (mlt_destructor) src_delete, NULL );
85                         mlt_properties_set_int( filter_properties, "channels", *channels );
86                 }
87
88                 // Convert to interleaved
89                 float *q = (float*) *buffer;
90                 float *p = input_buffer;
91                 int s, c;
92                 for ( s = 0; s < *samples; s++ )
93                         for ( c = 0; c < *channels; c++ )
94                                 *p++ = *( q + c * *samples + s );
95
96                 // Resample the audio
97                 error = src_process( state, &data );
98                 if ( !error )
99                 {
100                         int size = data.output_frames_gen * *channels * sizeof(float);
101
102                         // Resize if necessary
103                         if ( data.output_frames_gen > *samples )
104                         {
105                                 *buffer = mlt_pool_realloc( *buffer, size );
106                                 mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release );
107                         }
108
109                         // Convert to non-interleaved
110                         p = (float*) *buffer;
111                         for ( c = 0; c < *channels; c++ )
112                         {
113                                 float *q = output_buffer + c;
114                                 int i = data.output_frames_gen + 1;
115                                 while ( --i  )
116                                 {
117                                         *p++ = *q;
118                                         q += *channels;
119                                 }
120                         }
121
122                         // Update output variables
123                         *samples = data.output_frames_gen;
124                         *frequency = output_rate;
125
126                 }
127                 else
128                 {
129                         mlt_log_error( MLT_FILTER_SERVICE( filter ), "%s %d,%d,%d\n", src_strerror( error ), *frequency, *samples, output_rate );
130                 }
131                 mlt_service_unlock( MLT_FILTER_SERVICE(filter) );
132         }
133
134         return error;
135 }
136
137 /** Filter processing.
138 */
139
140 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
141 {
142         if ( mlt_frame_is_test_audio( frame ) == 0 )
143         {
144                 mlt_frame_push_audio( frame, this );
145                 mlt_frame_push_audio( frame, resample_get_audio );
146         }
147
148         return frame;
149 }
150
151 /** Constructor for the filter.
152 */
153
154 mlt_filter filter_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
155 {
156         mlt_filter this = mlt_filter_new( );
157         if ( this != NULL )
158         {
159                 int error;
160                 SRC_STATE *state = src_new( RESAMPLE_TYPE, 2 /* channels */, &error );
161                 if ( error == 0 )
162                 {
163                         void *input_buffer = mlt_pool_alloc( BUFFER_LEN );
164                         void *output_buffer = mlt_pool_alloc( BUFFER_LEN );
165                         this->process = filter_process;
166                         if ( arg != NULL )
167                                 mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "frequency", atoi( arg ) );
168                         mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", 2 );
169                         mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "state", state, 0, (mlt_destructor)src_delete, NULL );
170                         mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "input_buffer", input_buffer, BUFFER_LEN, mlt_pool_release, NULL );
171                         mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "output_buffer", output_buffer, BUFFER_LEN, mlt_pool_release, NULL );
172                 }
173                 else
174                 {
175                         fprintf( stderr, "filter_resample_init: %s\n", src_strerror( error ) );
176                 }
177         }
178         return this;
179 }