* modules/mux/wav.c: start of a WAV audio file muxer.
[vlc.git] / modules / mux / wav.c
1 /*****************************************************************************
2  * wav.c: wav muxer module for vlc
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
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 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <vlc/vlc.h>
30 #include <vlc/sout.h>
31
32 #include "codecs.h"
33
34 /*****************************************************************************
35  * Module descriptor
36  *****************************************************************************/
37 static int  Open   ( vlc_object_t * );
38 static void Close  ( vlc_object_t * );
39
40 vlc_module_begin();
41     set_description( _("WAV muxer") );
42     set_capability( "sout mux", 5 );
43     set_callbacks( Open, Close );
44     add_shortcut( "wav" );
45 vlc_module_end();
46
47 /*****************************************************************************
48  * Exported prototypes
49  *****************************************************************************/
50 static int  Capability(sout_mux_t *, int, void *, void * );
51 static int  AddStream( sout_mux_t *, sout_input_t * );
52 static int  DelStream( sout_mux_t *, sout_input_t * );
53 static int  Mux      ( sout_mux_t * );
54
55 struct sout_mux_sys_t
56 {
57     vlc_bool_t b_used;
58     vlc_bool_t b_header;
59
60     /* Wave header for the output data */
61     WAVEHEADER waveheader;
62 };
63
64 /*****************************************************************************
65  * Open:
66  *****************************************************************************/
67 static int Open( vlc_object_t *p_this )
68 {
69     sout_mux_t *p_mux = (sout_mux_t*)p_this;
70     sout_mux_sys_t  *p_sys;
71
72     p_mux->pf_capacity  = Capability;
73     p_mux->pf_addstream = AddStream;
74     p_mux->pf_delstream = DelStream;
75     p_mux->pf_mux       = Mux;
76
77     p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
78     p_sys->b_used       = VLC_FALSE;
79     p_sys->b_header     = VLC_TRUE;
80
81     return VLC_SUCCESS;
82 }
83
84 /*****************************************************************************
85  * Close:
86  *****************************************************************************/
87 static void Close( vlc_object_t * p_this )
88 {
89     sout_mux_t *p_mux = (sout_mux_t*)p_this;
90     sout_mux_sys_t *p_sys = p_mux->p_sys;
91
92     free( p_sys );
93 }
94
95 static int Capability( sout_mux_t *p_mux, int i_query,
96                        void *p_args, void *p_answer )
97 {
98    switch( i_query )
99    {
100         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
101             *(vlc_bool_t*)p_answer = VLC_FALSE;
102             return SOUT_MUX_CAP_ERR_OK;
103         default:
104             return SOUT_MUX_CAP_ERR_UNIMPLEMENTED;
105    }
106 }
107
108 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
109 {
110     sout_mux_sys_t *p_sys = p_mux->p_sys;
111     int i_bytes_per_sample;
112
113     if( p_input->p_fmt->i_cat != AUDIO_ES )
114         msg_Dbg( p_mux, "not an audio stream" );
115
116     if( p_sys->b_used )
117     {
118         msg_Dbg( p_mux, "can't add more than 1 stream" );
119         return VLC_EGENERIC;
120     }
121
122     msg_Dbg( p_mux, "adding input %i channels, %iHz",
123              p_input->p_fmt->audio.i_channels,
124              p_input->p_fmt->audio.i_rate );
125
126     //p_input->p_fmt->i_codec;
127
128     /* Build a WAV header for the output data */
129     memset( &p_sys->waveheader, 0, sizeof(WAVEHEADER) );
130     SetWLE( &p_sys->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/
131     SetWLE( &p_sys->waveheader.BitsPerSample, 16);
132     p_sys->waveheader.MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F');
133     p_sys->waveheader.Length = 0;                     /* we just don't know */
134     p_sys->waveheader.ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E');
135     p_sys->waveheader.SubChunkID = VLC_FOURCC('f', 'm', 't', ' ');
136     SetDWLE( &p_sys->waveheader.SubChunkLength, 16 );
137     SetWLE( &p_sys->waveheader.Modus, p_input->p_fmt->audio.i_channels );
138     SetDWLE( &p_sys->waveheader.SampleFreq, p_input->p_fmt->audio.i_rate );
139     i_bytes_per_sample = p_input->p_fmt->audio.i_channels *
140         16 /*BitsPerSample*/ / 8;
141     SetWLE( &p_sys->waveheader.BytesPerSample, i_bytes_per_sample );
142     SetDWLE( &p_sys->waveheader.BytesPerSec,
143              i_bytes_per_sample * p_input->p_fmt->audio.i_rate );
144     p_sys->waveheader.DataChunkID = VLC_FOURCC('d', 'a', 't', 'a');
145     p_sys->waveheader.DataLength = 0;                 /* we just don't know */
146
147     p_sys->b_used = VLC_TRUE;
148
149     return VLC_SUCCESS;
150 }
151
152 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
153 {
154     msg_Dbg( p_mux, "removing input" );
155     return VLC_SUCCESS;
156 }
157
158 static int Mux( sout_mux_t *p_mux )
159 {
160     sout_mux_sys_t *p_sys = p_mux->p_sys;
161
162     if( !p_mux->i_nb_inputs ) return VLC_SUCCESS;
163
164     if( p_sys->b_header )
165     {
166         /* Return only the header */
167         block_t *p_block = block_New( p_mux, sizeof( WAVEHEADER ) );
168         memcpy( p_block->p_buffer, &p_sys->waveheader, sizeof(WAVEHEADER) );
169
170         msg_Dbg( p_mux, "writing header data" );
171         sout_AccessOutWrite( p_mux->p_access, p_block );
172     }
173     p_sys->b_header = VLC_FALSE;
174
175     while( p_mux->pp_inputs[0]->p_fifo->i_depth > 0 )
176     {
177         block_t *p_block = block_FifoGet( p_mux->pp_inputs[0]->p_fifo );
178         sout_AccessOutWrite( p_mux->p_access, p_block );
179     }
180
181     return VLC_SUCCESS;
182 }