Line 0
Link Here
|
|
|
1 |
From 71aa01e98af9c1c44a992835c93bfcddba9e9ff5 Mon Sep 17 00:00:00 2001 |
2 |
From: Andrew Eikum <aeikum@codeweavers.com> |
3 |
Date: Thu, 31 May 2018 10:58:48 -0500 |
4 |
Subject: [PATCH] xaudio2: Use ffmpeg to convert WMA formats |
5 |
|
6 |
--- |
7 |
configure.ac | 33 ++++ |
8 |
dlls/xaudio2_0/Makefile.in | 3 +- |
9 |
dlls/xaudio2_1/Makefile.in | 3 +- |
10 |
dlls/xaudio2_2/Makefile.in | 3 +- |
11 |
dlls/xaudio2_3/Makefile.in | 3 +- |
12 |
dlls/xaudio2_4/Makefile.in | 3 +- |
13 |
dlls/xaudio2_5/Makefile.in | 3 +- |
14 |
dlls/xaudio2_6/Makefile.in | 3 +- |
15 |
dlls/xaudio2_7/Makefile.in | 3 +- |
16 |
dlls/xaudio2_7/xaudio_dll.c | 370 ++++++++++++++++++++++++++++++++++++++-- |
17 |
dlls/xaudio2_7/xaudio_private.h | 9 + |
18 |
dlls/xaudio2_8/Makefile.in | 3 +- |
19 |
dlls/xaudio2_9/Makefile.in | 3 +- |
20 |
include/config.h.in | 9 + |
21 |
include/mmreg.h | 5 + |
22 |
15 files changed, 436 insertions(+), 20 deletions(-) |
23 |
|
24 |
diff --git a/configure.ac b/configure.ac |
25 |
index 469fa8d..e753dde 100644 |
26 |
--- a/configure.ac |
27 |
+++ b/configure.ac |
28 |
@@ -43,6 +43,7 @@ AC_ARG_WITH(cups, AS_HELP_STRING([--without-cups],[do not use CUPS])) |
29 |
AC_ARG_WITH(curses, AS_HELP_STRING([--without-curses],[do not use (n)curses]), |
30 |
[if test "x$withval" = "xno"; then ac_cv_header_ncurses_h=no; ac_cv_header_curses_h=no; fi]) |
31 |
AC_ARG_WITH(dbus, AS_HELP_STRING([--without-dbus],[do not use DBus (dynamic device support)])) |
32 |
+AC_ARG_WITH(ffmpeg, AS_HELP_STRING([--without-ffmpeg],[do not use the FFmpeg library])) |
33 |
AC_ARG_WITH(float-abi, AS_HELP_STRING([--with-float-abi=abi],[specify the ABI (soft|softfp|hard) for ARM platforms])) |
34 |
AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig])) |
35 |
AC_ARG_WITH(freetype, AS_HELP_STRING([--without-freetype],[do not use the FreeType library])) |
36 |
@@ -1766,6 +1767,38 @@ WINE_NOTICE_WITH(mpg123,[test "x$ac_cv_lib_mpg123_mpg123_feed" != xyes -a x"$ac_ |
37 |
[enable_l3codeca_acm]) |
38 |
test "x$ac_cv_lib_mpg123_mpg123_feed" = xyes || enable_mp3dmod=${enable_mp3dmod:-no} |
39 |
|
40 |
+dnl **** Check for FFmpeg's libavutil **** |
41 |
+if test "x$with_ffmpeg" != "xno" |
42 |
+then |
43 |
+ WINE_PACKAGE_FLAGS(LIBAVUTIL,[libavutil],[-llibavutil],,, |
44 |
+ [AC_CHECK_HEADERS([libavutil/avutil.h]) |
45 |
+ if test "$ac_cv_header_libavutil_avutil_h" = "yes" |
46 |
+ then |
47 |
+ AC_CHECK_LIB(avutil,av_frame_alloc,[:],[LIBAVUTIL_LIBS=""],[$LIBAVUTIL_LIBS]) |
48 |
+ else |
49 |
+ LIBAVUTIL_CFLAGS="" |
50 |
+ LIBAVUTIL_LIBS="" |
51 |
+ fi]) |
52 |
+fi |
53 |
+ |
54 |
+dnl **** Check for FFmpeg's libavcodec **** |
55 |
+if test "x$with_ffmpeg" != "xno" -a "x$ac_cv_lib_avutil_av_frame_alloc" = "xyes" |
56 |
+then |
57 |
+ WINE_PACKAGE_FLAGS(LIBAVCODEC,[libavcodec],[-llibavcodec],,, |
58 |
+ [AC_CHECK_HEADERS([libavcodec/avcodec.h]) |
59 |
+ if test "$ac_cv_header_libavcodec_avcodec_h" = "yes" |
60 |
+ then |
61 |
+ AC_CHECK_LIB(avcodec,avcodec_send_packet, |
62 |
+ [AC_DEFINE(HAVE_FFMPEG, 1, [Define to 1 if you have libavutil and libavcodec from ffmpeg.])], |
63 |
+ [LIBAVCODEC_LIBS=""], [$LIBAVUTIL_LIBS $LIBAVCODEC_LIBS]) |
64 |
+ else |
65 |
+ LIBAVCODEC_CFLAGS="" |
66 |
+ LIBAVCODEC_LIBS="" |
67 |
+ fi]) |
68 |
+fi |
69 |
+WINE_NOTICE_WITH(libavcodec,[test "x$ac_cv_lib_avcodec_avcodec_send_packet" != xyes], |
70 |
+ [libavcodec ${notice_platform}development files not found (or too old), XAudio2 WMA conversion won't be supported.]) |
71 |
+ |
72 |
dnl **** Check for OpenAL 1.1 **** |
73 |
if test "$ac_cv_header_AL_al_h" = "yes" |
74 |
then |
75 |
diff --git a/dlls/xaudio2_0/Makefile.in b/dlls/xaudio2_0/Makefile.in |
76 |
index cf15c7b..d8d282b 100644 |
77 |
--- a/dlls/xaudio2_0/Makefile.in |
78 |
+++ b/dlls/xaudio2_0/Makefile.in |
79 |
@@ -1,7 +1,8 @@ |
80 |
EXTRADEFS = -DXAUDIO2_VER=0 |
81 |
MODULE = xaudio2_0.dll |
82 |
IMPORTS = advapi32 ole32 user32 uuid |
83 |
-EXTRALIBS = $(OPENAL_LIBS) |
84 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
85 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
86 |
PARENTSRC = ../xaudio2_7 |
87 |
|
88 |
C_SRCS = \ |
89 |
diff --git a/dlls/xaudio2_1/Makefile.in b/dlls/xaudio2_1/Makefile.in |
90 |
index 32a5a62..a0d7bfc 100644 |
91 |
--- a/dlls/xaudio2_1/Makefile.in |
92 |
+++ b/dlls/xaudio2_1/Makefile.in |
93 |
@@ -1,7 +1,8 @@ |
94 |
EXTRADEFS = -DXAUDIO2_VER=1 |
95 |
MODULE = xaudio2_1.dll |
96 |
IMPORTS = advapi32 ole32 user32 uuid |
97 |
-EXTRALIBS = $(OPENAL_LIBS) |
98 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
99 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
100 |
PARENTSRC = ../xaudio2_7 |
101 |
|
102 |
C_SRCS = \ |
103 |
diff --git a/dlls/xaudio2_2/Makefile.in b/dlls/xaudio2_2/Makefile.in |
104 |
index f20de2d..4ba7e6c 100644 |
105 |
--- a/dlls/xaudio2_2/Makefile.in |
106 |
+++ b/dlls/xaudio2_2/Makefile.in |
107 |
@@ -1,7 +1,8 @@ |
108 |
EXTRADEFS = -DXAUDIO2_VER=2 |
109 |
MODULE = xaudio2_2.dll |
110 |
IMPORTS = advapi32 ole32 user32 uuid |
111 |
-EXTRALIBS = $(OPENAL_LIBS) |
112 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
113 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
114 |
PARENTSRC = ../xaudio2_7 |
115 |
|
116 |
C_SRCS = \ |
117 |
diff --git a/dlls/xaudio2_3/Makefile.in b/dlls/xaudio2_3/Makefile.in |
118 |
index ca749f2..62c644f 100644 |
119 |
--- a/dlls/xaudio2_3/Makefile.in |
120 |
+++ b/dlls/xaudio2_3/Makefile.in |
121 |
@@ -1,7 +1,8 @@ |
122 |
EXTRADEFS = -DXAUDIO2_VER=3 |
123 |
MODULE = xaudio2_3.dll |
124 |
IMPORTS = advapi32 ole32 user32 uuid |
125 |
-EXTRALIBS = $(OPENAL_LIBS) |
126 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
127 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
128 |
PARENTSRC = ../xaudio2_7 |
129 |
|
130 |
C_SRCS = \ |
131 |
diff --git a/dlls/xaudio2_4/Makefile.in b/dlls/xaudio2_4/Makefile.in |
132 |
index 0b74f68..b77753f 100644 |
133 |
--- a/dlls/xaudio2_4/Makefile.in |
134 |
+++ b/dlls/xaudio2_4/Makefile.in |
135 |
@@ -1,7 +1,8 @@ |
136 |
EXTRADEFS = -DXAUDIO2_VER=4 |
137 |
MODULE = xaudio2_4.dll |
138 |
IMPORTS = advapi32 ole32 user32 uuid |
139 |
-EXTRALIBS = $(OPENAL_LIBS) |
140 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
141 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
142 |
PARENTSRC = ../xaudio2_7 |
143 |
|
144 |
C_SRCS = \ |
145 |
diff --git a/dlls/xaudio2_5/Makefile.in b/dlls/xaudio2_5/Makefile.in |
146 |
index 09356c9..bd68734 100644 |
147 |
--- a/dlls/xaudio2_5/Makefile.in |
148 |
+++ b/dlls/xaudio2_5/Makefile.in |
149 |
@@ -1,7 +1,8 @@ |
150 |
EXTRADEFS = -DXAUDIO2_VER=5 |
151 |
MODULE = xaudio2_5.dll |
152 |
IMPORTS = advapi32 ole32 user32 uuid |
153 |
-EXTRALIBS = $(OPENAL_LIBS) |
154 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
155 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
156 |
PARENTSRC = ../xaudio2_7 |
157 |
|
158 |
C_SRCS = \ |
159 |
diff --git a/dlls/xaudio2_6/Makefile.in b/dlls/xaudio2_6/Makefile.in |
160 |
index e0ef588..1729509 100644 |
161 |
--- a/dlls/xaudio2_6/Makefile.in |
162 |
+++ b/dlls/xaudio2_6/Makefile.in |
163 |
@@ -1,7 +1,8 @@ |
164 |
EXTRADEFS = -DXAUDIO2_VER=6 |
165 |
MODULE = xaudio2_6.dll |
166 |
IMPORTS = advapi32 ole32 user32 uuid |
167 |
-EXTRALIBS = $(OPENAL_LIBS) |
168 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
169 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
170 |
PARENTSRC = ../xaudio2_7 |
171 |
|
172 |
C_SRCS = \ |
173 |
diff --git a/dlls/xaudio2_7/Makefile.in b/dlls/xaudio2_7/Makefile.in |
174 |
index 2f2e232..41d307d 100644 |
175 |
--- a/dlls/xaudio2_7/Makefile.in |
176 |
+++ b/dlls/xaudio2_7/Makefile.in |
177 |
@@ -1,7 +1,8 @@ |
178 |
EXTRADEFS = -DXAUDIO2_VER=7 |
179 |
MODULE = xaudio2_7.dll |
180 |
IMPORTS = advapi32 ole32 user32 uuid |
181 |
-EXTRALIBS = $(OPENAL_LIBS) |
182 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
183 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
184 |
|
185 |
C_SRCS = \ |
186 |
compat.c \ |
187 |
diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c |
188 |
index e52d962..319c239 100644 |
189 |
--- a/dlls/xaudio2_7/xaudio_dll.c |
190 |
+++ b/dlls/xaudio2_7/xaudio_dll.c |
191 |
@@ -82,6 +82,11 @@ __ASM_GLOBAL_FUNC( call_on_voice_processing_pass_start, |
192 |
"ret" ) |
193 |
#endif |
194 |
|
195 |
+#define IS_WMA(tag) (tag == WAVE_FORMAT_MSAUDIO1 || \ |
196 |
+ tag == WAVE_FORMAT_WMAUDIO2 || \ |
197 |
+ tag == WAVE_FORMAT_WMAUDIO3 || \ |
198 |
+ tag == WAVE_FORMAT_WMAUDIO_LOSSLESS) |
199 |
+ |
200 |
static void dump_fmt(const WAVEFORMATEX *fmt) |
201 |
{ |
202 |
TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); |
203 |
@@ -90,6 +95,11 @@ static void dump_fmt(const WAVEFORMATEX *fmt) |
204 |
DOCASE(WAVE_FORMAT_PCM) |
205 |
DOCASE(WAVE_FORMAT_IEEE_FLOAT) |
206 |
DOCASE(WAVE_FORMAT_EXTENSIBLE) |
207 |
+ DOCASE(WAVE_FORMAT_ADPCM) |
208 |
+ DOCASE(WAVE_FORMAT_MSAUDIO1) |
209 |
+ DOCASE(WAVE_FORMAT_WMAUDIO2) |
210 |
+ DOCASE(WAVE_FORMAT_WMAUDIO3) |
211 |
+ DOCASE(WAVE_FORMAT_WMAUDIO_LOSSLESS) |
212 |
#undef DOCASE |
213 |
default: |
214 |
TRACE("Unknown"); |
215 |
@@ -462,6 +472,10 @@ static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface) |
216 |
} |
217 |
|
218 |
HeapFree(GetProcessHeap(), 0, This->fmt); |
219 |
+ HeapFree(GetProcessHeap(), 0, This->scratch_buf); |
220 |
+ This->scratch_buf = NULL; |
221 |
+ HeapFree(GetProcessHeap(), 0, This->convert_buf); |
222 |
+ This->convert_buf = NULL; |
223 |
|
224 |
alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, This->al_bufs); |
225 |
alDeleteSources(1, &This->al_src); |
226 |
@@ -474,6 +488,17 @@ static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface) |
227 |
This->cur_buf = 0; |
228 |
This->abandoned_albufs = 0; |
229 |
|
230 |
+#if HAVE_FFMPEG |
231 |
+ if(This->conv_ctx){ |
232 |
+ HeapFree(GetProcessHeap(), 0, This->conv_ctx->extradata); |
233 |
+ av_frame_free(&This->conv_frame); |
234 |
+ This->conv_frame = NULL; |
235 |
+ avcodec_close(This->conv_ctx); |
236 |
+ av_free(This->conv_ctx); |
237 |
+ This->conv_ctx = NULL; |
238 |
+ } |
239 |
+#endif |
240 |
+ |
241 |
LeaveCriticalSection(&This->lock); |
242 |
} |
243 |
|
244 |
@@ -579,6 +604,97 @@ static ALenum get_al_format(const WAVEFORMATEX *fmt) |
245 |
return 0; |
246 |
} |
247 |
|
248 |
+#if HAVE_FFMPEG |
249 |
+static enum AVCodecID get_ffmpeg_format(const WAVEFORMATEX *pSourceFormat) |
250 |
+{ |
251 |
+ switch(pSourceFormat->wFormatTag){ |
252 |
+ case WAVE_FORMAT_MSAUDIO1: |
253 |
+ return AV_CODEC_ID_WMAV1; |
254 |
+ case WAVE_FORMAT_WMAUDIO2: |
255 |
+ return AV_CODEC_ID_WMAV2; |
256 |
+ case WAVE_FORMAT_WMAUDIO3: |
257 |
+ return AV_CODEC_ID_WMAPRO; |
258 |
+ case WAVE_FORMAT_WMAUDIO_LOSSLESS: |
259 |
+ return AV_CODEC_ID_WMALOSSLESS; |
260 |
+ case WAVE_FORMAT_ADPCM: |
261 |
+ return AV_CODEC_ID_ADPCM_MS; |
262 |
+ } |
263 |
+ return 0; |
264 |
+} |
265 |
+ |
266 |
+static ALenum ffmpeg_to_al_fmt(enum AVSampleFormat fmt, int channels) |
267 |
+{ |
268 |
+ switch(fmt){ |
269 |
+ case AV_SAMPLE_FMT_U8: |
270 |
+ case AV_SAMPLE_FMT_U8P: |
271 |
+ switch(channels){ |
272 |
+ case 1: |
273 |
+ return AL_FORMAT_MONO8; |
274 |
+ case 2: |
275 |
+ return AL_FORMAT_STEREO8; |
276 |
+ case 4: |
277 |
+ return AL_FORMAT_QUAD8; |
278 |
+ case 6: |
279 |
+ return AL_FORMAT_51CHN8; |
280 |
+ case 7: |
281 |
+ return AL_FORMAT_61CHN8; |
282 |
+ case 8: |
283 |
+ return AL_FORMAT_71CHN8; |
284 |
+ } |
285 |
+ break; |
286 |
+ case AV_SAMPLE_FMT_S16: |
287 |
+ case AV_SAMPLE_FMT_S16P: |
288 |
+ switch(channels){ |
289 |
+ case 1: |
290 |
+ return AL_FORMAT_MONO16; |
291 |
+ case 2: |
292 |
+ return AL_FORMAT_STEREO16; |
293 |
+ case 4: |
294 |
+ return AL_FORMAT_QUAD16; |
295 |
+ case 6: |
296 |
+ return AL_FORMAT_51CHN16; |
297 |
+ case 7: |
298 |
+ return AL_FORMAT_61CHN16; |
299 |
+ case 8: |
300 |
+ return AL_FORMAT_71CHN16; |
301 |
+ } |
302 |
+ break; |
303 |
+ case AV_SAMPLE_FMT_S32: |
304 |
+ case AV_SAMPLE_FMT_S32P: |
305 |
+ switch(channels){ |
306 |
+ /* TODO: mono/stereo? */ |
307 |
+ case 4: |
308 |
+ return AL_FORMAT_QUAD32; |
309 |
+ case 6: |
310 |
+ return AL_FORMAT_51CHN32; |
311 |
+ case 7: |
312 |
+ return AL_FORMAT_61CHN32; |
313 |
+ case 8: |
314 |
+ return AL_FORMAT_71CHN32; |
315 |
+ } |
316 |
+ case AV_SAMPLE_FMT_FLT: |
317 |
+ case AV_SAMPLE_FMT_FLTP: |
318 |
+ switch(channels){ |
319 |
+ case 1: |
320 |
+ return AL_FORMAT_MONO_FLOAT32; |
321 |
+ case 2: |
322 |
+ return AL_FORMAT_STEREO_FLOAT32; |
323 |
+ } |
324 |
+ case AV_SAMPLE_FMT_DBL: |
325 |
+ case AV_SAMPLE_FMT_DBLP: |
326 |
+ switch(channels){ |
327 |
+ case 1: |
328 |
+ return AL_FORMAT_MONO_DOUBLE_EXT; |
329 |
+ case 2: |
330 |
+ return AL_FORMAT_STEREO_DOUBLE_EXT; |
331 |
+ } |
332 |
+ default: |
333 |
+ break; |
334 |
+ } |
335 |
+ return 0; |
336 |
+} |
337 |
+#endif |
338 |
+ |
339 |
static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface, |
340 |
const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA) |
341 |
{ |
342 |
@@ -622,7 +738,10 @@ static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface, |
343 |
#endif |
344 |
|
345 |
/* convert samples offsets to bytes */ |
346 |
- if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){ |
347 |
+ if(IS_WMA(This->fmt->wFormatTag)){ |
348 |
+ /* Offsets for WMA appear to just be byte offsets, since it doesn't |
349 |
+ * have the concept of "samples". */ |
350 |
+ }else if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){ |
351 |
/* ADPCM gives us a number of samples per block, so round down to |
352 |
* nearest block and convert to bytes */ |
353 |
buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign; |
354 |
@@ -1513,19 +1632,119 @@ static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface, |
355 |
|
356 |
src->al_fmt = get_al_format(pSourceFormat); |
357 |
if(!src->al_fmt){ |
358 |
- src->in_use = FALSE; |
359 |
- LeaveCriticalSection(&src->lock); |
360 |
- WARN("OpenAL can't convert this format!\n"); |
361 |
- return AUDCLNT_E_UNSUPPORTED_FORMAT; |
362 |
- } |
363 |
+#if HAVE_FFMPEG |
364 |
+ enum AVCodecID cid; |
365 |
+ AVCodec *codec; |
366 |
+ |
367 |
+ TRACE("OpenAL can't use this format, so using FFmpeg\n"); |
368 |
+ |
369 |
+ cid = get_ffmpeg_format(pSourceFormat); |
370 |
+ if(!cid){ |
371 |
+ WARN("Don't know how to convert this format to an FFmpeg codec\n"); |
372 |
+ src->in_use = FALSE; |
373 |
+ LeaveCriticalSection(&src->lock); |
374 |
+ return AUDCLNT_E_UNSUPPORTED_FORMAT; |
375 |
+ } |
376 |
+ |
377 |
+ codec = avcodec_find_decoder(cid); |
378 |
+ if(!codec){ |
379 |
+ WARN("FFmpeg can't convert this format (0x%x), so failing\n", cid); |
380 |
+ src->in_use = FALSE; |
381 |
+ LeaveCriticalSection(&src->lock); |
382 |
+ return AUDCLNT_E_UNSUPPORTED_FORMAT; |
383 |
+ } |
384 |
+ |
385 |
+ src->conv_ctx = avcodec_alloc_context3(codec); |
386 |
+ if(!src->conv_ctx){ |
387 |
+ WARN("avcodec_alloc_context3 failed\n"); |
388 |
+ src->in_use = FALSE; |
389 |
+ LeaveCriticalSection(&src->lock); |
390 |
+ return AUDCLNT_E_UNSUPPORTED_FORMAT; |
391 |
+ } |
392 |
+ |
393 |
+ src->conv_ctx->bit_rate = pSourceFormat->nAvgBytesPerSec * 8; |
394 |
+ src->conv_ctx->channels = pSourceFormat->nChannels; |
395 |
+ src->conv_ctx->sample_rate = pSourceFormat->nSamplesPerSec; |
396 |
+ src->conv_ctx->block_align = pSourceFormat->nBlockAlign; |
397 |
+ src->conv_ctx->bits_per_coded_sample = pSourceFormat->wBitsPerSample; |
398 |
+ src->conv_ctx->extradata_size = pSourceFormat->cbSize; |
399 |
+ if(pSourceFormat->cbSize){ |
400 |
+ src->conv_ctx->extradata = HeapAlloc(GetProcessHeap(), 0, pSourceFormat->cbSize + AV_INPUT_BUFFER_PADDING_SIZE); |
401 |
+ memcpy(src->conv_ctx->extradata, (&pSourceFormat->cbSize) + 1, pSourceFormat->cbSize); |
402 |
+ }else if(IS_WMA(pSourceFormat->wFormatTag)){ |
403 |
+ /* xWMA doesn't provide the extradata info that FFmpeg needs to |
404 |
+ * decode WMA data, so we create some fake extradata. This is taken |
405 |
+ * from <ffmpeg/libavformat/xwma.c>. */ |
406 |
+ TRACE("synthesizing extradata for xWMA\n"); |
407 |
+ src->conv_ctx->extradata_size = 6; |
408 |
+ src->conv_ctx->extradata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AV_INPUT_BUFFER_PADDING_SIZE); |
409 |
+ src->conv_ctx->extradata[4] = 31; |
410 |
+ } |
411 |
|
412 |
- src->submit_blocksize = pSourceFormat->nBlockAlign; |
413 |
+ if(avcodec_open2(src->conv_ctx, codec, NULL) < 0){ |
414 |
+ WARN("avcodec_open2 failed\n"); |
415 |
+ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); |
416 |
+ av_free(src->conv_ctx); |
417 |
+ src->conv_ctx = NULL; |
418 |
+ src->in_use = FALSE; |
419 |
+ LeaveCriticalSection(&src->lock); |
420 |
+ return AUDCLNT_E_UNSUPPORTED_FORMAT; |
421 |
+ } |
422 |
+ |
423 |
+ src->conv_frame = av_frame_alloc(); |
424 |
+ if(!src->conv_ctx){ |
425 |
+ WARN("av_frame_alloc failed\n"); |
426 |
+ avcodec_close(src->conv_ctx); |
427 |
+ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); |
428 |
+ av_free(src->conv_ctx); |
429 |
+ src->conv_ctx = NULL; |
430 |
+ src->in_use = FALSE; |
431 |
+ LeaveCriticalSection(&src->lock); |
432 |
+ return AUDCLNT_E_UNSUPPORTED_FORMAT; |
433 |
+ } |
434 |
+ |
435 |
+ src->al_fmt = ffmpeg_to_al_fmt(src->conv_ctx->sample_fmt, pSourceFormat->nChannels); |
436 |
+ if(!src->al_fmt){ |
437 |
+ WARN("OpenAL can't use FFmpeg output format\n"); |
438 |
+ av_frame_free(&src->conv_frame); |
439 |
+ src->conv_frame = NULL; |
440 |
+ avcodec_close(src->conv_ctx); |
441 |
+ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); |
442 |
+ av_free(src->conv_ctx); |
443 |
+ src->conv_ctx = NULL; |
444 |
+ src->in_use = FALSE; |
445 |
+ LeaveCriticalSection(&src->lock); |
446 |
+ return AUDCLNT_E_UNSUPPORTED_FORMAT; |
447 |
+ } |
448 |
+ |
449 |
+ src->submit_blocksize = av_get_bytes_per_sample(src->conv_ctx->sample_fmt); |
450 |
+ |
451 |
+ src->scratch_bytes = This->period_frames * 1.5 * src->submit_blocksize; |
452 |
+ src->scratch_buf = HeapAlloc(GetProcessHeap(), 0, src->scratch_bytes); |
453 |
+ |
454 |
+ src->convert_bytes = pSourceFormat->nBlockAlign + AV_INPUT_BUFFER_PADDING_SIZE; |
455 |
+ src->convert_buf = HeapAlloc(GetProcessHeap(), 0, src->convert_bytes); |
456 |
+#else |
457 |
+ WARN("OpenAL can't use this format and no FFmpeg, so giving up\n"); |
458 |
+#endif |
459 |
+ }else |
460 |
+ src->submit_blocksize = pSourceFormat->nBlockAlign; |
461 |
|
462 |
src->fmt = copy_waveformat(pSourceFormat); |
463 |
|
464 |
hr = XA2SRC_SetOutputVoices(&src->IXAudio2SourceVoice_iface, pSendList); |
465 |
if(FAILED(hr)){ |
466 |
HeapFree(GetProcessHeap(), 0, src->fmt); |
467 |
+#if HAVE_FFMPEG |
468 |
+ if(src->conv_ctx){ |
469 |
+ av_frame_free(&src->conv_frame); |
470 |
+ src->conv_frame = NULL; |
471 |
+ avcodec_close(src->conv_ctx); |
472 |
+ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); |
473 |
+ av_free(src->conv_ctx); |
474 |
+ src->conv_ctx = NULL; |
475 |
+ } |
476 |
+#endif |
477 |
src->in_use = FALSE; |
478 |
LeaveCriticalSection(&src->lock); |
479 |
return hr; |
480 |
@@ -2255,6 +2474,9 @@ HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR p |
481 |
* buffer's data has all been queued */ |
482 |
static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al_buf) |
483 |
{ |
484 |
+#if HAVE_FFMPEG |
485 |
+ int averr; |
486 |
+#endif |
487 |
UINT32 submit_bytes; |
488 |
const BYTE *submit_buf = NULL; |
489 |
|
490 |
@@ -2263,9 +2485,133 @@ static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al |
491 |
return FALSE; |
492 |
} |
493 |
|
494 |
- submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes); |
495 |
- submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes; |
496 |
- buf->offs_bytes += submit_bytes; |
497 |
+#if HAVE_FFMPEG |
498 |
+ if(src->conv_ctx){ |
499 |
+ DWORD scratch_offs_bytes = 0; |
500 |
+ AVPacket avpkt = {0}; |
501 |
+ |
502 |
+ avpkt.size = src->fmt->nBlockAlign; |
503 |
+ avpkt.data = (unsigned char*)buf->xa2buffer.pAudioData + buf->offs_bytes; |
504 |
+ |
505 |
+ /* convert at least a period into scratch_buf */ |
506 |
+ while(scratch_offs_bytes < src->xa2->period_frames * src->submit_blocksize){ |
507 |
+ DWORD to_copy_bytes; |
508 |
+ |
509 |
+ averr = avcodec_receive_frame(src->conv_ctx, src->conv_frame); |
510 |
+ if(averr == AVERROR(EAGAIN)){ |
511 |
+ /* ffmpeg needs more data to decode */ |
512 |
+ avpkt.pts = avpkt.dts = AV_NOPTS_VALUE; |
513 |
+ |
514 |
+ if(buf->offs_bytes >= buf->cur_end_bytes) |
515 |
+ /* no more data in this buffer */ |
516 |
+ break; |
517 |
+ |
518 |
+ if(buf->offs_bytes + avpkt.size + AV_INPUT_BUFFER_PADDING_SIZE > buf->cur_end_bytes){ |
519 |
+ UINT32 remain = buf->cur_end_bytes - buf->offs_bytes; |
520 |
+ /* Unfortunately, the FFmpeg API requires that a number of |
521 |
+ * extra bytes must be available past the end of the buffer. |
522 |
+ * The xaudio2 client probably hasn't done this, so we have to |
523 |
+ * perform a copy near the end of the buffer. */ |
524 |
+ TRACE("hitting end of buffer. copying %u + %u bytes into %u buffer\n", |
525 |
+ remain, AV_INPUT_BUFFER_PADDING_SIZE, src->convert_bytes); |
526 |
+ if(src->convert_bytes < remain + AV_INPUT_BUFFER_PADDING_SIZE){ |
527 |
+ src->convert_bytes = remain + AV_INPUT_BUFFER_PADDING_SIZE; |
528 |
+ TRACE("buffer too small, expanding to %u\n", src->convert_bytes); |
529 |
+ src->convert_buf = HeapReAlloc(GetProcessHeap(), 0, src->convert_buf, src->convert_bytes); |
530 |
+ } |
531 |
+ memcpy(src->convert_buf, buf->xa2buffer.pAudioData + buf->offs_bytes, remain); |
532 |
+ memset(src->convert_buf + remain, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
533 |
+ avpkt.data = src->convert_buf; |
534 |
+ } |
535 |
+ |
536 |
+ averr = avcodec_send_packet(src->conv_ctx, &avpkt); |
537 |
+ if(averr){ |
538 |
+ WARN("avcodec_send_packet failed: %s\n", av_err2str(averr)); |
539 |
+ break; |
540 |
+ } |
541 |
+ |
542 |
+ buf->offs_bytes += avpkt.size; |
543 |
+ avpkt.data += avpkt.size; |
544 |
+ |
545 |
+ /* data sent, try receive again */ |
546 |
+ continue; |
547 |
+ } |
548 |
+ |
549 |
+ if(averr){ |
550 |
+ WARN("avcodec_receive_frame failed: %s\n", av_err2str(averr)); |
551 |
+ return TRUE; |
552 |
+ } |
553 |
+ |
554 |
+ to_copy_bytes = src->conv_frame->nb_samples * src->conv_ctx->channels * src->submit_blocksize; |
555 |
+ |
556 |
+ while(scratch_offs_bytes + to_copy_bytes >= src->scratch_bytes){ |
557 |
+ src->scratch_bytes *= 2; |
558 |
+ src->scratch_buf = HeapReAlloc(GetProcessHeap(), 0, src->scratch_buf, src->scratch_bytes); |
559 |
+ } |
560 |
+ |
561 |
+ if(av_sample_fmt_is_planar(src->conv_ctx->sample_fmt)){ |
562 |
+ int s, c; |
563 |
+ uint8_t **source, *dst; |
564 |
+ uint16_t *dst16; |
565 |
+ uint32_t *dst32; |
566 |
+ uint64_t *dst64; |
567 |
+ |
568 |
+ /* one buffer per channel, but openal needs interleaved, so |
569 |
+ * interleave samples into scratch buf */ |
570 |
+ dst = src->scratch_buf + scratch_offs_bytes; |
571 |
+ source = src->conv_frame->data; |
572 |
+ |
573 |
+ switch(src->submit_blocksize){ |
574 |
+ case 1: |
575 |
+ for(s = 0; s < src->conv_frame->nb_samples; ++s) |
576 |
+ for(c = 0; c < src->conv_ctx->channels; ++c) |
577 |
+ *(dst++) = source[c][s]; |
578 |
+ break; |
579 |
+ case 2: |
580 |
+ dst16 = (uint16_t*)dst; |
581 |
+ for(s = 0; s < src->conv_frame->nb_samples; ++s) |
582 |
+ for(c = 0; c < src->conv_ctx->channels; ++c) |
583 |
+ *(dst16++) = ((uint16_t*)(source[c]))[s]; |
584 |
+ break; |
585 |
+ case 4: |
586 |
+ dst32 = (uint32_t*)dst; |
587 |
+ for(s = 0; s < src->conv_frame->nb_samples; ++s) |
588 |
+ for(c = 0; c < src->conv_ctx->channels; ++c) |
589 |
+ *(dst32++) = ((uint32_t*)(source[c]))[s]; |
590 |
+ break; |
591 |
+ case 8: |
592 |
+ dst64 = (uint64_t*)dst; |
593 |
+ for(s = 0; s < src->conv_frame->nb_samples; ++s) |
594 |
+ for(c = 0; c < src->conv_ctx->channels; ++c) |
595 |
+ *(dst64++) = ((uint64_t*)(source[c]))[s]; |
596 |
+ break; |
597 |
+ default: |
598 |
+ for(s = 0; s < src->conv_frame->nb_samples; ++s) |
599 |
+ for(c = 0; c < src->conv_ctx->channels; ++c){ |
600 |
+ memcpy(dst, &source[c][src->submit_blocksize * s], src->submit_blocksize); |
601 |
+ dst += src->submit_blocksize; |
602 |
+ } |
603 |
+ break; |
604 |
+ } |
605 |
+ |
606 |
+ scratch_offs_bytes += to_copy_bytes; |
607 |
+ }else{ |
608 |
+ /* copy into scratch buf */ |
609 |
+ memcpy(src->scratch_buf + scratch_offs_bytes, src->conv_frame->data[0], to_copy_bytes); |
610 |
+ scratch_offs_bytes += to_copy_bytes; |
611 |
+ } |
612 |
+ } |
613 |
+ |
614 |
+ submit_bytes = scratch_offs_bytes; |
615 |
+ submit_buf = src->scratch_buf; |
616 |
+ }else{ |
617 |
+#endif |
618 |
+ submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes); |
619 |
+ submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes; |
620 |
+ buf->offs_bytes += submit_bytes; |
621 |
+#if HAVE_FFMPEG |
622 |
+ } |
623 |
+#endif |
624 |
|
625 |
alBufferData(al_buf, src->al_fmt, submit_buf, submit_bytes, |
626 |
src->fmt->nSamplesPerSec); |
627 |
@@ -2288,6 +2634,10 @@ static UINT32 get_underrun_warning(XA2SourceImpl *src) |
628 |
UINT32 period_bytes = src->xa2->period_frames * src->submit_blocksize; |
629 |
UINT32 total = 0, i; |
630 |
|
631 |
+ if(IS_WMA(src->fmt->wFormatTag)) |
632 |
+ /* PCM only */ |
633 |
+ return 0; |
634 |
+ |
635 |
for(i = 0; i < src->nbufs && total < IN_AL_PERIODS * period_bytes; ++i){ |
636 |
XA2Buffer *buf = &src->buffers[(src->first_buf + i) % XAUDIO2_MAX_QUEUED_BUFFERS]; |
637 |
total += buf->cur_end_bytes - buf->offs_bytes; |
638 |
diff --git a/dlls/xaudio2_7/xaudio_private.h b/dlls/xaudio2_7/xaudio_private.h |
639 |
index 5d3814f..9cf7f00 100644 |
640 |
--- a/dlls/xaudio2_7/xaudio_private.h |
641 |
+++ b/dlls/xaudio2_7/xaudio_private.h |
642 |
@@ -29,6 +29,10 @@ |
643 |
#include "mmdeviceapi.h" |
644 |
#include "audioclient.h" |
645 |
|
646 |
+#if HAVE_FFMPEG |
647 |
+#include <libavcodec/avcodec.h> |
648 |
+#endif |
649 |
+ |
650 |
#include <AL/al.h> |
651 |
#include <AL/alc.h> |
652 |
#include <AL/alext.h> |
653 |
@@ -83,6 +87,11 @@ typedef struct _XA2SourceImpl { |
654 |
ALuint al_bufs[XAUDIO2_MAX_QUEUED_BUFFERS]; |
655 |
DWORD first_al_buf, al_bufs_used, abandoned_albufs; |
656 |
|
657 |
+#if HAVE_FFMPEG |
658 |
+ AVCodecContext *conv_ctx; |
659 |
+ AVFrame *conv_frame; |
660 |
+#endif |
661 |
+ |
662 |
struct list entry; |
663 |
} XA2SourceImpl; |
664 |
|
665 |
diff --git a/dlls/xaudio2_8/Makefile.in b/dlls/xaudio2_8/Makefile.in |
666 |
index d4efc41..8ad071f 100644 |
667 |
--- a/dlls/xaudio2_8/Makefile.in |
668 |
+++ b/dlls/xaudio2_8/Makefile.in |
669 |
@@ -1,7 +1,8 @@ |
670 |
EXTRADEFS = -DXAUDIO2_VER=8 |
671 |
MODULE = xaudio2_8.dll |
672 |
IMPORTS = advapi32 ole32 user32 uuid |
673 |
-EXTRALIBS = $(OPENAL_LIBS) |
674 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
675 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
676 |
PARENTSRC = ../xaudio2_7 |
677 |
|
678 |
C_SRCS = \ |
679 |
diff --git a/dlls/xaudio2_9/Makefile.in b/dlls/xaudio2_9/Makefile.in |
680 |
index ceb2216..0243ed6 100644 |
681 |
--- a/dlls/xaudio2_9/Makefile.in |
682 |
+++ b/dlls/xaudio2_9/Makefile.in |
683 |
@@ -1,7 +1,8 @@ |
684 |
EXTRADEFS = -DXAUDIO2_VER=9 |
685 |
MODULE = xaudio2_9.dll |
686 |
IMPORTS = advapi32 ole32 user32 uuid |
687 |
-EXTRALIBS = $(OPENAL_LIBS) |
688 |
+EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) |
689 |
+EXTRAINCL = $(LIBAVCODEC_CFLAGS) $(LIBAVUTIL_CFLAGS) |
690 |
PARENTSRC = ../xaudio2_7 |
691 |
|
692 |
C_SRCS = \ |
693 |
diff --git a/include/config.h.in b/include/config.h.in |
694 |
index c3247cb..7067a10 100644 |
695 |
--- a/include/config.h.in |
696 |
+++ b/include/config.h.in |
697 |
@@ -408,6 +408,15 @@ |
698 |
/* Define to 1 if you have the `lgammaf' function. */ |
699 |
#undef HAVE_LGAMMAF |
700 |
|
701 |
+/* Define to 1 if you have the <libavcodec/avcodec.h> header file. */ |
702 |
+#undef HAVE_LIBAVCODEC_AVCODEC_H |
703 |
+ |
704 |
+/* Define to 1 if you have the <libavutil/avutil.h> header file. */ |
705 |
+#undef HAVE_LIBAVUTIL_AVUTIL_H |
706 |
+ |
707 |
+/* Define to 1 if you have libavutil and libavcodec from ffmpeg. */ |
708 |
+#undef HAVE_FFMPEG |
709 |
+ |
710 |
/* Define to 1 if you have the `gettextpo' library (-lgettextpo). */ |
711 |
#undef HAVE_LIBGETTEXTPO |
712 |
|
713 |
diff --git a/include/mmreg.h b/include/mmreg.h |
714 |
index 8bb581d..1214dfa 100644 |
715 |
--- a/include/mmreg.h |
716 |
+++ b/include/mmreg.h |
717 |
@@ -110,6 +110,11 @@ typedef struct _WAVEFORMATEX { |
718 |
#define WAVE_FORMAT_MPEG 0x0050 /* Microsoft Corporation */ |
719 |
#define WAVE_FORMAT_MPEGLAYER3 0x0055 |
720 |
#define WAVE_FORMAT_MSRT24 0x0082 /* Microsoft Corporation */ |
721 |
+#define WAVE_FORMAT_MSAUDIO1 0x0160 |
722 |
+#define WAVE_FORMAT_WMAUDIO2 0x0161 |
723 |
+#define WAVE_FORMAT_WMAUDIO3 0x0162 |
724 |
+#define WAVE_FORMAT_WMAUDIO_LOSSLESS 0x0163 |
725 |
+ |
726 |
#define WAVE_FORMAT_CREATIVE_ADPCM 0x0200 /* Creative Labs, Inc */ |
727 |
#define WAVE_FORMAT_CREATIVE_FASTSPEECH8 0x0202 /* Creative Labs, Inc */ |
728 |
#define WAVE_FORMAT_CREATIVE_FASTSPEECH10 0x0203 /* Creative Labs, Inc */ |
729 |
-- |
730 |
2.7.4 |
731 |
|