Mercurial > mplayer.hg
comparison libao2/ao_pcm.c @ 30666:b20827f16dd0
Output WAVE_FORMAT_EXTENSIBLE extension in wave header when waveheader
option is enabled (default) and channels > 2.
author | tack |
---|---|
date | Mon, 22 Feb 2010 14:24:53 +0000 |
parents | 32725ca88fed |
children | f5478d5be47e |
comparison
equal
deleted
inserted
replaced
30665:16bb5e90205f | 30666:b20827f16dd0 |
---|---|
59 #define WAV_ID_WAVE 0x45564157 /* "WAVE" */ | 59 #define WAV_ID_WAVE 0x45564157 /* "WAVE" */ |
60 #define WAV_ID_FMT 0x20746d66 /* "fmt " */ | 60 #define WAV_ID_FMT 0x20746d66 /* "fmt " */ |
61 #define WAV_ID_DATA 0x61746164 /* "data" */ | 61 #define WAV_ID_DATA 0x61746164 /* "data" */ |
62 #define WAV_ID_PCM 0x0001 | 62 #define WAV_ID_PCM 0x0001 |
63 #define WAV_ID_FLOAT_PCM 0x0003 | 63 #define WAV_ID_FLOAT_PCM 0x0003 |
64 | 64 #define WAV_ID_FORMAT_EXTENSIBLE 0xfffe |
65 struct WaveHeader | |
66 { | |
67 uint32_t riff; | |
68 uint32_t file_length; | |
69 uint32_t wave; | |
70 uint32_t fmt; | |
71 uint32_t fmt_length; | |
72 uint16_t fmt_tag; | |
73 uint16_t channels; | |
74 uint32_t sample_rate; | |
75 uint32_t bytes_per_second; | |
76 uint16_t block_align; | |
77 uint16_t bits; | |
78 uint32_t data; | |
79 uint32_t data_length; | |
80 }; | |
81 | 65 |
82 /* init with default values */ | 66 /* init with default values */ |
83 static struct WaveHeader wavhdr; | |
84 static uint64_t data_length; | 67 static uint64_t data_length; |
85 | |
86 static FILE *fp = NULL; | 68 static FILE *fp = NULL; |
69 | |
70 | |
71 static void fput16le(uint16_t val, FILE *fp) { | |
72 uint8_t bytes[2] = {val, val >> 8}; | |
73 fwrite(bytes, 1, 2, fp); | |
74 } | |
75 | |
76 static void fput32le(uint32_t val, FILE *fp) { | |
77 uint8_t bytes[4] = {val, val >> 8, val >> 16, val >> 24}; | |
78 fwrite(bytes, 1, 4, fp); | |
79 } | |
80 | |
81 static void write_wave_header(FILE *fp, uint64_t data_length) { | |
82 int use_waveex = (ao_data.channels >= 5 && ao_data.channels <= 8); | |
83 uint16_t fmt = (ao_data.format == AF_FORMAT_FLOAT_LE) ? WAV_ID_FLOAT_PCM : WAV_ID_PCM; | |
84 uint32_t fmt_chunk_size = use_waveex ? 40 : 16; | |
85 int bits = af_fmt2bits(ao_data.format); | |
86 | |
87 // Master RIFF chunk | |
88 fput32le(WAV_ID_RIFF, fp); | |
89 // RIFF chunk size: 'WAVE' + 'fmt ' + 4 + fmt_chunk_size + data chunk hdr (8) + data length | |
90 fput32le(12 + fmt_chunk_size + 8 + data_length, fp); | |
91 fput32le(WAV_ID_WAVE, fp); | |
92 | |
93 // Format chunk | |
94 fput32le(WAV_ID_FMT, fp); | |
95 fput32le(fmt_chunk_size, fp); | |
96 fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp); | |
97 fput16le(ao_data.channels, fp); | |
98 fput32le(ao_data.samplerate, fp); | |
99 fput32le(ao_data.bps, fp); | |
100 fput16le(ao_data.channels * (bits / 8), fp); | |
101 fput16le(bits, fp); | |
102 | |
103 if (use_waveex) { | |
104 // Extension chunk | |
105 fput16le(22, fp); | |
106 fput16le(bits, fp); | |
107 switch (ao_data.channels) { | |
108 case 5: | |
109 fput32le(0x0607, fp); // L R C Lb Rb | |
110 break; | |
111 case 6: | |
112 fput32le(0x060f, fp); // L R C Lb Rb LFE | |
113 break; | |
114 case 7: | |
115 fput32le(0x0727, fp); // L R C Cb Ls Rs LFE | |
116 break; | |
117 case 8: | |
118 fput32le(0x063f, fp); // L R C Lb Rb Ls Rs LFE | |
119 break; | |
120 } | |
121 // 2 bytes format + 14 bytes guid | |
122 fput32le(fmt, fp); | |
123 fput32le(0x00100000, fp); | |
124 fput32le(0xAA000080, fp); | |
125 fput32le(0x719B3800, fp); | |
126 } | |
127 | |
128 // Data chunk | |
129 fput32le(WAV_ID_DATA, fp); | |
130 fput32le(data_length, fp); | |
131 } | |
87 | 132 |
88 // to set/get/query special features/parameters | 133 // to set/get/query special features/parameters |
89 static int control(int cmd,void *arg){ | 134 static int control(int cmd,void *arg){ |
90 return -1; | 135 return -1; |
91 } | 136 } |
92 | 137 |
93 // open & setup audio device | 138 // open & setup audio device |
94 // return: 1=success 0=fail | 139 // return: 1=success 0=fail |
95 static int init(int rate,int channels,int format,int flags){ | 140 static int init(int rate,int channels,int format,int flags){ |
96 int bits; | |
97 const opt_t subopts[] = { | 141 const opt_t subopts[] = { |
98 {"waveheader", OPT_ARG_BOOL, &ao_pcm_waveheader, NULL}, | 142 {"waveheader", OPT_ARG_BOOL, &ao_pcm_waveheader, NULL}, |
99 {"file", OPT_ARG_MSTRZ, &ao_outputfilename, NULL}, | 143 {"file", OPT_ARG_MSTRZ, &ao_outputfilename, NULL}, |
100 {"fast", OPT_ARG_BOOL, &fast, NULL}, | 144 {"fast", OPT_ARG_BOOL, &fast, NULL}, |
101 {NULL} | 145 {NULL} |
128 format = AF_FORMAT_S16_LE; | 172 format = AF_FORMAT_S16_LE; |
129 break; | 173 break; |
130 } | 174 } |
131 } | 175 } |
132 | 176 |
133 bits = af_fmt2bits(format); | |
134 | |
135 ao_data.outburst = 65536; | 177 ao_data.outburst = 65536; |
136 ao_data.buffersize= 2*65536; | 178 ao_data.buffersize= 2*65536; |
137 ao_data.channels=channels; | 179 ao_data.channels=channels; |
138 ao_data.samplerate=rate; | 180 ao_data.samplerate=rate; |
139 ao_data.format=format; | 181 ao_data.format=format; |
140 ao_data.bps=channels*rate*(bits/8); | 182 ao_data.bps=channels*rate*(af_fmt2bits(format)/8); |
141 | |
142 wavhdr.riff = le2me_32(WAV_ID_RIFF); | |
143 wavhdr.wave = le2me_32(WAV_ID_WAVE); | |
144 wavhdr.fmt = le2me_32(WAV_ID_FMT); | |
145 wavhdr.fmt_length = le2me_32(16); | |
146 wavhdr.fmt_tag = le2me_16(format == AF_FORMAT_FLOAT_LE ? WAV_ID_FLOAT_PCM : WAV_ID_PCM); | |
147 wavhdr.channels = le2me_16(ao_data.channels); | |
148 wavhdr.sample_rate = le2me_32(ao_data.samplerate); | |
149 wavhdr.bytes_per_second = le2me_32(ao_data.bps); | |
150 wavhdr.bits = le2me_16(bits); | |
151 wavhdr.block_align = le2me_16(ao_data.channels * (bits / 8)); | |
152 | |
153 wavhdr.data = le2me_32(WAV_ID_DATA); | |
154 wavhdr.data_length=le2me_32(0x7ffff000); | |
155 wavhdr.file_length = wavhdr.data_length + sizeof(wavhdr) - 8; | |
156 | 183 |
157 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_PCM_FileInfo, ao_outputfilename, | 184 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_PCM_FileInfo, ao_outputfilename, |
158 (ao_pcm_waveheader?"WAVE":"RAW PCM"), rate, | 185 (ao_pcm_waveheader?"WAVE":"RAW PCM"), rate, |
159 (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format)); | 186 (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format)); |
160 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_PCM_HintInfo); | 187 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_PCM_HintInfo); |
161 | 188 |
162 fp = fopen(ao_outputfilename, "wb"); | 189 fp = fopen(ao_outputfilename, "wb"); |
163 if(fp) { | 190 if(fp) { |
164 if(ao_pcm_waveheader){ /* Reserve space for wave header */ | 191 if(ao_pcm_waveheader){ /* Reserve space for wave header */ |
165 fwrite(&wavhdr,sizeof(wavhdr),1,fp); | 192 write_wave_header(fp, 0x7ffff000); |
166 } | 193 } |
167 return 1; | 194 return 1; |
168 } | 195 } |
169 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_PCM_CantOpenOutputFile, | 196 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_PCM_CantOpenOutputFile, |
170 ao_outputfilename); | 197 ao_outputfilename); |
184 if (broken_seek || fseek(fp, 0, SEEK_SET) != 0) | 211 if (broken_seek || fseek(fp, 0, SEEK_SET) != 0) |
185 mp_msg(MSGT_AO, MSGL_ERR, "Could not seek to start, WAV size headers not updated!\n"); | 212 mp_msg(MSGT_AO, MSGL_ERR, "Could not seek to start, WAV size headers not updated!\n"); |
186 else if (data_length > 0x7ffff000) | 213 else if (data_length > 0x7ffff000) |
187 mp_msg(MSGT_AO, MSGL_ERR, "File larger than allowed for WAV files, may play truncated!\n"); | 214 mp_msg(MSGT_AO, MSGL_ERR, "File larger than allowed for WAV files, may play truncated!\n"); |
188 else { | 215 else { |
189 wavhdr.file_length = data_length + sizeof(wavhdr) - 8; | 216 write_wave_header(fp, data_length); |
190 wavhdr.file_length = le2me_32(wavhdr.file_length); | |
191 wavhdr.data_length = le2me_32(data_length); | |
192 fwrite(&wavhdr,sizeof(wavhdr),1,fp); | |
193 } | 217 } |
194 } | 218 } |
195 fclose(fp); | 219 fclose(fp); |
196 if (ao_outputfilename) | 220 if (ao_outputfilename) |
197 free(ao_outputfilename); | 221 free(ao_outputfilename); |
239 } | 263 } |
240 } | 264 } |
241 #endif | 265 #endif |
242 | 266 |
243 if (ao_data.channels == 5 || ao_data.channels == 6 || ao_data.channels == 8) { | 267 if (ao_data.channels == 5 || ao_data.channels == 6 || ao_data.channels == 8) { |
244 int frame_size = le2me_16(wavhdr.bits) / 8; | 268 int frame_size = af_fmt2bits(ao_data.format) / 8; |
245 len -= len % (frame_size * ao_data.channels); | 269 len -= len % (frame_size * ao_data.channels); |
246 reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, | 270 reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, |
247 AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT, | 271 AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT, |
248 ao_data.channels, | 272 ao_data.channels, |
249 len / frame_size, frame_size); | 273 len / frame_size, frame_size); |