Add a comment that explains why this header has no multiple inclusion guards.
[mplayer/greg.git] / libao2 / ao_pcm.c
blob7182630fe20deb4255a325f8422db90c3683b35a
1 #include "config.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include "libavutil/common.h"
8 #include "mpbswap.h"
9 #include "subopt-helper.h"
10 #include "libaf/af_format.h"
11 #include "libaf/reorder_ch.h"
12 #include "audio_out.h"
13 #include "audio_out_internal.h"
14 #include "mp_msg.h"
15 #include "help_mp.h"
18 static ao_info_t info =
20 "RAW PCM/WAVE file writer audio output",
21 "pcm",
22 "Atmosfear",
26 LIBAO_EXTERN(pcm)
28 extern int vo_pts;
30 static char *ao_outputfilename = NULL;
31 static int ao_pcm_waveheader = 1;
32 static int fast = 0;
34 #define WAV_ID_RIFF 0x46464952 /* "RIFF" */
35 #define WAV_ID_WAVE 0x45564157 /* "WAVE" */
36 #define WAV_ID_FMT 0x20746d66 /* "fmt " */
37 #define WAV_ID_DATA 0x61746164 /* "data" */
38 #define WAV_ID_PCM 0x0001
40 struct WaveHeader
42 uint32_t riff;
43 uint32_t file_length;
44 uint32_t wave;
45 uint32_t fmt;
46 uint32_t fmt_length;
47 uint16_t fmt_tag;
48 uint16_t channels;
49 uint32_t sample_rate;
50 uint32_t bytes_per_second;
51 uint16_t block_align;
52 uint16_t bits;
53 uint32_t data;
54 uint32_t data_length;
57 /* init with default values */
58 static struct WaveHeader wavhdr;
60 static FILE *fp = NULL;
62 // to set/get/query special features/parameters
63 static int control(int cmd,void *arg){
64 return -1;
67 // open & setup audio device
68 // return: 1=success 0=fail
69 static int init(int rate,int channels,int format,int flags){
70 int bits;
71 opt_t subopts[] = {
72 {"waveheader", OPT_ARG_BOOL, &ao_pcm_waveheader, NULL},
73 {"file", OPT_ARG_MSTRZ, &ao_outputfilename, NULL},
74 {"fast", OPT_ARG_BOOL, &fast, NULL},
75 {NULL}
77 // set defaults
78 ao_pcm_waveheader = 1;
80 if (subopt_parse(ao_subdevice, subopts) != 0) {
81 return 0;
83 if (!ao_outputfilename){
84 ao_outputfilename =
85 strdup(ao_pcm_waveheader?"audiodump.wav":"audiodump.pcm");
88 /* bits is only equal to format if (format == 8) or (format == 16);
89 this means that the following "if" is a kludge and should
90 really be a switch to be correct in all cases */
92 bits=8;
93 switch(format){
94 case AF_FORMAT_S8:
95 format=AF_FORMAT_U8;
96 case AF_FORMAT_U8:
97 break;
98 case AF_FORMAT_AC3:
99 bits=16;
100 break;
101 default:
102 format=AF_FORMAT_S16_LE;
103 bits=16;
104 break;
107 ao_data.outburst = 65536;
108 ao_data.buffersize= 2*65536;
109 ao_data.channels=channels;
110 ao_data.samplerate=rate;
111 ao_data.format=format;
112 ao_data.bps=channels*rate*(bits/8);
114 wavhdr.riff = le2me_32(WAV_ID_RIFF);
115 wavhdr.wave = le2me_32(WAV_ID_WAVE);
116 wavhdr.fmt = le2me_32(WAV_ID_FMT);
117 wavhdr.fmt_length = le2me_32(16);
118 wavhdr.fmt_tag = le2me_16(WAV_ID_PCM);
119 wavhdr.channels = le2me_16(ao_data.channels);
120 wavhdr.sample_rate = le2me_32(ao_data.samplerate);
121 wavhdr.bytes_per_second = le2me_32(ao_data.bps);
122 wavhdr.bits = le2me_16(bits);
123 wavhdr.block_align = le2me_16(ao_data.channels * (bits / 8));
125 wavhdr.data = le2me_32(WAV_ID_DATA);
126 wavhdr.data_length=le2me_32(0x7ffff000);
127 wavhdr.file_length = wavhdr.data_length + sizeof(wavhdr) - 8;
129 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_PCM_FileInfo, ao_outputfilename,
130 (ao_pcm_waveheader?"WAVE":"RAW PCM"), rate,
131 (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
132 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_PCM_HintInfo);
134 fp = fopen(ao_outputfilename, "wb");
135 if(fp) {
136 if(ao_pcm_waveheader){ /* Reserve space for wave header */
137 fwrite(&wavhdr,sizeof(wavhdr),1,fp);
138 wavhdr.file_length=wavhdr.data_length=0;
140 return 1;
142 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_PCM_CantOpenOutputFile,
143 ao_outputfilename);
144 return 0;
147 // close audio device
148 static void uninit(int immed){
150 if(ao_pcm_waveheader && fseek(fp, 0, SEEK_SET) == 0){ /* Write wave header */
151 wavhdr.file_length = wavhdr.data_length + sizeof(wavhdr) - 8;
152 wavhdr.file_length = le2me_32(wavhdr.file_length);
153 wavhdr.data_length = le2me_32(wavhdr.data_length);
154 fwrite(&wavhdr,sizeof(wavhdr),1,fp);
156 fclose(fp);
157 if (ao_outputfilename)
158 free(ao_outputfilename);
159 ao_outputfilename = NULL;
162 // stop playing and empty buffers (for seeking/pause)
163 static void reset(void){
167 // stop playing, keep buffers (for pause)
168 static void audio_pause(void)
170 // for now, just call reset();
171 reset();
174 // resume playing, after audio_pause()
175 static void audio_resume(void)
179 // return: how many bytes can be played without blocking
180 static int get_space(void){
182 if(vo_pts)
183 return ao_data.pts < vo_pts + fast * 30000 ? ao_data.outburst : 0;
184 return ao_data.outburst;
187 // plays 'len' bytes of 'data'
188 // it should round it down to outburst*n
189 // return: number of bytes played
190 static int play(void* data,int len,int flags){
192 // let libaf to do the conversion...
193 #if 0
194 //#ifdef WORDS_BIGENDIAN
195 if (ao_data.format == AFMT_S16_LE) {
196 unsigned short *buffer = (unsigned short *) data;
197 register int i;
198 for(i = 0; i < len/2; ++i) {
199 buffer[i] = le2me_16(buffer[i]);
202 #endif
204 if (ao_data.channels == 6 || ao_data.channels == 5) {
205 int frame_size = le2me_16(wavhdr.bits) / 8;
206 len -= len % (frame_size * ao_data.channels);
207 reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
208 AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
209 ao_data.channels,
210 len / frame_size, frame_size);
213 //printf("PCM: Writing chunk!\n");
214 fwrite(data,len,1,fp);
216 if(ao_pcm_waveheader)
217 wavhdr.data_length += len;
219 return len;
222 // return: delay in seconds between first and last sample in buffer
223 static float get_delay(void){
225 return 0.0;