7 #include "libavutil/common.h"
9 #include "subopt-helper.h"
10 #include "libaf/af_format.h"
11 #include "audio_out.h"
12 #include "audio_out_internal.h"
17 static ao_info_t info
=
19 "RAW PCM/WAVE file writer audio output",
29 static char *ao_outputfilename
= NULL
;
30 static int ao_pcm_waveheader
= 1;
33 #define WAV_ID_RIFF 0x46464952 /* "RIFF" */
34 #define WAV_ID_WAVE 0x45564157 /* "WAVE" */
35 #define WAV_ID_FMT 0x20746d66 /* "fmt " */
36 #define WAV_ID_DATA 0x61746164 /* "data" */
37 #define WAV_ID_PCM 0x0001
49 uint32_t bytes_per_second
;
56 /* init with default values */
57 static struct WaveHeader wavhdr
;
59 static FILE *fp
= NULL
;
61 // to set/get/query special features/parameters
62 static int control(int cmd
,void *arg
){
66 // open & setup audio device
67 // return: 1=success 0=fail
68 static int init(int rate
,int channels
,int format
,int flags
){
71 {"waveheader", OPT_ARG_BOOL
, &ao_pcm_waveheader
, NULL
},
72 {"file", OPT_ARG_MSTRZ
, &ao_outputfilename
, NULL
},
73 {"fast", OPT_ARG_BOOL
, &fast
, NULL
},
77 ao_pcm_waveheader
= 1;
79 if (subopt_parse(ao_subdevice
, subopts
) != 0) {
82 if (!ao_outputfilename
){
84 strdup(ao_pcm_waveheader
?"audiodump.wav":"audiodump.pcm");
87 /* bits is only equal to format if (format == 8) or (format == 16);
88 this means that the following "if" is a kludge and should
89 really be a switch to be correct in all cases */
98 format
=AF_FORMAT_S16_LE
;
103 ao_data
.outburst
= 65536;
104 ao_data
.buffersize
= 2*65536;
105 ao_data
.channels
=channels
;
106 ao_data
.samplerate
=rate
;
107 ao_data
.format
=format
;
108 ao_data
.bps
=channels
*rate
*(bits
/8);
110 wavhdr
.riff
= le2me_32(WAV_ID_RIFF
);
111 wavhdr
.wave
= le2me_32(WAV_ID_WAVE
);
112 wavhdr
.fmt
= le2me_32(WAV_ID_FMT
);
113 wavhdr
.fmt_length
= le2me_32(16);
114 wavhdr
.fmt_tag
= le2me_16(WAV_ID_PCM
);
115 wavhdr
.channels
= le2me_16(ao_data
.channels
);
116 wavhdr
.sample_rate
= le2me_32(ao_data
.samplerate
);
117 wavhdr
.bytes_per_second
= le2me_32(ao_data
.bps
);
118 wavhdr
.bits
= le2me_16(bits
);
119 wavhdr
.block_align
= le2me_16(ao_data
.channels
* (bits
/ 8));
121 wavhdr
.data
= le2me_32(WAV_ID_DATA
);
122 wavhdr
.data_length
=le2me_32(0x7ffff000);
123 wavhdr
.file_length
= wavhdr
.data_length
+ sizeof(wavhdr
) - 8;
125 mp_msg(MSGT_AO
, MSGL_INFO
, MSGTR_AO_PCM_FileInfo
, ao_outputfilename
,
126 (ao_pcm_waveheader
?"WAVE":"RAW PCM"), rate
,
127 (channels
> 1) ? "Stereo" : "Mono", af_fmt2str_short(format
));
128 mp_msg(MSGT_AO
, MSGL_INFO
, MSGTR_AO_PCM_HintInfo
);
130 fp
= fopen(ao_outputfilename
, "wb");
132 if(ao_pcm_waveheader
){ /* Reserve space for wave header */
133 fwrite(&wavhdr
,sizeof(wavhdr
),1,fp
);
134 wavhdr
.file_length
=wavhdr
.data_length
=0;
138 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_PCM_CantOpenOutputFile
,
143 // close audio device
144 static void uninit(int immed
){
146 if(ao_pcm_waveheader
&& fseek(fp
, 0, SEEK_SET
) == 0){ /* Write wave header */
147 wavhdr
.file_length
= wavhdr
.data_length
+ sizeof(wavhdr
) - 8;
148 wavhdr
.file_length
= le2me_32(wavhdr
.file_length
);
149 wavhdr
.data_length
= le2me_32(wavhdr
.data_length
);
150 fwrite(&wavhdr
,sizeof(wavhdr
),1,fp
);
153 if (ao_outputfilename
)
154 free(ao_outputfilename
);
155 ao_outputfilename
= NULL
;
158 // stop playing and empty buffers (for seeking/pause)
159 static void reset(void){
163 // stop playing, keep buffers (for pause)
164 static void audio_pause(void)
166 // for now, just call reset();
170 // resume playing, after audio_pause()
171 static void audio_resume(void)
175 // return: how many bytes can be played without blocking
176 static int get_space(void){
179 return ao_data
.pts
< vo_pts
+ fast
* 30000 ? ao_data
.outburst
: 0;
180 return ao_data
.outburst
;
183 // plays 'len' bytes of 'data'
184 // it should round it down to outburst*n
185 // return: number of bytes played
186 static int play(void* data
,int len
,int flags
){
188 // let libaf to do the conversion...
190 //#ifdef WORDS_BIGENDIAN
191 if (ao_data
.format
== AFMT_S16_LE
) {
192 unsigned short *buffer
= (unsigned short *) data
;
194 for(i
= 0; i
< len
/2; ++i
) {
195 buffer
[i
] = le2me_16(buffer
[i
]);
200 //printf("PCM: Writing chunk!\n");
201 fwrite(data
,len
,1,fp
);
203 if(ao_pcm_waveheader
)
204 wavhdr
.data_length
+= len
;
209 // return: delay in seconds between first and last sample in buffer
210 static float get_delay(void){