Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

filters.c

00001 /*****************************************************************************
00002  * filters.c : audio output filters management
00003  *****************************************************************************
00004  * Copyright (C) 2002-2004 the VideoLAN team
00005  * $Id: filters.c 12676 2005-09-25 16:49:40Z babal $
00006  *
00007  * Authors: Christophe Massiot <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>                            /* calloc(), malloc(), free() */
00028 #include <string.h>
00029 
00030 #include <vlc/vlc.h>
00031 
00032 #ifdef HAVE_ALLOCA_H
00033 #   include <alloca.h>
00034 #endif
00035 
00036 #include "audio_output.h"
00037 #include "aout_internal.h"
00038 
00039 /*****************************************************************************
00040  * FindFilter: find an audio filter for a specific transformation
00041  *****************************************************************************/
00042 static aout_filter_t * FindFilter( aout_instance_t * p_aout,
00043                              const audio_sample_format_t * p_input_format,
00044                              const audio_sample_format_t * p_output_format )
00045 {
00046     aout_filter_t * p_filter = vlc_object_create( p_aout,
00047                                                   sizeof(aout_filter_t) );
00048 
00049     if ( p_filter == NULL ) return NULL;
00050     vlc_object_attach( p_filter, p_aout );
00051 
00052     memcpy( &p_filter->input, p_input_format, sizeof(audio_sample_format_t) );
00053     memcpy( &p_filter->output, p_output_format,
00054             sizeof(audio_sample_format_t) );
00055     p_filter->p_module = module_Need( p_filter, "audio filter", NULL, 0 );
00056     if ( p_filter->p_module == NULL )
00057     {
00058         vlc_object_detach( p_filter );
00059         vlc_object_destroy( p_filter );
00060         return NULL;
00061     }
00062 
00063     p_filter->b_continuity = VLC_FALSE;
00064 
00065     return p_filter;
00066 }
00067 
00068 /*****************************************************************************
00069  * SplitConversion: split a conversion in two parts
00070  *****************************************************************************
00071  * Returns the number of conversions required by the first part - 0 if only
00072  * one conversion was asked.
00073  * Beware : p_output_format can be modified during this function if the
00074  * developer passed SplitConversion( toto, titi, titi, ... ). That is legal.
00075  * SplitConversion( toto, titi, toto, ... ) isn't.
00076  *****************************************************************************/
00077 static int SplitConversion( const audio_sample_format_t * p_input_format,
00078                             const audio_sample_format_t * p_output_format,
00079                             audio_sample_format_t * p_middle_format )
00080 {
00081     vlc_bool_t b_format =
00082              (p_input_format->i_format != p_output_format->i_format);
00083     vlc_bool_t b_rate = (p_input_format->i_rate != p_output_format->i_rate);
00084     vlc_bool_t b_channels =
00085         (p_input_format->i_physical_channels
00086           != p_output_format->i_physical_channels)
00087      || (p_input_format->i_original_channels
00088           != p_output_format->i_original_channels);
00089     int i_nb_conversions = b_format + b_rate + b_channels;
00090 
00091     if ( i_nb_conversions <= 1 ) return 0;
00092 
00093     memcpy( p_middle_format, p_output_format, sizeof(audio_sample_format_t) );
00094 
00095     if ( i_nb_conversions == 2 )
00096     {
00097         if ( !b_format || !b_channels )
00098         {
00099             p_middle_format->i_rate = p_input_format->i_rate;
00100             aout_FormatPrepare( p_middle_format );
00101             return 1;
00102         }
00103 
00104         /* !b_rate */
00105         p_middle_format->i_physical_channels
00106              = p_input_format->i_physical_channels;
00107         p_middle_format->i_original_channels
00108              = p_input_format->i_original_channels;
00109         aout_FormatPrepare( p_middle_format );
00110         return 1;
00111     }
00112 
00113     /* i_nb_conversion == 3 */
00114     p_middle_format->i_rate = p_input_format->i_rate;
00115     aout_FormatPrepare( p_middle_format );
00116     return 2;
00117 }
00118 
00119 static void ReleaseFilter( aout_filter_t * p_filter )
00120 {
00121     module_Unneed( p_filter, p_filter->p_module );
00122     vlc_object_detach( p_filter );
00123     vlc_object_destroy( p_filter );
00124 }
00125 
00126 /*****************************************************************************
00127  * aout_FiltersCreatePipeline: create a filters pipeline to transform a sample
00128  *                             format to another
00129  *****************************************************************************
00130  * pi_nb_filters must be initialized before calling this function
00131  *****************************************************************************/
00132 int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
00133                                 aout_filter_t ** pp_filters_start,
00134                                 int * pi_nb_filters,
00135                                 const audio_sample_format_t * p_input_format,
00136                                 const audio_sample_format_t * p_output_format )
00137 {
00138     aout_filter_t** pp_filters = pp_filters_start + *pi_nb_filters;
00139     audio_sample_format_t temp_format;
00140     int i_nb_conversions;
00141 
00142     if ( AOUT_FMTS_IDENTICAL( p_input_format, p_output_format ) )
00143     {
00144         msg_Dbg( p_aout, "no need for any filter" );
00145         return 0;
00146     }
00147 
00148     aout_FormatsPrint( p_aout, "filter(s)", p_input_format, p_output_format );
00149 
00150     if( *pi_nb_filters + 1 > AOUT_MAX_FILTERS )
00151     {
00152         msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
00153         return -1;
00154     }
00155 
00156     /* Try to find a filter to do the whole conversion. */
00157     pp_filters[0] = FindFilter( p_aout, p_input_format, p_output_format );
00158     if ( pp_filters[0] != NULL )
00159     {
00160         msg_Dbg( p_aout, "found a filter for the whole conversion" );
00161         ++*pi_nb_filters;
00162         return 0;
00163     }
00164 
00165     /* We'll have to split the conversion. We always do the downmixing
00166      * before the resampling, because the audio decoder can probably do it
00167      * for us. */
00168     i_nb_conversions = SplitConversion( p_input_format,
00169                                         p_output_format, &temp_format );
00170     if ( !i_nb_conversions )
00171     {
00172         /* There was only one conversion to do, and we already failed. */
00173         msg_Err( p_aout, "couldn't find a filter for the conversion" );
00174         return -1;
00175     }
00176 
00177     pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
00178     if ( pp_filters[0] == NULL && i_nb_conversions == 2 )
00179     {
00180         /* Try with only one conversion. */
00181         SplitConversion( p_input_format, &temp_format, &temp_format );
00182         pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
00183     }
00184     if ( pp_filters[0] == NULL )
00185     {
00186         msg_Err( p_aout,
00187               "couldn't find a filter for the first part of the conversion" );
00188         return -1;
00189     }
00190 
00191     /* We have the first stage of the conversion. Find a filter for
00192      * the rest. */
00193     if( *pi_nb_filters + 2 > AOUT_MAX_FILTERS )
00194     {
00195         ReleaseFilter( pp_filters[0] );
00196         msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
00197         return -1;
00198     }
00199     pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
00200                                 p_output_format );
00201     if ( pp_filters[1] == NULL )
00202     {
00203         /* Try to split the conversion. */
00204         i_nb_conversions = SplitConversion( &pp_filters[0]->output,
00205                                            p_output_format, &temp_format );
00206         if ( !i_nb_conversions )
00207         {
00208             ReleaseFilter( pp_filters[0] );
00209             msg_Err( p_aout,
00210               "couldn't find a filter for the second part of the conversion" );
00211             return -1;
00212         }
00213         if( *pi_nb_filters + 3 > AOUT_MAX_FILTERS )
00214         {
00215             ReleaseFilter( pp_filters[0] );
00216             msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
00217             return -1;
00218         }
00219         pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
00220                                     &temp_format );
00221         pp_filters[2] = FindFilter( p_aout, &temp_format,
00222                                     p_output_format );
00223 
00224         if ( pp_filters[1] == NULL || pp_filters[2] == NULL )
00225         {
00226             ReleaseFilter( pp_filters[0] );
00227             if ( pp_filters[1] != NULL )
00228             {
00229                 ReleaseFilter( pp_filters[1] );
00230             }
00231             if ( pp_filters[2] != NULL )
00232             {
00233                 ReleaseFilter( pp_filters[2] );
00234             }
00235             msg_Err( p_aout,
00236                "couldn't find filters for the second part of the conversion" );
00237             return -1;
00238         }
00239         *pi_nb_filters += 3;
00240         msg_Dbg( p_aout, "found 3 filters for the whole conversion" );
00241     }
00242     else
00243     {
00244         *pi_nb_filters += 2;
00245         msg_Dbg( p_aout, "found 2 filters for the whole conversion" );
00246     }
00247 
00248     return 0;
00249 }
00250 
00251 /*****************************************************************************
00252  * aout_FiltersDestroyPipeline: deallocate a filters pipeline
00253  *****************************************************************************/
00254 void aout_FiltersDestroyPipeline( aout_instance_t * p_aout,
00255                                   aout_filter_t ** pp_filters,
00256                                   int i_nb_filters )
00257 {
00258     int i;
00259 
00260     for ( i = 0; i < i_nb_filters; i++ )
00261     {
00262         module_Unneed( pp_filters[i], pp_filters[i]->p_module );
00263         vlc_object_detach( pp_filters[i] );
00264         vlc_object_destroy( pp_filters[i] );
00265     }
00266 }
00267 
00268 /*****************************************************************************
00269  * aout_FiltersHintBuffers: fill in aout_alloc_t structures to optimize
00270  *                          buffer allocations
00271  *****************************************************************************/
00272 void aout_FiltersHintBuffers( aout_instance_t * p_aout,
00273                               aout_filter_t ** pp_filters,
00274                               int i_nb_filters, aout_alloc_t * p_first_alloc )
00275 {
00276     int i;
00277 
00278     (void)p_aout; /* unused */
00279 
00280     for ( i = i_nb_filters - 1; i >= 0; i-- )
00281     {
00282         aout_filter_t * p_filter = pp_filters[i];
00283 
00284         int i_output_size = p_filter->output.i_bytes_per_frame
00285                              * p_filter->output.i_rate
00286                              / p_filter->output.i_frame_length;
00287         int i_input_size = p_filter->input.i_bytes_per_frame
00288                              * p_filter->input.i_rate
00289                              / p_filter->input.i_frame_length;
00290 
00291         p_first_alloc->i_bytes_per_sec = __MAX( p_first_alloc->i_bytes_per_sec,
00292                                                 i_output_size );
00293 
00294         if ( p_filter->b_in_place )
00295         {
00296             p_first_alloc->i_bytes_per_sec = __MAX(
00297                                          p_first_alloc->i_bytes_per_sec,
00298                                          i_input_size );
00299             p_filter->output_alloc.i_alloc_type = AOUT_ALLOC_NONE;
00300         }
00301         else
00302         {
00303             /* We're gonna need a buffer allocation. */
00304             memcpy( &p_filter->output_alloc, p_first_alloc,
00305                     sizeof(aout_alloc_t) );
00306             p_first_alloc->i_alloc_type = AOUT_ALLOC_STACK;
00307             p_first_alloc->i_bytes_per_sec = i_input_size;
00308         }
00309     }
00310 }
00311 
00312 /*****************************************************************************
00313  * aout_FiltersPlay: play a buffer
00314  *****************************************************************************/
00315 void aout_FiltersPlay( aout_instance_t * p_aout,
00316                        aout_filter_t ** pp_filters,
00317                        int i_nb_filters, aout_buffer_t ** pp_input_buffer )
00318 {
00319     int i;
00320 
00321     for ( i = 0; i < i_nb_filters; i++ )
00322     {
00323         aout_filter_t * p_filter = pp_filters[i];
00324         aout_buffer_t * p_output_buffer;
00325 
00326         /* Resamplers can produce slightly more samples than (i_in_nb *
00327          * p_filter->output.i_rate / p_filter->input.i_rate) so we need
00328          * slightly bigger buffers. */
00329         aout_BufferAlloc( &p_filter->output_alloc,
00330             ((mtime_t)(*pp_input_buffer)->i_nb_samples + 2)
00331             * 1000000 / p_filter->input.i_rate,
00332             *pp_input_buffer, p_output_buffer );
00333         if ( p_output_buffer == NULL )
00334         {
00335             msg_Err( p_aout, "out of memory" );
00336             return;
00337         }
00338         /* Please note that p_output_buffer->i_nb_samples & i_nb_bytes
00339          * shall be set by the filter plug-in. */
00340 
00341         p_filter->pf_do_work( p_aout, p_filter, *pp_input_buffer,
00342                               p_output_buffer );
00343 
00344         if ( !p_filter->b_in_place )
00345         {
00346             aout_BufferFree( *pp_input_buffer );
00347             *pp_input_buffer = p_output_buffer;
00348         }
00349     }
00350 }
00351 

Generated on Tue Dec 20 10:14:59 2005 for vlc-0.8.4a by  doxygen 1.4.2