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

file.c

00001 /*****************************************************************************
00002  * file.c : audio output which writes the samples to a file
00003  *****************************************************************************
00004  * Copyright (C) 2002 the VideoLAN team
00005  * $Id: file.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Christophe Massiot <[email protected]>
00008  *          Gildas Bazin <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <errno.h>
00031 
00032 #include <vlc/vlc.h>
00033 #include <vlc/aout.h>
00034 
00035 #include "aout_internal.h"
00036 #include "codecs.h"
00037 
00038 #define FRAME_SIZE 2048
00039 #define A52_FRAME_NB 1536
00040 
00041 /*****************************************************************************
00042  * aout_sys_t: audio output method descriptor
00043  *****************************************************************************
00044  * This structure is part of the audio output thread descriptor.
00045  * It describes the direct sound specific properties of an audio device.
00046  *****************************************************************************/
00047 struct aout_sys_t
00048 {
00049     FILE     * p_file;
00050     vlc_bool_t b_add_wav_header;
00051 
00052     WAVEHEADER waveh;                      /* Wave header of the output file */
00053 };
00054 
00055 #define CHANNELS_MAX 6
00056 static int pi_channels_maps[CHANNELS_MAX+1] =
00057 {
00058     0,
00059     AOUT_CHAN_CENTER,
00060     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
00061     AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
00062     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
00063      | AOUT_CHAN_REARRIGHT,
00064     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00065      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
00066     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00067      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE
00068 };
00069 
00070 /*****************************************************************************
00071  * Local prototypes.
00072  *****************************************************************************/
00073 static int     Open        ( vlc_object_t * );
00074 static void    Close       ( vlc_object_t * );
00075 static void    Play        ( aout_instance_t * );
00076 
00077 /*****************************************************************************
00078  * Module descriptor
00079  *****************************************************************************/
00080 #define FORMAT_TEXT N_("Output format")
00081 #define FORMAT_LONGTEXT N_("One of \"u8\", \"s8\", \"u16\", \"s16\", " \
00082     "\"u16_le\", \"s16_le\", \"u16_be\", \"s16_be\", \"fixed32\", " \
00083     "\"float32\" or \"spdif\"")
00084 #define CHANNELS_TEXT N_("Output channels number")
00085 #define CHANNELS_LONGTEXT N_("By default, all the channels of the incoming " \
00086     "will be saved but you can restrict the number of channels here.")
00087 
00088 #define WAV_TEXT N_("Add wave header")
00089 #define WAV_LONGTEXT N_("Instead of writing a raw file, you can add a WAV " \
00090                         "header to the file")
00091 
00092 static char *format_list[] = { "u8", "s8", "u16", "s16", "u16_le", "s16_le",
00093                                "u16_be", "s16_be", "fixed32", "float32",
00094                                "spdif" };
00095 static int format_int[] = { VLC_FOURCC('u','8',' ',' '),
00096                             VLC_FOURCC('s','8',' ',' '),
00097                             AOUT_FMT_U16_NE, AOUT_FMT_S16_NE,
00098                             VLC_FOURCC('u','1','6','l'),
00099                             VLC_FOURCC('s','1','6','l'),
00100                             VLC_FOURCC('u','1','6','b'),
00101                             VLC_FOURCC('s','1','6','b'),
00102                             VLC_FOURCC('f','i','3','2'),
00103                             VLC_FOURCC('f','l','3','2'),
00104                             VLC_FOURCC('s','p','i','f') };
00105 
00106 #define FILE_TEXT N_("Output file")
00107 #define FILE_LONGTEXT N_("File to which the audio samples will be written to")
00108 
00109 vlc_module_begin();
00110     set_description( N_("File audio output") );
00111     set_shortname( _("File") );
00112     set_category( CAT_AUDIO );
00113     set_subcategory( SUBCAT_AUDIO_AOUT );
00114 
00115     add_string( "audiofile-format", "s16", NULL,
00116                 FORMAT_TEXT, FORMAT_LONGTEXT, VLC_TRUE );
00117         change_string_list( format_list, 0, 0 );
00118     add_integer( "audiofile-channels", 0, NULL,
00119                  CHANNELS_TEXT, CHANNELS_LONGTEXT, VLC_TRUE );
00120     add_file( "audiofile-file", "audiofile.wav", NULL, FILE_TEXT,
00121               FILE_LONGTEXT, VLC_FALSE );
00122     add_bool( "audiofile-wav", 1, NULL, WAV_TEXT, WAV_LONGTEXT, VLC_TRUE );
00123 
00124     set_capability( "audio output", 0 );
00125     add_shortcut( "file" );
00126     add_shortcut( "audiofile" );
00127     set_callbacks( Open, Close );
00128 vlc_module_end();
00129 
00130 /*****************************************************************************
00131  * Open: open a dummy audio device
00132  *****************************************************************************/
00133 static int Open( vlc_object_t * p_this )
00134 {
00135     aout_instance_t * p_aout = (aout_instance_t *)p_this;
00136     char * psz_name, * psz_format;
00137     char ** ppsz_compare = format_list;
00138     vlc_value_t val;
00139     int i_channels, i = 0;
00140 
00141     var_Create( p_this, "audiofile-file", VLC_VAR_STRING|VLC_VAR_DOINHERIT );
00142     var_Get( p_this, "audiofile-file", &val );
00143     psz_name = val.psz_string;
00144     if( !psz_name || !*psz_name )
00145     {
00146         msg_Err( p_aout, "you need to specify an output file name" );
00147         if( psz_name ) free( psz_name );
00148         return VLC_EGENERIC;
00149     }
00150 
00151     /* Allocate structure */
00152     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
00153     if( p_aout->output.p_sys == NULL )
00154     {
00155         msg_Err( p_aout, "out of memory" );
00156         return VLC_EGENERIC;
00157     }
00158 
00159     p_aout->output.p_sys->p_file = fopen( psz_name, "wb" );
00160     free( psz_name );
00161     if ( p_aout->output.p_sys->p_file == NULL )
00162     {
00163         free( p_aout->output.p_sys );
00164         return VLC_EGENERIC;
00165     }
00166 
00167     p_aout->output.pf_play = Play;
00168 
00169     /* Audio format */
00170     var_Create( p_this, "audiofile-format", VLC_VAR_STRING|VLC_VAR_DOINHERIT );
00171     var_Get( p_this, "audiofile-format", &val );
00172     psz_format = val.psz_string;
00173 
00174     while ( *ppsz_compare != NULL )
00175     {
00176         if ( !strncmp( *ppsz_compare, psz_format, strlen(*ppsz_compare) ) )
00177         {
00178             break;
00179         }
00180         ppsz_compare++; i++;
00181     }
00182 
00183     if ( *ppsz_compare == NULL )
00184     {
00185         msg_Err( p_aout, "cannot understand the format string (%s)",
00186                  psz_format );
00187         fclose( p_aout->output.p_sys->p_file );
00188         free( p_aout->output.p_sys );
00189         return VLC_EGENERIC;
00190     }
00191 
00192     p_aout->output.output.i_format = format_int[i];
00193     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
00194     {
00195         p_aout->output.i_nb_samples = A52_FRAME_NB;
00196         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
00197         p_aout->output.output.i_frame_length = A52_FRAME_NB;
00198         aout_VolumeNoneInit( p_aout );
00199     }
00200     else
00201     {
00202         p_aout->output.i_nb_samples = FRAME_SIZE;
00203         aout_VolumeSoftInit( p_aout );
00204     }
00205 
00206     /* Channels number */
00207     var_Create( p_this, "audiofile-channels",
00208                 VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00209     var_Get( p_this, "audiofile-channels", &val );
00210     i_channels = val.i_int;
00211 
00212     if( i_channels > 0 && i_channels <= CHANNELS_MAX )
00213     {
00214         p_aout->output.output.i_physical_channels =
00215             pi_channels_maps[i_channels];
00216     }
00217 
00218     /* WAV header */
00219     var_Create( p_this, "audiofile-wav", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
00220     var_Get( p_this, "audiofile-wav", &val );
00221     p_aout->output.p_sys->b_add_wav_header = val.b_bool;
00222 
00223     if( p_aout->output.p_sys->b_add_wav_header )
00224     {
00225         /* Write wave header */
00226         WAVEHEADER *wh = &p_aout->output.p_sys->waveh;
00227 
00228         memset( wh, 0, sizeof(wh) );
00229 
00230         switch( p_aout->output.output.i_format )
00231         {
00232         case VLC_FOURCC('f','l','3','2'):
00233             wh->Format     = WAVE_FORMAT_IEEE_FLOAT;
00234             wh->BitsPerSample = sizeof(float) * 8;
00235             break;
00236         case VLC_FOURCC('u','8',' ',' '):
00237             wh->Format     = WAVE_FORMAT_PCM;
00238             wh->BitsPerSample = 8;
00239             break;
00240         case VLC_FOURCC('s','1','6','l'):
00241         default:
00242             wh->Format     = WAVE_FORMAT_PCM;
00243             wh->BitsPerSample = 16;
00244             break;
00245         }
00246 
00247         wh->MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F');
00248         wh->Length = 0;                    /* temp, to be filled in as we go */
00249         wh->ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E');
00250         wh->SubChunkID = VLC_FOURCC('f', 'm', 't', ' ');
00251         wh->SubChunkLength = 16;
00252 
00253         wh->Modus = aout_FormatNbChannels( &p_aout->output.output );
00254         wh->SampleFreq = p_aout->output.output.i_rate;
00255         wh->BytesPerSample = wh->Modus * ( wh->BitsPerSample / 8 );
00256         wh->BytesPerSec = wh->BytesPerSample * wh->SampleFreq;
00257 
00258         wh->DataChunkID = VLC_FOURCC('d', 'a', 't', 'a');
00259         wh->DataLength = 0;                /* temp, to be filled in as we go */
00260 
00261         /* Header -> little endian format */
00262         SetWLE( &wh->Format, wh->Format );
00263         SetWLE( &wh->BitsPerSample, wh->BitsPerSample );
00264         SetDWLE( &wh->SubChunkLength, wh->SubChunkLength );
00265         SetWLE( &wh->Modus, wh->Modus );
00266         SetDWLE( &wh->SampleFreq, wh->SampleFreq );
00267         SetWLE( &wh->BytesPerSample, wh->BytesPerSample );
00268         SetDWLE( &wh->BytesPerSec, wh->BytesPerSec );
00269 
00270         if( fwrite( wh, sizeof(WAVEHEADER), 1,
00271                     p_aout->output.p_sys->p_file ) != 1 )
00272         {
00273             msg_Err( p_aout, "write error (%s)", strerror(errno) );
00274         }
00275     }
00276 
00277     return 0;
00278 }
00279 
00280 /*****************************************************************************
00281  * Close: close our file
00282  *****************************************************************************/
00283 static void Close( vlc_object_t * p_this )
00284 {
00285     aout_instance_t * p_aout = (aout_instance_t *)p_this;
00286 
00287     msg_Dbg( p_aout, "closing audio file" );
00288 
00289     if( p_aout->output.p_sys->b_add_wav_header )
00290     {
00291         /* Update Wave Header */
00292         p_aout->output.p_sys->waveh.Length =
00293             p_aout->output.p_sys->waveh.DataLength + sizeof(WAVEHEADER) - 4;
00294 
00295         /* Write Wave Header */
00296         if( fseek( p_aout->output.p_sys->p_file, 0, SEEK_SET ) )
00297         {
00298             msg_Err( p_aout, "seek error (%s)", strerror(errno) );
00299         }
00300 
00301         /* Header -> little endian format */
00302         SetDWLE( &p_aout->output.p_sys->waveh.Length,
00303                  p_aout->output.p_sys->waveh.Length );
00304         SetDWLE( &p_aout->output.p_sys->waveh.DataLength,
00305                  p_aout->output.p_sys->waveh.DataLength );
00306 
00307         if( fwrite( &p_aout->output.p_sys->waveh, sizeof(WAVEHEADER), 1,
00308                     p_aout->output.p_sys->p_file ) != 1 )
00309         {
00310             msg_Err( p_aout, "write error (%s)", strerror(errno) );
00311         }
00312     }
00313 
00314     fclose( p_aout->output.p_sys->p_file );
00315     free( p_aout->output.p_sys );
00316 }
00317 
00318 /*****************************************************************************
00319  * Play: pretend to play a sound
00320  *****************************************************************************/
00321 static void Play( aout_instance_t * p_aout )
00322 {
00323     aout_buffer_t * p_buffer;
00324 
00325     p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
00326 
00327     if( fwrite( p_buffer->p_buffer, p_buffer->i_nb_bytes, 1,
00328                 p_aout->output.p_sys->p_file ) != 1 )
00329     {
00330         msg_Err( p_aout, "write error (%s)", strerror(errno) );
00331     }
00332 
00333     if( p_aout->output.p_sys->b_add_wav_header )
00334     {
00335         /* Update Wave Header */
00336         p_aout->output.p_sys->waveh.DataLength += p_buffer->i_nb_bytes;
00337     }
00338 
00339     aout_BufferFree( p_buffer );
00340 }

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