X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faudio_output%2Ffile.c;h=fb568059e996e26a0e55d46737cc33d5f7d26ea2;hb=a63b0ed15e9fb8894f63c4261811ab2ed2a890c3;hp=e30dd6037b4d56ad7a0e6725aa7aed93aae26c85;hpb=a64cdbee390364ed7f018eca2339e46c050852f1;p=vlc diff --git a/modules/audio_output/file.c b/modules/audio_output/file.c index e30dd6037b..fb568059e9 100644 --- a/modules/audio_output/file.c +++ b/modules/audio_output/file.c @@ -1,8 +1,8 @@ /***************************************************************************** * file.c : audio output which writes the samples to a file ***************************************************************************** - * Copyright (C) 2002 VideoLAN - * $Id: file.c,v 1.21 2003/04/20 22:52:03 gbazin Exp $ + * Copyright (C) 2002 the VideoLAN team + * $Id$ * * Authors: Christophe Massiot * Gildas Bazin @@ -11,7 +11,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -19,42 +19,25 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include "aout_internal.h" -#include "codecs.h" +#include +#include +#include +#include /* WAVEHEADER */ +#include -#define FRAME_SIZE 2048 #define A52_FRAME_NB 1536 -typedef struct WAVEHEADER -{ - uint32_t MainChunkID; // it will be 'RIFF' - uint32_t Length; - uint32_t ChunkTypeID; // it will be 'WAVE' - uint32_t SubChunkID; // it will be 'fmt ' - uint32_t SubChunkLength; - uint16_t Format; - uint16_t Modus; - uint32_t SampleFreq; - uint32_t BytesPerSec; - uint16_t BytesPerSample; - uint16_t BitsPerSample; - uint32_t DataChunkID; // it will be 'data' - uint32_t DataLength; -} WAVEHEADER; - /***************************************************************************** * aout_sys_t: audio output method descriptor ***************************************************************************** @@ -64,88 +47,125 @@ typedef struct WAVEHEADER struct aout_sys_t { FILE * p_file; - vlc_bool_t b_add_wav_header; + bool b_add_wav_header; WAVEHEADER waveh; /* Wave header of the output file */ }; +#define CHANNELS_MAX 6 +static const int pi_channels_maps[CHANNELS_MAX+1] = +{ + 0, + AOUT_CHAN_CENTER, + AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT, + AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT, + AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT + | AOUT_CHAN_REARRIGHT, + AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER + | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT, + AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER + | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE +}; + /***************************************************************************** * Local prototypes. *****************************************************************************/ static int Open ( vlc_object_t * ); static void Close ( vlc_object_t * ); -static void Play ( aout_instance_t * ); +static void Play ( audio_output_t *, block_t * ); /***************************************************************************** * Module descriptor *****************************************************************************/ -#define FORMAT_TEXT N_("output format") -#define FORMAT_LONGTEXT N_("one of \"u8\", \"s8\", \"u16\", \"s16\", " \ - "\"u16_le\", \"s16_le\", \"u16_be\", " \ - "\"s16_be\", \"fixed32\", \"float32\" or \"spdif\"") -#define WAV_TEXT N_("add wave header") -#define WAV_LONGTEXT N_("instead of writing a raw file, you can add a wav " \ - "header to the file") - -static char *format_list[] = { "u8", "s8", "u16", "s16", "u16_le", "s16_le", - "u16_be", "s16_be", "fixed32", "float32", - "spdif", NULL }; -static int format_int[] = { VLC_FOURCC('u','8',' ',' '), - VLC_FOURCC('s','8',' ',' '), - AOUT_FMT_U16_NE, AOUT_FMT_S16_NE, - VLC_FOURCC('u','1','6','l'), - VLC_FOURCC('s','1','6','l'), - VLC_FOURCC('u','1','6','b'), - VLC_FOURCC('s','1','6','b'), - VLC_FOURCC('f','i','3','2'), - VLC_FOURCC('f','l','3','2'), - VLC_FOURCC('s','p','i','f') }; - -#define FILE_TEXT N_("output file") -#define FILE_LONGTEXT N_("file to which the audio samples will be written to") - -vlc_module_begin(); - add_category_hint( N_("Audio"), NULL, VLC_FALSE ); - add_string_from_list( "audiofile-format", "s16", format_list, NULL, - FORMAT_TEXT, FORMAT_LONGTEXT, VLC_TRUE ); - add_file( "audiofile", "audiofile.wav", NULL, FILE_TEXT, - FILE_LONGTEXT, VLC_FALSE ); - add_bool( "audiofile-wav", 1, NULL, WAV_TEXT, WAV_LONGTEXT, VLC_TRUE ); - set_description( N_("file audio output") ); - set_capability( "audio output", 0 ); - add_shortcut( "file" ); - add_shortcut( "audiofile" ); - set_callbacks( Open, Close ); -vlc_module_end(); +#define FORMAT_TEXT N_("Output format") + +#define CHANNELS_TEXT N_("Number of output channels") +#define CHANNELS_LONGTEXT N_("By default (0), all the channels of the incoming " \ + "will be saved but you can restrict the number of channels here.") + +#define WAV_TEXT N_("Add WAVE header") +#define WAV_LONGTEXT N_("Instead of writing a raw file, you can add a WAV " \ + "header to the file.") + +static const char *const format_list[] = { "u8", "s8", "u16", "s16", "u16_le", + "s16_le", "u16_be", "s16_be", "fixed32", + "float32", "spdif" }; +static const int format_int[] = { VLC_CODEC_U8, + VLC_CODEC_S8, + VLC_CODEC_U16N, VLC_CODEC_S16N, + VLC_CODEC_U16L, + VLC_CODEC_S16L, + VLC_CODEC_U16B, + VLC_CODEC_S16B, + VLC_CODEC_FI32, + VLC_CODEC_FL32, + VLC_CODEC_SPDIFL }; + +#define FILE_TEXT N_("Output file") +#define FILE_LONGTEXT N_("File to which the audio samples will be written to. (\"-\" for stdout") + +vlc_module_begin () + set_description( N_("File audio output") ) + set_shortname( N_("File") ) + set_category( CAT_AUDIO ) + set_subcategory( SUBCAT_AUDIO_AOUT ) + + add_savefile( "audiofile-file", "audiofile.wav", FILE_TEXT, + FILE_LONGTEXT, false ) + add_string( "audiofile-format", "s16", + FORMAT_TEXT, FORMAT_TEXT, true ) + change_string_list( format_list, 0, 0 ) + add_integer( "audiofile-channels", 0, + CHANNELS_TEXT, CHANNELS_LONGTEXT, true ) + change_integer_range( 0, 6 ) + add_bool( "audiofile-wav", true, WAV_TEXT, WAV_LONGTEXT, true ) + + set_capability( "audio output", 0 ) + add_shortcut( "file", "audiofile" ) + set_callbacks( Open, Close ) +vlc_module_end () /***************************************************************************** * Open: open a dummy audio device *****************************************************************************/ static int Open( vlc_object_t * p_this ) { - aout_instance_t * p_aout = (aout_instance_t *)p_this; - char * psz_name = config_GetPsz( p_this, "audiofile" ); - char * psz_format = config_GetPsz( p_aout, "audiofile-format" ); - char ** ppsz_compare = format_list; - int i = 0; - - /* Allocate structure */ - p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); - if( p_aout->output.p_sys == NULL ) + audio_output_t * p_aout = (audio_output_t *)p_this; + char * psz_name, * psz_format; + const char * const * ppsz_compare = format_list; + int i_channels, i = 0; + + psz_name = var_CreateGetString( p_this, "audiofile-file" ); + if( !psz_name || !*psz_name ) { - msg_Err( p_aout, "out of memory" ); + msg_Err( p_aout, "you need to specify an output file name" ); + free( psz_name ); return VLC_EGENERIC; } - p_aout->output.p_sys->p_file = fopen( psz_name, "wb" ); + /* Allocate structure */ + p_aout->sys = malloc( sizeof( aout_sys_t ) ); + if( p_aout->sys == NULL ) + return VLC_ENOMEM; + + if( !strcmp( psz_name, "-" ) ) + p_aout->sys->p_file = stdout; + else + p_aout->sys->p_file = vlc_fopen( psz_name, "wb" ); + free( psz_name ); - if ( p_aout->output.p_sys->p_file == NULL ) + if ( p_aout->sys->p_file == NULL ) { - free( p_aout->output.p_sys ); - return -1; + free( p_aout->sys ); + return VLC_EGENERIC; } - p_aout->output.pf_play = Play; + p_aout->pf_play = Play; + p_aout->pf_pause = NULL; + p_aout->pf_flush = NULL; + + /* Audio format */ + psz_format = var_CreateGetString( p_this, "audiofile-format" ); while ( *ppsz_compare != NULL ) { @@ -158,48 +178,57 @@ static int Open( vlc_object_t * p_this ) if ( *ppsz_compare == NULL ) { - msg_Err( p_aout, "Cannot understand the format string (%s)", + msg_Err( p_aout, "cannot understand the format string (%s)", psz_format ); - fclose( p_aout->output.p_sys->p_file ); - free( p_aout->output.p_sys ); - return -1; + if( p_aout->sys->p_file != stdout ) + fclose( p_aout->sys->p_file ); + free( p_aout->sys ); + free( psz_format ); + return VLC_EGENERIC; } + free( psz_format ); - p_aout->output.output.i_format = format_int[i]; - if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) + p_aout->format.i_format = format_int[i]; + if ( AOUT_FMT_SPDIF( &p_aout->format ) ) { - p_aout->output.i_nb_samples = A52_FRAME_NB; - p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; - p_aout->output.output.i_frame_length = A52_FRAME_NB; + p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE; + p_aout->format.i_frame_length = A52_FRAME_NB; aout_VolumeNoneInit( p_aout ); } else - { - p_aout->output.i_nb_samples = FRAME_SIZE; aout_VolumeSoftInit( p_aout ); + + /* Channels number */ + i_channels = var_CreateGetInteger( p_this, "audiofile-channels" ); + + if( i_channels > 0 && i_channels <= CHANNELS_MAX ) + { + p_aout->format.i_physical_channels = + pi_channels_maps[i_channels]; } - p_aout->output.p_sys->b_add_wav_header = - config_GetInt( p_this, "audiofile-wav" ); + /* WAV header */ + p_aout->sys->b_add_wav_header = var_CreateGetBool( p_this, + "audiofile-wav" ); - if( p_aout->output.p_sys->b_add_wav_header ) + if( p_aout->sys->b_add_wav_header ) { /* Write wave header */ - WAVEHEADER *wh = &p_aout->output.p_sys->waveh; + WAVEHEADER *wh = &p_aout->sys->waveh; - memset( wh, 0, sizeof(wh) ); + memset( wh, 0, sizeof(*wh) ); - switch( p_aout->output.output.i_format ) + switch( p_aout->format.i_format ) { - case VLC_FOURCC('f','l','3','2'): + case VLC_CODEC_FL32: wh->Format = WAVE_FORMAT_IEEE_FLOAT; wh->BitsPerSample = sizeof(float) * 8; break; - case VLC_FOURCC('u','8',' ',' '): + case VLC_CODEC_U8: wh->Format = WAVE_FORMAT_PCM; wh->BitsPerSample = 8; break; - case VLC_FOURCC('s','1','6','l'): + case VLC_CODEC_S16L: default: wh->Format = WAVE_FORMAT_PCM; wh->BitsPerSample = 16; @@ -212,18 +241,27 @@ static int Open( vlc_object_t * p_this ) wh->SubChunkID = VLC_FOURCC('f', 'm', 't', ' '); wh->SubChunkLength = 16; - wh->Modus = aout_FormatNbChannels( &p_aout->output.output ); - wh->SampleFreq = p_aout->output.output.i_rate; + wh->Modus = aout_FormatNbChannels( &p_aout->format ); + wh->SampleFreq = p_aout->format.i_rate; wh->BytesPerSample = wh->Modus * ( wh->BitsPerSample / 8 ); wh->BytesPerSec = wh->BytesPerSample * wh->SampleFreq; wh->DataChunkID = VLC_FOURCC('d', 'a', 't', 'a'); wh->DataLength = 0; /* temp, to be filled in as we go */ + /* Header -> little endian format */ + SetWLE( &wh->Format, wh->Format ); + SetWLE( &wh->BitsPerSample, wh->BitsPerSample ); + SetDWLE( &wh->SubChunkLength, wh->SubChunkLength ); + SetWLE( &wh->Modus, wh->Modus ); + SetDWLE( &wh->SampleFreq, wh->SampleFreq ); + SetWLE( &wh->BytesPerSample, wh->BytesPerSample ); + SetDWLE( &wh->BytesPerSec, wh->BytesPerSec ); + if( fwrite( wh, sizeof(WAVEHEADER), 1, - p_aout->output.p_sys->p_file ) != 1 ) + p_aout->sys->p_file ) != 1 ) { - msg_Err( p_aout, "write error (%s)", strerror(errno) ); + msg_Err( p_aout, "write error (%m)" ); } } @@ -235,51 +273,55 @@ static int Open( vlc_object_t * p_this ) *****************************************************************************/ static void Close( vlc_object_t * p_this ) { - aout_instance_t * p_aout = (aout_instance_t *)p_this; + audio_output_t * p_aout = (audio_output_t *)p_this; msg_Dbg( p_aout, "closing audio file" ); - if( p_aout->output.p_sys->b_add_wav_header ) + if( p_aout->sys->b_add_wav_header ) { /* Update Wave Header */ - p_aout->output.p_sys->waveh.Length = - p_aout->output.p_sys->waveh.DataLength + sizeof(WAVEHEADER) - 4; + p_aout->sys->waveh.Length = + p_aout->sys->waveh.DataLength + sizeof(WAVEHEADER) - 4; /* Write Wave Header */ - if( fseek( p_aout->output.p_sys->p_file, 0, SEEK_SET ) ) + if( fseek( p_aout->sys->p_file, 0, SEEK_SET ) ) { - msg_Err( p_aout, "seek error (%s)", strerror(errno) ); + msg_Err( p_aout, "seek error (%m)" ); } - if( fwrite( &p_aout->output.p_sys->waveh, sizeof(WAVEHEADER), 1, - p_aout->output.p_sys->p_file ) != 1 ) + + /* Header -> little endian format */ + SetDWLE( &p_aout->sys->waveh.Length, + p_aout->sys->waveh.Length ); + SetDWLE( &p_aout->sys->waveh.DataLength, + p_aout->sys->waveh.DataLength ); + + if( fwrite( &p_aout->sys->waveh, sizeof(WAVEHEADER), 1, + p_aout->sys->p_file ) != 1 ) { - msg_Err( p_aout, "write error (%s)", strerror(errno) ); + msg_Err( p_aout, "write error (%m)" ); } } - fclose( p_aout->output.p_sys->p_file ); - free( p_aout->output.p_sys ); + if( p_aout->sys->p_file != stdout ) + fclose( p_aout->sys->p_file ); + free( p_aout->sys ); } /***************************************************************************** * Play: pretend to play a sound *****************************************************************************/ -static void Play( aout_instance_t * p_aout ) +static void Play( audio_output_t * p_aout, block_t *p_buffer ) { - aout_buffer_t * p_buffer; - - p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); - - if( fwrite( p_buffer->p_buffer, p_buffer->i_nb_bytes, 1, - p_aout->output.p_sys->p_file ) != 1 ) + if( fwrite( p_buffer->p_buffer, p_buffer->i_buffer, 1, + p_aout->sys->p_file ) != 1 ) { - msg_Err( p_aout, "write error (%s)", strerror(errno) ); + msg_Err( p_aout, "write error (%m)" ); } - if( p_aout->output.p_sys->b_add_wav_header ) + if( p_aout->sys->b_add_wav_header ) { /* Update Wave Header */ - p_aout->output.p_sys->waveh.DataLength += p_buffer->i_nb_bytes; + p_aout->sys->waveh.DataLength += p_buffer->i_buffer; } aout_BufferFree( p_buffer );