Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 661192
Collapse All | Expand All

(-)a/patches/xaudio2_7-WMA_support/0001-xaudio2-Use-ffmpeg-to-convert-WMA-formats.patch (+731 lines)
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
(-)a/patches/xaudio2_7-WMA_support/definition (+2 lines)
Line 0 Link Here
1
Fixes: [39402] Use ffmpeg 4.x to convert WMA format
2
Depends: xaudio2_7-OnVoiceProcessingPassStart

Return to bug 661192