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

wav.c

00001 /*****************************************************************************
00002  * wav.c : wav file input module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2001-2003 the VideoLAN team
00005  * $Id: wav.c 11685 2005-07-10 10:51:28Z zorglub $
00006  *
00007  * Authors: Laurent Aimar <[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>                                      /* malloc(), free() */
00028 
00029 #include <vlc/vlc.h>
00030 #include <vlc/input.h>
00031 #include <vlc/aout.h>
00032 
00033 #include <codecs.h>
00034 
00035 /*****************************************************************************
00036  * Module descriptor
00037  *****************************************************************************/
00038 static int  Open ( vlc_object_t * );
00039 static void Close( vlc_object_t * );
00040 
00041 vlc_module_begin();
00042     set_description( _("WAV demuxer") );
00043     set_category( CAT_INPUT );
00044     set_subcategory( SUBCAT_INPUT_DEMUX );
00045     set_capability( "demux2", 142 );
00046     set_callbacks( Open, Close );
00047 vlc_module_end();
00048 
00049 /*****************************************************************************
00050  * Local prototypes
00051  *****************************************************************************/
00052 static int Demux  ( demux_t * );
00053 static int Control( demux_t *, int i_query, va_list args );
00054 
00055 struct demux_sys_t
00056 {
00057     es_format_t     fmt;
00058     es_out_id_t     *p_es;
00059 
00060     int64_t         i_data_pos;
00061     unsigned int    i_data_size;
00062 
00063     unsigned int    i_frame_size;
00064     int             i_frame_samples;
00065 
00066     date_t          pts;
00067 
00068     uint32_t i_channel_mask;
00069     vlc_bool_t b_chan_reorder;              /* do we need channel reordering */
00070     int pi_chan_table[AOUT_CHAN_MAX];
00071 };
00072 
00073 #define __EVEN( x ) ( ( (x)%2 != 0 ) ? ((x)+1) : (x) )
00074 
00075 static int ChunkFind( demux_t *, char *, unsigned int * );
00076 
00077 static void FrameInfo_IMA_ADPCM( demux_t *, unsigned int *, int * );
00078 static void FrameInfo_MS_ADPCM ( demux_t *, unsigned int *, int * );
00079 static void FrameInfo_PCM      ( demux_t *, unsigned int *, int * );
00080 
00081 static const uint32_t pi_channels_src[] =
00082     { WAVE_SPEAKER_FRONT_LEFT, WAVE_SPEAKER_FRONT_RIGHT,
00083       WAVE_SPEAKER_FRONT_CENTER, WAVE_SPEAKER_LOW_FREQUENCY,
00084       WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT,
00085       WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT, 0 };
00086 static const uint32_t pi_channels_in[] =
00087     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
00088       AOUT_CHAN_CENTER, AOUT_CHAN_LFE,
00089       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
00090       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, 0 };
00091 static const uint32_t pi_channels_out[] =
00092     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
00093       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
00094       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
00095       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
00096 
00097 /*****************************************************************************
00098  * Open: check file and initializes structures
00099  *****************************************************************************/
00100 static int Open( vlc_object_t * p_this )
00101 {
00102     demux_t     *p_demux = (demux_t*)p_this;
00103     demux_sys_t *p_sys;
00104 
00105     uint8_t     *p_peek;
00106     unsigned int i_size, i_extended;
00107     char        *psz_name;
00108 
00109     WAVEFORMATEXTENSIBLE *p_wf_ext;
00110     WAVEFORMATEX         *p_wf;
00111 
00112     /* Is it a wav file ? */
00113     if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 ) return VLC_EGENERIC;
00114 
00115     if( memcmp( p_peek, "RIFF", 4 ) || memcmp( &p_peek[8], "WAVE", 4 ) )
00116     {
00117         return VLC_EGENERIC;
00118     }
00119 
00120     p_demux->pf_demux   = Demux;
00121     p_demux->pf_control = Control;
00122     p_demux->p_sys      = p_sys = malloc( sizeof( demux_sys_t ) );
00123     p_sys->p_es         = NULL;
00124     p_sys->b_chan_reorder = 0;
00125     p_sys->i_channel_mask = 0;
00126 
00127     /* skip riff header */
00128     stream_Read( p_demux->s, NULL, 12 );  /* cannot fail as peek succeed */
00129 
00130     /* search fmt chunk */
00131     if( ChunkFind( p_demux, "fmt ", &i_size ) )
00132     {
00133         msg_Err( p_demux, "cannot find 'fmt ' chunk" );
00134         goto error;
00135     }
00136     if( i_size < sizeof( WAVEFORMATEX ) - 2 )   /* XXX -2 isn't a typo */
00137     {
00138         msg_Err( p_demux, "invalid 'fmt ' chunk" );
00139         goto error;
00140     }
00141     stream_Read( p_demux->s, NULL, 8 );   /* Cannot fail */
00142 
00143     /* load waveformatex */
00144     p_wf_ext = malloc( __EVEN( i_size ) + 2 );
00145     p_wf = (WAVEFORMATEX *)p_wf_ext;
00146     p_wf->cbSize = 0;
00147     if( stream_Read( p_demux->s,
00148                      p_wf, __EVEN( i_size ) ) < (int)__EVEN( i_size ) )
00149     {
00150         msg_Err( p_demux, "cannot load 'fmt ' chunk" );
00151         goto error;
00152     }
00153 
00154     es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
00155     wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_sys->fmt.i_codec,
00156                       &psz_name );
00157     p_sys->fmt.audio.i_channels = GetWLE ( &p_wf->nChannels );
00158     p_sys->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
00159     p_sys->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );
00160     p_sys->fmt.i_bitrate = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
00161     p_sys->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
00162     p_sys->fmt.i_extra = GetWLE( &p_wf->cbSize );
00163     i_extended = 0;
00164 
00165     /* Handle new WAVE_FORMAT_EXTENSIBLE wav files */
00166     /* see the following link for more information:
00167      * http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EFAA */
00168     if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_EXTENSIBLE &&
00169         i_size >= sizeof( WAVEFORMATEXTENSIBLE ) )
00170     {
00171         unsigned i, i_channel_mask;
00172         GUID guid_subformat;
00173 
00174         guid_subformat = p_wf_ext->SubFormat;
00175         guid_subformat.Data1 = GetDWLE( &p_wf_ext->SubFormat.Data1 );
00176         guid_subformat.Data2 = GetWLE( &p_wf_ext->SubFormat.Data2 );
00177         guid_subformat.Data3 = GetWLE( &p_wf_ext->SubFormat.Data3 );
00178 
00179         sf_tag_to_fourcc( &guid_subformat, &p_sys->fmt.i_codec, &psz_name );
00180 
00181         i_extended = sizeof( WAVEFORMATEXTENSIBLE ) - sizeof( WAVEFORMATEX );
00182         p_sys->fmt.i_extra -= i_extended;
00183 
00184         i_channel_mask = GetDWLE( &p_wf_ext->dwChannelMask );
00185         if( i_channel_mask )
00186         {
00187             for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
00188             {
00189                 if( i_channel_mask & pi_channels_src[i] )
00190                     p_sys->i_channel_mask |= pi_channels_in[i];
00191             }
00192 
00193             if( p_sys->fmt.i_codec == VLC_FOURCC('a','r','a','w') ||
00194                 p_sys->fmt.i_codec == VLC_FOURCC('a','f','l','t') )
00195 
00196             p_sys->b_chan_reorder =
00197                 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
00198                                           p_sys->i_channel_mask,
00199                                           p_sys->fmt.audio.i_channels,
00200                                           p_sys->pi_chan_table );
00201 
00202             msg_Dbg( p_demux, "channel mask: %x, reordering: %i",
00203                      p_sys->i_channel_mask, (int)p_sys->b_chan_reorder );
00204         }
00205         p_sys->fmt.audio.i_physical_channels =
00206             p_sys->fmt.audio.i_original_channels =
00207                 p_sys->i_channel_mask;
00208     }
00209 
00210     if( p_sys->fmt.i_extra > 0 )
00211     {
00212         p_sys->fmt.p_extra = malloc( p_sys->fmt.i_extra );
00213         memcpy( p_sys->fmt.p_extra, ((uint8_t *)p_wf) + i_extended,
00214                 p_sys->fmt.i_extra );
00215     }
00216 
00217     msg_Dbg( p_demux, "format: 0x%4.4x, fourcc: %4.4s, channels: %d, "
00218              "freq: %d Hz, bitrate: %dKo/s, blockalign: %d, bits/samples: %d, "
00219              "extra size: %d",
00220              GetWLE( &p_wf->wFormatTag ), (char *)&p_sys->fmt.i_codec,
00221              p_sys->fmt.audio.i_channels, p_sys->fmt.audio.i_rate,
00222              p_sys->fmt.i_bitrate / 8 / 1024, p_sys->fmt.audio.i_blockalign,
00223              p_sys->fmt.audio.i_bitspersample, p_sys->fmt.i_extra );
00224 
00225     free( p_wf );
00226 
00227     switch( p_sys->fmt.i_codec )
00228     {
00229     case VLC_FOURCC( 'a', 'r', 'a', 'w' ):
00230     case VLC_FOURCC( 'a', 'f', 'l', 't' ):
00231     case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
00232     case VLC_FOURCC( 'a', 'l', 'a', 'w' ):
00233         FrameInfo_PCM( p_demux, &p_sys->i_frame_size,
00234                        &p_sys->i_frame_samples );
00235         break;
00236     case VLC_FOURCC( 'm', 's', 0x00, 0x02 ):
00237         FrameInfo_MS_ADPCM( p_demux, &p_sys->i_frame_size,
00238                             &p_sys->i_frame_samples );
00239         break;
00240     case VLC_FOURCC( 'm', 's', 0x00, 0x11 ):
00241         FrameInfo_IMA_ADPCM( p_demux, &p_sys->i_frame_size,
00242                              &p_sys->i_frame_samples );
00243         break;
00244     case VLC_FOURCC( 'm', 's', 0x00, 0x61 ):
00245     case VLC_FOURCC( 'm', 's', 0x00, 0x62 ):
00246         /* FIXME not sure at all FIXME */
00247         FrameInfo_MS_ADPCM( p_demux, &p_sys->i_frame_size,
00248                             &p_sys->i_frame_samples );
00249         break;
00250     case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
00251     case VLC_FOURCC( 'a', '5', '2', ' ' ):
00252         /* FIXME set end of area FIXME */
00253         goto relay;
00254     default:
00255         msg_Err( p_demux, "unsupported codec (%4.4s)",
00256                  (char*)&p_sys->fmt.i_codec );
00257         goto error;
00258     }
00259 
00260     msg_Dbg( p_demux, "found %s audio format", psz_name );
00261 
00262     if( ChunkFind( p_demux, "data", &p_sys->i_data_size ) )
00263     {
00264         msg_Err( p_demux, "cannot find 'data' chunk" );
00265         goto error;
00266     }
00267     stream_Read( p_demux->s, NULL, 8 );   /* Cannot fail */
00268     p_sys->i_data_pos = stream_Tell( p_demux->s );
00269 
00270     if( p_sys->fmt.i_bitrate <= 0 )
00271     {
00272         p_sys->fmt.i_bitrate = (mtime_t)p_sys->i_frame_size *
00273             p_sys->fmt.audio.i_rate * 8 / p_sys->i_frame_samples;
00274     }
00275 
00276     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
00277 
00278     date_Init( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 );
00279     date_Set( &p_sys->pts, 1 );
00280 
00281     return VLC_SUCCESS;
00282 
00283 error:
00284 relay:
00285     free( p_sys );
00286     return VLC_EGENERIC;
00287 }
00288 
00289 /*****************************************************************************
00290  * Demux: read packet and send them to decoders
00291  *****************************************************************************
00292  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
00293  *****************************************************************************/
00294 static int Demux( demux_t *p_demux )
00295 {
00296     demux_sys_t *p_sys = p_demux->p_sys;
00297     int64_t     i_pos;
00298     block_t     *p_block;
00299 
00300     i_pos = stream_Tell( p_demux->s );
00301 
00302     if( p_sys->i_data_size > 0 &&
00303         i_pos >= p_sys->i_data_pos + p_sys->i_data_size )
00304     {
00305         /* EOF */
00306         return 0;
00307     }
00308 
00309     if( ( p_block = stream_Block( p_demux->s, p_sys->i_frame_size ) ) == NULL )
00310     {
00311         msg_Warn( p_demux, "cannot read data" );
00312         return 0;
00313     }
00314 
00315     p_block->i_dts = p_block->i_pts =
00316         date_Increment( &p_sys->pts, p_sys->i_frame_samples );
00317 
00318     /* set PCR */
00319     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
00320 
00321     /* Do the channel reordering */
00322     if( p_sys->b_chan_reorder )
00323         aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
00324                              p_sys->fmt.audio.i_channels,
00325                              p_sys->pi_chan_table,
00326                              p_sys->fmt.audio.i_bitspersample );
00327 
00328     es_out_Send( p_demux->out, p_sys->p_es, p_block );
00329 
00330     return 1;
00331 }
00332 
00333 /*****************************************************************************
00334  * Close: frees unused data
00335  *****************************************************************************/
00336 static void Close ( vlc_object_t * p_this )
00337 {
00338     demux_t     *p_demux = (demux_t*)p_this;
00339     demux_sys_t *p_sys  = p_demux->p_sys;
00340 
00341     free( p_sys );
00342 }
00343 
00344 /*****************************************************************************
00345  * Control:
00346  *****************************************************************************/
00347 static int Control( demux_t *p_demux, int i_query, va_list args )
00348 {
00349     demux_sys_t *p_sys  = p_demux->p_sys;
00350     int64_t i_end = -1;
00351 
00352     if( p_sys->i_data_size > 0 )
00353     {
00354         i_end = p_sys->i_data_pos + p_sys->i_data_size;
00355     }
00356 
00357     return demux2_vaControlHelper( p_demux->s, p_sys->i_data_pos, i_end,
00358                                    p_sys->fmt.i_bitrate,
00359                                    p_sys->fmt.audio.i_blockalign,
00360                                    i_query, args );
00361 }
00362 
00363 /*****************************************************************************
00364  * Local functions
00365  *****************************************************************************/
00366 static int ChunkFind( demux_t *p_demux, char *fcc, unsigned int *pi_size )
00367 {
00368     uint8_t *p_peek;
00369 
00370     for( ;; )
00371     {
00372         int i_size;
00373 
00374         if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
00375         {
00376             msg_Err( p_demux, "cannot peek()" );
00377             return VLC_EGENERIC;
00378         }
00379 
00380         i_size = GetDWLE( p_peek + 4 );
00381 
00382         msg_Dbg( p_demux, "Chunk: fcc=`%4.4s` size=%d", p_peek, i_size );
00383 
00384         if( !memcmp( p_peek, fcc, 4 ) )
00385         {
00386             if( pi_size )
00387             {
00388                 *pi_size = i_size;
00389             }
00390             return VLC_SUCCESS;
00391         }
00392 
00393         i_size = __EVEN( i_size ) + 8;
00394         if( stream_Read( p_demux->s, NULL, i_size ) != i_size )
00395         {
00396             return VLC_EGENERIC;
00397         }
00398     }
00399 }
00400 
00401 static void FrameInfo_PCM( demux_t *p_demux, unsigned int *pi_size,
00402                            int *pi_samples )
00403 {
00404     demux_sys_t *p_sys = p_demux->p_sys;
00405     int i_bytes, i_modulo;
00406 
00407     /* read samples for 50ms of */
00408     *pi_samples = __MAX( p_sys->fmt.audio.i_rate / 20, 1 );
00409 
00410     i_bytes = *pi_samples * p_sys->fmt.audio.i_channels *
00411         ( (p_sys->fmt.audio.i_bitspersample + 7) / 8 );
00412 
00413     if( p_sys->fmt.audio.i_blockalign > 0 )
00414     {
00415         if( ( i_modulo = i_bytes % p_sys->fmt.audio.i_blockalign ) != 0 )
00416         {
00417             i_bytes += p_sys->fmt.audio.i_blockalign - i_modulo;
00418         }
00419     }
00420 
00421     *pi_size = i_bytes;
00422 }
00423 
00424 static void FrameInfo_MS_ADPCM( demux_t *p_demux, unsigned int *pi_size,
00425                                 int *pi_samples )
00426 {
00427     demux_sys_t *p_sys = p_demux->p_sys;
00428 
00429     *pi_samples = 2 + 2 * ( p_sys->fmt.audio.i_blockalign -
00430         7 * p_sys->fmt.audio.i_channels ) / p_sys->fmt.audio.i_channels;
00431 
00432     *pi_size = p_sys->fmt.audio.i_blockalign;
00433 }
00434 
00435 static void FrameInfo_IMA_ADPCM( demux_t *p_demux, unsigned int *pi_size,
00436                                  int *pi_samples )
00437 {
00438     demux_sys_t *p_sys = p_demux->p_sys;
00439 
00440     *pi_samples = 2 * ( p_sys->fmt.audio.i_blockalign -
00441         4 * p_sys->fmt.audio.i_channels ) / p_sys->fmt.audio.i_channels;
00442 
00443     *pi_size = p_sys->fmt.audio.i_blockalign;
00444 }

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