Mercurial > mplayer.hg
annotate libao2/ao_kai.c @ 31139:9a2e299dc256
Add final missing bits of CineForm HD support on Linux (via the Windows
DirectShow codec).
Required changes:
- codecs.conf entry (of course).
- Allow opening files with ¡È.col¡É in the file name, just like ¡Èvp3¡É and ¡È.fpf¡É
already was allowed. (CineForm expects to be able to do this, presumably
for some color management code.)
- In registry.c, fake a few registry keys that the codec expects the installer
to have written. Also, change a few magic numbers (0, 2) to the appropriate
constants (ERROR_SUCCESS, ERROR_FILE_NOT_FOUND) where appropriate, so the code
is easier to follow.
SMP works fine, but seemingly performs suboptimally (e.g., on my dual-core
laptop, CineForm performs better if I lie to it and tell it I have four cores).
I don't know if this is inherent in the codec, or some inefficiency in the
emulated synchronization primitives.
author | sesse |
---|---|
date | Sun, 23 May 2010 16:01:12 +0000 |
parents | d50e20b4e441 |
children |
rev | line source |
---|---|
30439 | 1 /* |
2 * OS/2 KAI audio output driver | |
3 * | |
4 * Copyright (c) 2010 by KO Myung-Hun (komh@chollian.net) | |
5 * | |
6 * This file is part of MPlayer. | |
7 * | |
8 * MPlayer is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * MPlayer is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License along | |
19 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 */ | |
22 | |
23 #define INCL_DOS | |
24 #define INCL_DOSERRORS | |
25 #include <os2.h> | |
26 | |
27 #include <stdio.h> | |
28 #include <stdlib.h> | |
29 #include <sys/time.h> | |
30 #include <float.h> | |
31 | |
32 #include <kai.h> | |
33 | |
34 #include "config.h" | |
35 #include "libaf/af_format.h" | |
36 #include "audio_out.h" | |
37 #include "audio_out_internal.h" | |
38 #include "mp_msg.h" | |
39 #include "libvo/fastmemcpy.h" | |
40 #include "subopt-helper.h" | |
30839 | 41 #include "libavutil/avutil.h" |
30439 | 42 #include "libavutil/fifo.h" |
43 | |
44 static const ao_info_t info = { | |
45 "KAI audio output", | |
46 "kai", | |
47 "KO Myung-Hun <komh@chollian.net>", | |
48 "" | |
49 }; | |
50 | |
51 LIBAO_EXTERN(kai) | |
52 | |
53 #define OUTBURST_SAMPLES 512 | |
54 #define DEFAULT_SAMPLES (OUTBURST_SAMPLES << 2) | |
55 | |
56 #define CHUNK_SIZE ao_data.outburst | |
57 | |
58 static AVFifoBuffer *m_audioBuf; | |
59 | |
60 static int m_nBufSize = 0; | |
61 | |
62 static volatile int m_fQuit = FALSE; | |
63 | |
64 static KAISPEC m_kaiSpec; | |
65 | |
66 static HKAI m_hkai; | |
67 | |
68 static int write_buffer(unsigned char *data, int len) | |
69 { | |
70 int nFree = av_fifo_space(m_audioBuf); | |
71 | |
72 len = FFMIN(len, nFree); | |
73 | |
74 return av_fifo_generic_write(m_audioBuf, data, len, NULL); | |
75 } | |
76 | |
77 static int read_buffer(unsigned char *data, int len) | |
78 { | |
79 int nBuffered = av_fifo_size(m_audioBuf); | |
80 | |
81 len = FFMIN(len, nBuffered); | |
82 | |
83 av_fifo_generic_read(m_audioBuf, data, len, NULL); | |
84 return len; | |
85 } | |
86 | |
87 // end ring buffer stuff | |
88 | |
89 static ULONG APIENTRY kai_audio_callback(PVOID pCBData, PVOID pBuffer, | |
90 ULONG ulSize) | |
91 { | |
92 int nReadLen; | |
93 | |
94 nReadLen = read_buffer(pBuffer, ulSize); | |
95 if (nReadLen < ulSize && !m_fQuit) { | |
96 memset((uint8_t *)pBuffer + nReadLen, m_kaiSpec.bSilence, ulSize - nReadLen); | |
97 nReadLen = ulSize; | |
98 } | |
99 | |
100 return nReadLen; | |
101 } | |
102 | |
103 // to set/get/query special features/parameters | |
104 static int control(int cmd, void *arg) | |
105 { | |
106 switch (cmd) { | |
107 case AOCONTROL_GET_VOLUME: | |
108 { | |
109 ao_control_vol_t *vol = arg; | |
110 | |
111 vol->left = vol->right = kaiGetVolume(m_hkai, MCI_STATUS_AUDIO_ALL); | |
112 | |
113 return CONTROL_OK; | |
114 } | |
115 | |
116 case AOCONTROL_SET_VOLUME: | |
117 { | |
118 int mid; | |
119 ao_control_vol_t *vol = arg; | |
120 | |
121 mid = (vol->left + vol->right) / 2; | |
122 kaiSetVolume(m_hkai, MCI_SET_AUDIO_ALL, mid); | |
123 | |
124 return CONTROL_OK; | |
125 } | |
126 } | |
127 | |
128 return CONTROL_UNKNOWN; | |
129 } | |
130 | |
131 static void print_help(void) | |
132 { | |
133 mp_msg(MSGT_AO, MSGL_FATAL, | |
134 "\n-ao kai commandline help:\n" | |
135 "Example: mplayer -ao kai:noshare\n" | |
136 " open audio in exclusive mode\n" | |
137 "\nOptions:\n" | |
138 " uniaud\n" | |
139 " Use UNIAUD audio driver\n" | |
140 " dart\n" | |
141 " Use DART audio driver\n" | |
142 " (no)share\n" | |
143 " Open audio in shareable or exclusive mode\n" | |
144 " bufsize=<size>\n" | |
145 " Set buffer size to <size> in samples(default: 2048)\n"); | |
146 } | |
147 | |
148 // open & set up audio device | |
149 // return: 1=success 0=fail | |
150 static int init(int rate, int channels, int format, int flags) | |
151 { | |
152 int fUseUniaud = 0; | |
153 int fUseDart = 0; | |
154 int fShare = 1; | |
155 ULONG kaiMode; | |
156 KAICAPS kc; | |
157 int nSamples = DEFAULT_SAMPLES; | |
158 int nBytesPerSample; | |
159 KAISPEC ksWanted; | |
160 | |
161 const opt_t subopts[] = { | |
162 {"uniaud", OPT_ARG_BOOL, &fUseUniaud, NULL}, | |
163 {"dart", OPT_ARG_BOOL, &fUseDart, NULL}, | |
164 {"share", OPT_ARG_BOOL, &fShare, NULL}, | |
165 {"bufsize", OPT_ARG_INT, &nSamples, int_non_neg}, | |
166 {NULL} | |
167 }; | |
168 | |
169 const char *audioDriver[] = {"DART", "UNIAUD",}; | |
170 | |
171 if (subopt_parse(ao_subdevice, subopts) != 0) { | |
172 print_help(); | |
173 return 0; | |
174 } | |
175 | |
176 if (fUseUniaud && fUseDart) | |
177 mp_msg(MSGT_VO, MSGL_WARN,"KAI: Multiple mode specified!!!\n"); | |
178 | |
179 if (fUseUniaud) | |
180 kaiMode = KAIM_UNIAUD; | |
181 else if (fUseDart) | |
182 kaiMode = KAIM_DART; | |
183 else | |
184 kaiMode = KAIM_AUTO; | |
185 | |
186 if (kaiInit(kaiMode)) { | |
187 mp_msg(MSGT_VO, MSGL_ERR, "KAI: Init failed!!!\n"); | |
188 return 0; | |
189 } | |
190 | |
191 kaiCaps(&kc); | |
192 mp_msg(MSGT_AO, MSGL_V, "KAI: selected audio driver = %s\n", | |
193 audioDriver[kc.ulMode - 1]); | |
194 mp_msg(MSGT_AO, MSGL_V, "KAI: PDD name = %s, maximum channels = %lu\n", | |
195 kc.szPDDName, kc.ulMaxChannels); | |
196 | |
197 if (!nSamples) | |
198 nSamples = DEFAULT_SAMPLES; | |
199 | |
200 mp_msg(MSGT_AO, MSGL_V, "KAI: open in %s mode, buffer size = %d sample(s)\n", | |
201 fShare ? "shareable" : "exclusive", nSamples); | |
202 | |
203 switch (format) { | |
204 case AF_FORMAT_S16_LE: | |
205 case AF_FORMAT_S8: | |
206 break; | |
207 | |
208 default: | |
209 format = AF_FORMAT_S16_LE; | |
210 mp_msg(MSGT_AO, MSGL_V, "KAI: format %s not supported defaulting to Signed 16-bit Little-Endian\n", | |
211 af_fmt2str_short(format)); | |
212 break; | |
213 } | |
214 | |
215 nBytesPerSample = (af_fmt2bits(format) >> 3) * channels; | |
216 | |
217 ksWanted.usDeviceIndex = 0; | |
218 ksWanted.ulType = KAIT_PLAY; | |
219 ksWanted.ulBitsPerSample = af_fmt2bits(format); | |
220 ksWanted.ulSamplingRate = rate; | |
221 ksWanted.ulDataFormat = MCI_WAVE_FORMAT_PCM; | |
222 ksWanted.ulChannels = channels; | |
223 ksWanted.ulNumBuffers = 2; | |
224 ksWanted.ulBufferSize = nBytesPerSample * nSamples; | |
225 ksWanted.fShareable = fShare; | |
226 ksWanted.pfnCallBack = kai_audio_callback; | |
227 ksWanted.pCallBackData = NULL; | |
228 | |
229 if (kaiOpen(&ksWanted, &m_kaiSpec, &m_hkai)) { | |
230 mp_msg(MSGT_VO, MSGL_ERR, "KAI: Open failed!!!\n"); | |
231 return 0; | |
232 } | |
233 | |
234 mp_msg(MSGT_AO, MSGL_V, "KAI: obtained buffer count = %lu, size = %lu bytes\n", | |
235 m_kaiSpec.ulNumBuffers, m_kaiSpec.ulBufferSize); | |
236 | |
237 m_fQuit = FALSE; | |
238 | |
239 ao_data.channels = channels; | |
240 ao_data.samplerate = rate; | |
241 ao_data.format = format; | |
242 ao_data.bps = nBytesPerSample * rate; | |
243 ao_data.outburst = nBytesPerSample * OUTBURST_SAMPLES; | |
244 ao_data.buffersize = m_kaiSpec.ulBufferSize; | |
245 | |
30460
2675229bd06f
Audio buffer is too large so that it takes too long time to respond to audio
komh
parents:
30439
diff
changeset
|
246 m_nBufSize = (m_kaiSpec.ulBufferSize * m_kaiSpec.ulNumBuffers) << 2; |
30439 | 247 |
248 // multiple of CHUNK_SIZE | |
249 m_nBufSize = (m_nBufSize / CHUNK_SIZE) * CHUNK_SIZE; | |
250 | |
251 // and one more chunk plus round up | |
252 m_nBufSize += 2 * CHUNK_SIZE; | |
253 | |
254 mp_msg(MSGT_AO, MSGL_V, "KAI: internal audio buffer size = %d bytes\n", | |
255 m_nBufSize); | |
256 | |
257 m_audioBuf = av_fifo_alloc(m_nBufSize); | |
258 | |
259 kaiPlay(m_hkai); | |
260 | |
261 // might cause PM DLLs to be loaded which incorrectly enable SIG_FPE, | |
262 // which AAC decoding might trigger. | |
263 // so, mask off all floating-point exceptions. | |
264 _control87(MCW_EM, MCW_EM); | |
265 | |
266 return 1; | |
267 } | |
268 | |
269 // close audio device | |
270 static void uninit(int immed) | |
271 { | |
272 m_fQuit = TRUE; | |
273 | |
274 if (!immed) | |
275 while (kaiStatus(m_hkai) & KAIS_PLAYING) | |
276 DosSleep(1); | |
277 | |
278 kaiClose(m_hkai); | |
279 | |
280 kaiDone(); | |
281 | |
282 av_fifo_free(m_audioBuf); | |
283 } | |
284 | |
285 // stop playing and empty buffers (for seeking/pause) | |
286 static void reset(void) | |
287 { | |
288 kaiPause(m_hkai); | |
289 | |
290 // Reset ring-buffer state | |
291 av_fifo_reset(m_audioBuf); | |
292 | |
293 kaiResume(m_hkai); | |
294 } | |
295 | |
296 // stop playing, keep buffers (for pause) | |
297 static void audio_pause(void) | |
298 { | |
299 kaiPause(m_hkai); | |
300 } | |
301 | |
302 // resume playing, after audio_pause() | |
303 static void audio_resume(void) | |
304 { | |
305 kaiResume(m_hkai); | |
306 } | |
307 | |
308 // return: how many bytes can be played without blocking | |
309 static int get_space(void) | |
310 { | |
311 return av_fifo_space(m_audioBuf); | |
312 } | |
313 | |
314 // plays 'len' bytes of 'data' | |
315 // it should round it down to outburst*n | |
316 // return: number of bytes played | |
317 static int play(void *data, int len, int flags) | |
318 { | |
319 | |
320 if (!(flags & AOPLAY_FINAL_CHUNK)) | |
321 len = (len / ao_data.outburst) * ao_data.outburst; | |
322 | |
323 return write_buffer(data, len); | |
324 } | |
325 | |
326 // return: delay in seconds between first and last sample in buffer | |
327 static float get_delay(void) | |
328 { | |
329 int nBuffered = av_fifo_size(m_audioBuf); // could be less | |
330 | |
331 return (float)nBuffered / (float)ao_data.bps; | |
332 } |