00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028
00029 #include <vlc/vlc.h>
00030 #include <vlc/aout.h>
00031 #include <vlc/sout.h>
00032
00033 #include "codecs.h"
00034
00035
00036
00037
00038 static int Open ( vlc_object_t * );
00039 static void Close ( vlc_object_t * );
00040
00041 vlc_module_begin();
00042 set_description( _("WAV muxer") );
00043 set_capability( "sout mux", 5 );
00044 set_category( CAT_SOUT );
00045 set_subcategory( SUBCAT_SOUT_MUX );
00046 set_callbacks( Open, Close );
00047 add_shortcut( "wav" );
00048 vlc_module_end();
00049
00050
00051
00052
00053 static int Control ( sout_mux_t *, int, va_list );
00054 static int AddStream( sout_mux_t *, sout_input_t * );
00055 static int DelStream( sout_mux_t *, sout_input_t * );
00056 static int Mux ( sout_mux_t * );
00057
00058 #define MAX_CHANNELS 6
00059
00060 struct sout_mux_sys_t
00061 {
00062 vlc_bool_t b_used;
00063 vlc_bool_t b_header;
00064 vlc_bool_t b_ext;
00065
00066 uint32_t i_data;
00067
00068
00069 uint32_t waveheader[5];
00070 WAVEFORMATEXTENSIBLE waveformat;
00071 uint32_t waveheader2[2];
00072
00073 uint32_t i_channel_mask;
00074 vlc_bool_t b_chan_reorder;
00075 int pi_chan_table[AOUT_CHAN_MAX];
00076 };
00077
00078
00079 static const uint32_t pi_channels_src[] =
00080 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
00081 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
00082 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
00083 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
00084 static const uint32_t pi_channels_in[] =
00085 { WAVE_SPEAKER_FRONT_LEFT, WAVE_SPEAKER_FRONT_RIGHT,
00086 WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT,
00087 WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT,
00088 WAVE_SPEAKER_FRONT_CENTER, WAVE_SPEAKER_LOW_FREQUENCY, 0 };
00089 static const uint32_t pi_channels_out[] =
00090 { WAVE_SPEAKER_FRONT_LEFT, WAVE_SPEAKER_FRONT_RIGHT,
00091 WAVE_SPEAKER_FRONT_CENTER, WAVE_SPEAKER_LOW_FREQUENCY,
00092 WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT,
00093 WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT, 0 };
00094
00095
00096
00097
00098 static int Open( vlc_object_t *p_this )
00099 {
00100 sout_mux_t *p_mux = (sout_mux_t*)p_this;
00101 sout_mux_sys_t *p_sys;
00102
00103 p_mux->pf_control = Control;
00104 p_mux->pf_addstream = AddStream;
00105 p_mux->pf_delstream = DelStream;
00106 p_mux->pf_mux = Mux;
00107
00108 p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
00109 p_sys->b_used = VLC_FALSE;
00110 p_sys->b_header = VLC_TRUE;
00111 p_sys->i_data = 0;
00112
00113 p_sys->b_chan_reorder = 0;
00114
00115 return VLC_SUCCESS;
00116 }
00117
00118
00119
00120
00121 static void Close( vlc_object_t * p_this )
00122 {
00123 sout_mux_t *p_mux = (sout_mux_t*)p_this;
00124 sout_mux_sys_t *p_sys = p_mux->p_sys;
00125 free( p_sys );
00126 }
00127
00128 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
00129 {
00130 vlc_bool_t *pb_bool;
00131 char **ppsz;
00132
00133 switch( i_query )
00134 {
00135 case MUX_CAN_ADD_STREAM_WHILE_MUXING:
00136 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00137 *pb_bool = VLC_FALSE;
00138 return VLC_SUCCESS;
00139
00140 case MUX_GET_ADD_STREAM_WAIT:
00141 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00142 *pb_bool = VLC_TRUE;
00143 return VLC_SUCCESS;
00144
00145 case MUX_GET_MIME:
00146 ppsz = (char**)va_arg( args, char ** );
00147 *ppsz = strdup( "audio/wav" );
00148 return VLC_SUCCESS;
00149
00150 default:
00151 return VLC_EGENERIC;
00152 }
00153 }
00154 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
00155 {
00156 GUID subformat_guid = {0, 0, 0x10,{0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71}};
00157 sout_mux_sys_t *p_sys = p_mux->p_sys;
00158 WAVEFORMATEX *p_waveformat = &p_sys->waveformat.Format;
00159 int i_bytes_per_sample, i_format;
00160 vlc_bool_t b_ext;
00161
00162 if( p_input->p_fmt->i_cat != AUDIO_ES )
00163 {
00164 msg_Dbg( p_mux, "not an audio stream" );
00165 return VLC_EGENERIC;
00166 }
00167
00168 if( p_sys->b_used )
00169 {
00170 msg_Dbg( p_mux, "can't add more than 1 stream" );
00171 return VLC_EGENERIC;
00172 }
00173
00174 msg_Dbg( p_mux, "adding input %i channels, %iHz",
00175 p_input->p_fmt->audio.i_channels,
00176 p_input->p_fmt->audio.i_rate );
00177
00178 p_sys->i_channel_mask = 0;
00179 if( p_input->p_fmt->audio.i_physical_channels )
00180 {
00181 unsigned int i;
00182
00183 for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ )
00184 {
00185 if( p_input->p_fmt->audio.i_physical_channels & pi_channels_src[i])
00186 p_sys->i_channel_mask |= pi_channels_in[i];
00187 }
00188
00189 p_sys->b_chan_reorder =
00190 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
00191 p_sys->i_channel_mask,
00192 p_input->p_fmt->audio.i_channels,
00193 p_sys->pi_chan_table );
00194
00195 msg_Dbg( p_mux, "channel mask: %x, reordering: %i",
00196 p_sys->i_channel_mask, (int)p_sys->b_chan_reorder );
00197 }
00198
00199 i_format = p_input->p_fmt->i_codec == VLC_FOURCC('f', 'l', '3', '2') ?
00200 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
00201 b_ext = p_sys->b_ext = p_input->p_fmt->audio.i_channels > 2;
00202
00203
00204 p_sys->waveheader[0] = VLC_FOURCC('R', 'I', 'F', 'F');
00205 SetDWLE( &p_sys->waveheader[1], 0 );
00206 p_sys->waveheader[2] = VLC_FOURCC('W', 'A', 'V', 'E');
00207 p_sys->waveheader[3] = VLC_FOURCC('f', 'm', 't', ' ');
00208 SetDWLE( &p_sys->waveheader[4], b_ext ? 40 : 16 );
00209
00210 p_sys->waveheader2[0] = VLC_FOURCC('d', 'a', 't', 'a');
00211 SetDWLE( &p_sys->waveheader2[1], 0 );
00212
00213
00214 memset( &p_sys->waveformat, 0, sizeof(WAVEFORMATEXTENSIBLE) );
00215 SetWLE( &p_waveformat->wFormatTag,
00216 b_ext ? WAVE_FORMAT_EXTENSIBLE : i_format );
00217 SetWLE( &p_waveformat->nChannels,
00218 p_input->p_fmt->audio.i_channels );
00219 SetDWLE( &p_waveformat->nSamplesPerSec, p_input->p_fmt->audio.i_rate );
00220 i_bytes_per_sample = p_input->p_fmt->audio.i_channels *
00221 p_input->p_fmt->audio.i_bitspersample / 8;
00222 SetDWLE( &p_waveformat->nAvgBytesPerSec,
00223 i_bytes_per_sample * p_input->p_fmt->audio.i_rate );
00224 SetWLE( &p_waveformat->nBlockAlign, i_bytes_per_sample );
00225 SetWLE( &p_waveformat->wBitsPerSample,
00226 p_input->p_fmt->audio.i_bitspersample );
00227 SetWLE( &p_waveformat->cbSize, 22 );
00228 SetWLE( &p_sys->waveformat.Samples.wValidBitsPerSample,
00229 p_input->p_fmt->audio.i_bitspersample );
00230 SetDWLE( &p_sys->waveformat.dwChannelMask,
00231 p_sys->i_channel_mask );
00232 p_sys->waveformat.SubFormat = subformat_guid;
00233 p_sys->waveformat.SubFormat.Data1 = i_format;
00234
00235
00236 p_sys->b_used = VLC_TRUE;
00237
00238 return VLC_SUCCESS;
00239 }
00240
00241 static block_t *GetHeader( sout_mux_t *p_mux )
00242 {
00243 sout_mux_sys_t *p_sys = p_mux->p_sys;
00244 block_t *p_block =
00245 block_New( p_mux, sizeof( WAVEFORMATEXTENSIBLE ) + 7 * 4 );
00246
00247 SetDWLE( &p_sys->waveheader[1],
00248 20 + (p_sys->b_ext ? 40 : 16) + p_sys->i_data );
00249 SetDWLE( &p_sys->waveheader2[1], p_sys->i_data );
00250
00251 memcpy( p_block->p_buffer, &p_sys->waveheader, 5 * 4 );
00252 memcpy( p_block->p_buffer + 5 * 4, &p_sys->waveformat,
00253 sizeof( WAVEFORMATEXTENSIBLE ) );
00254 memcpy( p_block->p_buffer + 5 * 4 +
00255 (p_sys->b_ext ? sizeof( WAVEFORMATEXTENSIBLE ) : 16),
00256 &p_sys->waveheader2, 2 * 4 );
00257 if( !p_sys->b_ext ) p_block->i_buffer -= 24;
00258 return p_block;
00259 }
00260
00261 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
00262 {
00263 msg_Dbg( p_mux, "removing input" );
00264
00265 msg_Dbg( p_mux, "writing header data" );
00266 if( !sout_AccessOutSeek( p_mux->p_access, 0 ) )
00267 {
00268 sout_AccessOutWrite( p_mux->p_access, GetHeader( p_mux ) );
00269 }
00270
00271 return VLC_SUCCESS;
00272 }
00273
00274 static int Mux( sout_mux_t *p_mux )
00275 {
00276 sout_mux_sys_t *p_sys = p_mux->p_sys;
00277 sout_input_t *p_input;
00278
00279 if( !p_mux->i_nb_inputs ) return VLC_SUCCESS;
00280
00281 if( p_sys->b_header )
00282 {
00283 msg_Dbg( p_mux, "writing header data" );
00284 sout_AccessOutWrite( p_mux->p_access, GetHeader( p_mux ) );
00285 }
00286 p_sys->b_header = VLC_FALSE;
00287
00288 p_input = p_mux->pp_inputs[0];
00289 while( p_input->p_fifo->i_depth > 0 )
00290 {
00291 block_t *p_block = block_FifoGet( p_input->p_fifo );
00292 p_sys->i_data += p_block->i_buffer;
00293
00294
00295 if( p_sys->b_chan_reorder )
00296 aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
00297 p_input->p_fmt->audio.i_channels,
00298 p_sys->pi_chan_table,
00299 p_input->p_fmt->audio.i_bitspersample );
00300
00301 sout_AccessOutWrite( p_mux->p_access, p_block );
00302 }
00303
00304 return VLC_SUCCESS;
00305 }