wav.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:10k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * wav.c: wav muxer module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 VideoLAN
  5.  * $Id: wav.c 8862 2004-09-30 17:21:40Z gbazin $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>
  27. #include <vlc/vlc.h>
  28. #include <vlc/aout.h>
  29. #include <vlc/sout.h>
  30. #include "codecs.h"
  31. /*****************************************************************************
  32.  * Module descriptor
  33.  *****************************************************************************/
  34. static int  Open   ( vlc_object_t * );
  35. static void Close  ( vlc_object_t * );
  36. vlc_module_begin();
  37.     set_description( _("WAV muxer") );
  38.     set_capability( "sout mux", 5 );
  39.     set_callbacks( Open, Close );
  40.     add_shortcut( "wav" );
  41. vlc_module_end();
  42. /*****************************************************************************
  43.  * Exported prototypes
  44.  *****************************************************************************/
  45. static int Control  ( sout_mux_t *, int, va_list );
  46. static int AddStream( sout_mux_t *, sout_input_t * );
  47. static int DelStream( sout_mux_t *, sout_input_t * );
  48. static int Mux      ( sout_mux_t * );
  49. #define MAX_CHANNELS 6
  50. struct sout_mux_sys_t
  51. {
  52.     vlc_bool_t b_used;
  53.     vlc_bool_t b_header;
  54.     vlc_bool_t b_ext;
  55.     uint32_t i_data;
  56.     /* Wave header for the output data */
  57.     uint32_t waveheader[5];
  58.     WAVEFORMATEXTENSIBLE waveformat;
  59.     uint32_t waveheader2[2];
  60.     uint32_t i_channel_mask;
  61.     vlc_bool_t b_chan_reorder;              /* do we need channel reordering */
  62.     int pi_chan_table[AOUT_CHAN_MAX];
  63. };
  64. static const uint32_t pi_channels_src[] =
  65.     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
  66.       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
  67.       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
  68.       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
  69. static const uint32_t pi_channels_in[] =
  70.     { WAVE_SPEAKER_FRONT_LEFT, WAVE_SPEAKER_FRONT_RIGHT,
  71.       WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT,
  72.       WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT,
  73.       WAVE_SPEAKER_FRONT_CENTER, WAVE_SPEAKER_LOW_FREQUENCY, 0 };
  74. static const uint32_t pi_channels_out[] =
  75.     { WAVE_SPEAKER_FRONT_LEFT, WAVE_SPEAKER_FRONT_RIGHT,
  76.       WAVE_SPEAKER_FRONT_CENTER, WAVE_SPEAKER_LOW_FREQUENCY,
  77.       WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT,
  78.       WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT, 0 };
  79. /*****************************************************************************
  80.  * Open:
  81.  *****************************************************************************/
  82. static int Open( vlc_object_t *p_this )
  83. {
  84.     sout_mux_t *p_mux = (sout_mux_t*)p_this;
  85.     sout_mux_sys_t  *p_sys;
  86.     p_mux->pf_control  = Control;
  87.     p_mux->pf_addstream = AddStream;
  88.     p_mux->pf_delstream = DelStream;
  89.     p_mux->pf_mux       = Mux;
  90.     p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
  91.     p_sys->b_used   = VLC_FALSE;
  92.     p_sys->b_header = VLC_TRUE;
  93.     p_sys->i_data   = 0;
  94.     p_sys->b_chan_reorder = 0;
  95.     return VLC_SUCCESS;
  96. }
  97. /*****************************************************************************
  98.  * Close:
  99.  *****************************************************************************/
  100. static void Close( vlc_object_t * p_this )
  101. {
  102.     sout_mux_t *p_mux = (sout_mux_t*)p_this;
  103.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  104.     free( p_sys );
  105. }
  106. static int Control( sout_mux_t *p_mux, int i_query, va_list args )
  107. {
  108.     vlc_bool_t *pb_bool;
  109.     char **ppsz;
  110.    switch( i_query )
  111.    {
  112.        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
  113.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  114.            *pb_bool = VLC_FALSE;
  115.            return VLC_SUCCESS;
  116.        case MUX_GET_ADD_STREAM_WAIT:
  117.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  118.            *pb_bool = VLC_TRUE;
  119.            return VLC_SUCCESS;
  120.        case MUX_GET_MIME:
  121.            ppsz = (char**)va_arg( args, char ** );
  122.            *ppsz = strdup( "audio/wav" );
  123.            return VLC_SUCCESS;
  124.         default:
  125.             return VLC_EGENERIC;
  126.    }
  127. }
  128. static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
  129. {
  130.     GUID subformat_guid = {0, 0, 0x10,{0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71}};
  131.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  132.     WAVEFORMATEX *p_waveformat = &p_sys->waveformat.Format;
  133.     int i_bytes_per_sample, i_format, i;
  134.     vlc_bool_t b_ext;
  135.     if( p_input->p_fmt->i_cat != AUDIO_ES )
  136.     {
  137.         msg_Dbg( p_mux, "not an audio stream" );
  138.         return VLC_EGENERIC;
  139.     }
  140.     if( p_sys->b_used )
  141.     {
  142.         msg_Dbg( p_mux, "can't add more than 1 stream" );
  143.         return VLC_EGENERIC;
  144.     }
  145.     msg_Dbg( p_mux, "adding input %i channels, %iHz",
  146.              p_input->p_fmt->audio.i_channels,
  147.              p_input->p_fmt->audio.i_rate );
  148.     p_sys->i_channel_mask = 0;
  149.     if( p_input->p_fmt->audio.i_physical_channels )
  150.     {
  151.         for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ )
  152.         {
  153.             if( p_input->p_fmt->audio.i_physical_channels & pi_channels_src[i])
  154.                 p_sys->i_channel_mask |= pi_channels_in[i];
  155.         }
  156.         p_sys->b_chan_reorder =
  157.             aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
  158.                                       p_sys->i_channel_mask,
  159.                                       p_input->p_fmt->audio.i_channels,
  160.                                       p_sys->pi_chan_table );
  161.         msg_Dbg( p_mux, "channel mask: %x, reordering: %i",
  162.                  p_sys->i_channel_mask, (int)p_sys->b_chan_reorder );
  163.     }
  164.     i_format = p_input->p_fmt->i_codec == VLC_FOURCC('f', 'l', '3', '2') ?
  165.         WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
  166.     b_ext = p_sys->b_ext = p_input->p_fmt->audio.i_channels > 2;
  167.     /* Build a WAV header for the output data */
  168.     p_sys->waveheader[0] = VLC_FOURCC('R', 'I', 'F', 'F'); /* MainChunkID */
  169.     SetDWLE( &p_sys->waveheader[1], 0 ); /* Length */
  170.     p_sys->waveheader[2] = VLC_FOURCC('W', 'A', 'V', 'E'); /* ChunkTypeID */
  171.     p_sys->waveheader[3] = VLC_FOURCC('f', 'm', 't', ' '); /* SubChunkID */
  172.     SetDWLE( &p_sys->waveheader[4], b_ext ? 40 : 16 ); /* SubChunkLength */
  173.     p_sys->waveheader2[0] = VLC_FOURCC('d', 'a', 't', 'a'); /* DataChunkID */
  174.     SetDWLE( &p_sys->waveheader2[1], 0 ); /* DataLength */
  175.     /* Build a WAVEVFORMAT header for the output data */
  176.     memset( &p_sys->waveformat, 0, sizeof(WAVEFORMATEXTENSIBLE) );
  177.     SetWLE( &p_waveformat->wFormatTag,
  178.             b_ext ? WAVE_FORMAT_EXTENSIBLE : i_format );
  179.     SetWLE( &p_waveformat->nChannels,
  180.             p_input->p_fmt->audio.i_channels );
  181.     SetDWLE( &p_waveformat->nSamplesPerSec, p_input->p_fmt->audio.i_rate );
  182.     i_bytes_per_sample = p_input->p_fmt->audio.i_channels *
  183.         p_input->p_fmt->audio.i_bitspersample / 8;
  184.     SetDWLE( &p_waveformat->nAvgBytesPerSec,
  185.              i_bytes_per_sample * p_input->p_fmt->audio.i_rate );
  186.     SetWLE( &p_waveformat->nBlockAlign, i_bytes_per_sample );
  187.     SetWLE( &p_waveformat->wBitsPerSample,
  188.             p_input->p_fmt->audio.i_bitspersample );
  189.     SetWLE( &p_waveformat->cbSize, 22 );
  190.     SetWLE( &p_sys->waveformat.Samples.wValidBitsPerSample,
  191.             p_input->p_fmt->audio.i_bitspersample );
  192.     SetDWLE( &p_sys->waveformat.dwChannelMask,
  193.              p_sys->i_channel_mask );
  194.     p_sys->waveformat.SubFormat = subformat_guid;
  195.     p_sys->waveformat.SubFormat.Data1 = i_format;
  196.     p_sys->b_used = VLC_TRUE;
  197.     return VLC_SUCCESS;
  198. }
  199. static block_t *GetHeader( sout_mux_t *p_mux )
  200. {
  201.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  202.     block_t *p_block =
  203.         block_New( p_mux, sizeof( WAVEFORMATEXTENSIBLE ) + 7 * 4 );
  204.     SetDWLE( &p_sys->waveheader[1],
  205.              20 + (p_sys->b_ext ? 40 : 16) + p_sys->i_data ); /* Length */
  206.     SetDWLE( &p_sys->waveheader2[1], p_sys->i_data ); /* DataLength */
  207.     memcpy( p_block->p_buffer, &p_sys->waveheader, 5 * 4 );
  208.     memcpy( p_block->p_buffer + 5 * 4, &p_sys->waveformat,
  209.             sizeof( WAVEFORMATEXTENSIBLE ) );
  210.     memcpy( p_block->p_buffer + 5 * 4 +
  211.             (p_sys->b_ext ? sizeof( WAVEFORMATEXTENSIBLE ) : 16),
  212.             &p_sys->waveheader2, 2 * 4 );
  213.     if( !p_sys->b_ext ) p_block->i_buffer -= 24;
  214.     return p_block;
  215. }
  216. static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
  217. {
  218.     msg_Dbg( p_mux, "removing input" );
  219.     msg_Dbg( p_mux, "writing header data" );
  220.     if( !sout_AccessOutSeek( p_mux->p_access, 0 ) )
  221.     {
  222.         sout_AccessOutWrite( p_mux->p_access, GetHeader( p_mux ) );
  223.     }
  224.     return VLC_SUCCESS;
  225. }
  226. static int Mux( sout_mux_t *p_mux )
  227. {
  228.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  229.     sout_input_t *p_input;
  230.     if( !p_mux->i_nb_inputs ) return VLC_SUCCESS;
  231.     if( p_sys->b_header )
  232.     {
  233.         msg_Dbg( p_mux, "writing header data" );
  234.         sout_AccessOutWrite( p_mux->p_access, GetHeader( p_mux ) );
  235.     }
  236.     p_sys->b_header = VLC_FALSE;
  237.     p_input = p_mux->pp_inputs[0];
  238.     while( p_input->p_fifo->i_depth > 0 )
  239.     {
  240.         block_t *p_block = block_FifoGet( p_input->p_fifo );
  241.         p_sys->i_data += p_block->i_buffer;
  242.         /* Do the channel reordering */
  243.         if( p_sys->b_chan_reorder )
  244.             aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
  245.                                  p_input->p_fmt->audio.i_channels,
  246.                                  p_sys->pi_chan_table,
  247.                                  p_input->p_fmt->audio.i_bitspersample );
  248.         sout_AccessOutWrite( p_mux->p_access, p_block );
  249.     }
  250.     return VLC_SUCCESS;
  251. }