core: fix audio-only + framestep weird behavior
[mplayer/glamo.git] / libao2 / ao_pcm.c
blob64eda888f7074f58602ae3ae9f066e67dd2e0392
1 /*
2 * PCM audio output driver
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "libavutil/common.h"
28 #include "mpbswap.h"
29 #include "subopt-helper.h"
30 #include "libaf/af_format.h"
31 #include "libaf/reorder_ch.h"
32 #include "audio_out.h"
33 #include "audio_out_internal.h"
34 #include "mp_msg.h"
36 #ifdef __MINGW32__
37 // for GetFileType to detect pipes
38 #include <windows.h>
39 #endif
41 static const ao_info_t info =
43 "RAW PCM/WAVE file writer audio output",
44 "pcm",
45 "Atmosfear",
49 LIBAO_EXTERN(pcm)
51 extern int vo_pts;
53 static char *ao_outputfilename = NULL;
54 static int ao_pcm_waveheader = 1;
55 static int fast = 0;
57 #define WAV_ID_RIFF 0x46464952 /* "RIFF" */
58 #define WAV_ID_WAVE 0x45564157 /* "WAVE" */
59 #define WAV_ID_FMT 0x20746d66 /* "fmt " */
60 #define WAV_ID_DATA 0x61746164 /* "data" */
61 #define WAV_ID_PCM 0x0001
62 #define WAV_ID_FLOAT_PCM 0x0003
63 #define WAV_ID_FORMAT_EXTENSIBLE 0xfffe
65 /* init with default values */
66 static uint64_t data_length;
67 static FILE *fp = NULL;
70 static void fput16le(uint16_t val, FILE *fp) {
71 uint8_t bytes[2] = {val, val >> 8};
72 fwrite(bytes, 1, 2, fp);
75 static void fput32le(uint32_t val, FILE *fp) {
76 uint8_t bytes[4] = {val, val >> 8, val >> 16, val >> 24};
77 fwrite(bytes, 1, 4, fp);
80 static void write_wave_header(FILE *fp, uint64_t data_length) {
81 int use_waveex = (ao_data.channels >= 5 && ao_data.channels <= 8);
82 uint16_t fmt = (ao_data.format == AF_FORMAT_FLOAT_LE) ? WAV_ID_FLOAT_PCM : WAV_ID_PCM;
83 uint32_t fmt_chunk_size = use_waveex ? 40 : 16;
84 int bits = af_fmt2bits(ao_data.format);
86 // Master RIFF chunk
87 fput32le(WAV_ID_RIFF, fp);
88 // RIFF chunk size: 'WAVE' + 'fmt ' + 4 + fmt_chunk_size + data chunk hdr (8) + data length
89 fput32le(12 + fmt_chunk_size + 8 + data_length, fp);
90 fput32le(WAV_ID_WAVE, fp);
92 // Format chunk
93 fput32le(WAV_ID_FMT, fp);
94 fput32le(fmt_chunk_size, fp);
95 fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp);
96 fput16le(ao_data.channels, fp);
97 fput32le(ao_data.samplerate, fp);
98 fput32le(ao_data.bps, fp);
99 fput16le(ao_data.channels * (bits / 8), fp);
100 fput16le(bits, fp);
102 if (use_waveex) {
103 // Extension chunk
104 fput16le(22, fp);
105 fput16le(bits, fp);
106 switch (ao_data.channels) {
107 case 5:
108 fput32le(0x0607, fp); // L R C Lb Rb
109 break;
110 case 6:
111 fput32le(0x060f, fp); // L R C Lb Rb LFE
112 break;
113 case 7:
114 fput32le(0x0727, fp); // L R C Cb Ls Rs LFE
115 break;
116 case 8:
117 fput32le(0x063f, fp); // L R C Lb Rb Ls Rs LFE
118 break;
120 // 2 bytes format + 14 bytes guid
121 fput32le(fmt, fp);
122 fput32le(0x00100000, fp);
123 fput32le(0xAA000080, fp);
124 fput32le(0x719B3800, fp);
127 // Data chunk
128 fput32le(WAV_ID_DATA, fp);
129 fput32le(data_length, fp);
132 // to set/get/query special features/parameters
133 static int control(int cmd,void *arg){
134 return -1;
137 // open & setup audio device
138 // return: 1=success 0=fail
139 static int init(int rate,int channels,int format,int flags){
140 const opt_t subopts[] = {
141 {"waveheader", OPT_ARG_BOOL, &ao_pcm_waveheader, NULL},
142 {"file", OPT_ARG_MSTRZ, &ao_outputfilename, NULL},
143 {"fast", OPT_ARG_BOOL, &fast, NULL},
144 {NULL}
146 // set defaults
147 ao_pcm_waveheader = 1;
149 if (subopt_parse(ao_subdevice, subopts) != 0) {
150 return 0;
152 if (!ao_outputfilename){
153 ao_outputfilename =
154 strdup(ao_pcm_waveheader?"audiodump.wav":"audiodump.pcm");
157 if (ao_pcm_waveheader)
159 // WAV files must have one of the following formats
161 switch(format){
162 case AF_FORMAT_U8:
163 case AF_FORMAT_S16_LE:
164 case AF_FORMAT_S24_LE:
165 case AF_FORMAT_S32_LE:
166 case AF_FORMAT_FLOAT_LE:
167 case AF_FORMAT_AC3_BE:
168 case AF_FORMAT_AC3_LE:
169 break;
170 default:
171 format = AF_FORMAT_S16_LE;
172 break;
176 ao_data.outburst = 65536;
177 ao_data.buffersize= 2*65536;
178 ao_data.channels=channels;
179 ao_data.samplerate=rate;
180 ao_data.format=format;
181 ao_data.bps=channels*rate*(af_fmt2bits(format)/8);
183 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] File: %s (%s)\nPCM: Samplerate: %iHz Channels: %s Format %s\n", ao_outputfilename,
184 (ao_pcm_waveheader?"WAVE":"RAW PCM"), rate,
185 (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
186 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] Info: Faster dumping is achieved with -novideo -ao pcm:fast\n[AO PCM] Info: To write WAVE files use -ao pcm:waveheader (default).\n");
188 fp = fopen(ao_outputfilename, "wb");
189 if(fp) {
190 if(ao_pcm_waveheader){ /* Reserve space for wave header */
191 write_wave_header(fp, 0x7ffff000);
193 return 1;
195 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO PCM] Failed to open %s for writing!\n",
196 ao_outputfilename);
197 return 0;
200 // close audio device
201 static void uninit(int immed){
203 if(ao_pcm_waveheader){ /* Rewrite wave header */
204 int broken_seek = 0;
205 #ifdef __MINGW32__
206 // Windows, in its usual idiocy "emulates" seeks on pipes so it always looks
207 // like they work. So we have to detect them brute-force.
208 broken_seek = GetFileType((HANDLE)_get_osfhandle(_fileno(fp))) != FILE_TYPE_DISK;
209 #endif
210 if (broken_seek || fseek(fp, 0, SEEK_SET) != 0)
211 mp_msg(MSGT_AO, MSGL_ERR, "Could not seek to start, WAV size headers not updated!\n");
212 else {
213 if (data_length > 0xfffff000) {
214 mp_msg(MSGT_AO, MSGL_ERR, "File larger than allowed for WAV files, may play truncated!\n");
215 data_length = 0xfffff000;
217 write_wave_header(fp, data_length);
220 fclose(fp);
221 free(ao_outputfilename);
222 ao_outputfilename = NULL;
225 // stop playing and empty buffers (for seeking/pause)
226 static void reset(void){
230 // stop playing, keep buffers (for pause)
231 static void audio_pause(void)
233 // for now, just call reset();
234 reset();
237 // resume playing, after audio_pause()
238 static void audio_resume(void)
242 // return: how many bytes can be played without blocking
243 static int get_space(void){
245 if(vo_pts)
246 return ao_data.pts < vo_pts + fast * 30000 ? ao_data.outburst : 0;
247 return ao_data.outburst;
250 // plays 'len' bytes of 'data'
251 // it should round it down to outburst*n
252 // return: number of bytes played
253 static int play(void* data,int len,int flags){
255 if (ao_data.channels == 5 || ao_data.channels == 6 || ao_data.channels == 8) {
256 int frame_size = af_fmt2bits(ao_data.format) / 8;
257 len -= len % (frame_size * ao_data.channels);
258 reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
259 AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
260 ao_data.channels,
261 len / frame_size, frame_size);
264 //printf("PCM: Writing chunk!\n");
265 fwrite(data,len,1,fp);
267 if(ao_pcm_waveheader)
268 data_length += len;
270 return len;
273 // return: delay in seconds between first and last sample in buffer
274 static float get_delay(void){
276 return 0.0;