From 19db07f062fdf4c486f78e3201544f5cf5ac7f02 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 28 Jun 2018 12:19:43 +1000 Subject: [PATCH] Added xaudio2-WMA_support patchset --- patches/patchinstall.sh | 22 + ...o2-Use-ffmpeg-to-convert-WMA-formats.patch | 721 ++++++++++++++++++ patches/xaudio2_7-WMA_support/definition | 1 + 3 files changed, 744 insertions(+) create mode 100644 patches/xaudio2_7-WMA_support/0001-xaudio2-Use-ffmpeg-to-convert-WMA-formats.patch create mode 100644 patches/xaudio2_7-WMA_support/definition diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index bcdf4a7c..b0367bfe 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -419,6 +419,7 @@ patch_enable_all () enable_wuauserv_Dummy_Service="$1" enable_wusa_MSU_Package_Installer="$1" enable_xaudio2_7_OnVoiceProcessingPassStart="$1" + enable_xaudio2_7_WMA_support="$1" enable_xaudio2_CommitChanges="$1" } @@ -1434,6 +1435,9 @@ patch_enable () xaudio2_7-OnVoiceProcessingPassStart) enable_xaudio2_7_OnVoiceProcessingPassStart="$2" ;; + xaudio2_7-WMA_support) + enable_xaudio2_7_WMA_support="$2" + ;; xaudio2_CommitChanges) enable_xaudio2_CommitChanges="$2" ;; @@ -8412,6 +8416,24 @@ if test "$enable_xaudio2_7_OnVoiceProcessingPassStart" -eq 1; then ) >> "$patchlist" fi +# Patchset xaudio2_7-WMA_support +# | +# | This patchset fixes the following Wine bugs: +# | * [#39402] Use ffmpeg 4.x to convert WMA format +# | +# | Modified files: +# | * configure.ac, dlls/xaudio2_0/Makefile.in, dlls/xaudio2_1/Makefile.in, dlls/xaudio2_2/Makefile.in, +# | dlls/xaudio2_3/Makefile.in, dlls/xaudio2_4/Makefile.in, dlls/xaudio2_5/Makefile.in, dlls/xaudio2_6/Makefile.in, +# | dlls/xaudio2_7/Makefile.in, dlls/xaudio2_7/xaudio_dll.c, dlls/xaudio2_7/xaudio_private.h, dlls/xaudio2_8/Makefile.in, +# | dlls/xaudio2_9/Makefile.in, include/config.h.in, include/mmreg.h +# | +if test "$enable_xaudio2_7_WMA_support" -eq 1; then + patch_apply xaudio2_7-WMA_support/0001-xaudio2-Use-ffmpeg-to-convert-WMA-formats.patch + ( + printf '%s\n' '+ { "Andrew Eikum", "xaudio2: Use ffmpeg to convert WMA formats.", 1 },'; + ) >> "$patchlist" +fi + # Patchset xaudio2_CommitChanges # | # | This patchset fixes the following Wine bugs: diff --git a/patches/xaudio2_7-WMA_support/0001-xaudio2-Use-ffmpeg-to-convert-WMA-formats.patch b/patches/xaudio2_7-WMA_support/0001-xaudio2-Use-ffmpeg-to-convert-WMA-formats.patch new file mode 100644 index 00000000..373fe64c --- /dev/null +++ b/patches/xaudio2_7-WMA_support/0001-xaudio2-Use-ffmpeg-to-convert-WMA-formats.patch @@ -0,0 +1,721 @@ +From 86489505fd9cdf61f90ba31a045f1412833517cc Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 31 May 2018 10:58:48 -0500 +Subject: [PATCH] xaudio2: Use ffmpeg to convert WMA formats + +--- + configure.ac | 33 ++++ + dlls/xaudio2_0/Makefile.in | 2 +- + dlls/xaudio2_1/Makefile.in | 2 +- + dlls/xaudio2_2/Makefile.in | 2 +- + dlls/xaudio2_3/Makefile.in | 2 +- + dlls/xaudio2_4/Makefile.in | 2 +- + dlls/xaudio2_5/Makefile.in | 2 +- + dlls/xaudio2_6/Makefile.in | 2 +- + dlls/xaudio2_7/Makefile.in | 2 +- + dlls/xaudio2_7/xaudio_dll.c | 370 ++++++++++++++++++++++++++++++++++++++-- + dlls/xaudio2_7/xaudio_private.h | 9 + + dlls/xaudio2_8/Makefile.in | 2 +- + dlls/xaudio2_9/Makefile.in | 2 +- + include/config.h.in | 9 + + include/mmreg.h | 5 + + 15 files changed, 426 insertions(+), 20 deletions(-) + +diff --git a/configure.ac b/configure.ac +index e8dc9f2..ca0ad72 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -43,6 +43,7 @@ AC_ARG_WITH(cups, AS_HELP_STRING([--without-cups],[do not use CUPS])) + AC_ARG_WITH(curses, AS_HELP_STRING([--without-curses],[do not use (n)curses]), + [if test "x$withval" = "xno"; then ac_cv_header_ncurses_h=no; ac_cv_header_curses_h=no; fi]) + AC_ARG_WITH(dbus, AS_HELP_STRING([--without-dbus],[do not use DBus (dynamic device support)])) ++AC_ARG_WITH(ffmpeg, AS_HELP_STRING([--without-ffmpeg],[do not use the FFmpeg library])) + AC_ARG_WITH(float-abi, AS_HELP_STRING([--with-float-abi=abi],[specify the ABI (soft|softfp|hard) for ARM platforms])) + AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig])) + AC_ARG_WITH(freetype, AS_HELP_STRING([--without-freetype],[do not use the FreeType library])) +@@ -1836,6 +1837,38 @@ WINE_NOTICE_WITH(mpg123,[test "x$ac_cv_lib_mpg123_mpg123_feed" != xyes -a x"$ac_ + [enable_l3codeca_acm]) + test "x$ac_cv_lib_mpg123_mpg123_feed" = xyes || enable_mp3dmod=${enable_mp3dmod:-no} + ++dnl **** Check for FFmpeg's libavutil **** ++if test "x$with_ffmpeg" != "xno" ++then ++ WINE_PACKAGE_FLAGS(LIBAVUTIL,[libavutil],[-llibavutil],,, ++ [AC_CHECK_HEADERS([libavutil/avutil.h]) ++ if test "$ac_cv_header_libavutil_avutil_h" = "yes" ++ then ++ AC_CHECK_LIB(avutil,av_frame_alloc,[:],[LIBAVUTIL_LIBS=""],[$LIBAVUTIL_LIBS]) ++ else ++ LIBAVUTIL_CFLAGS="" ++ LIBAVUTIL_LIBS="" ++ fi]) ++fi ++ ++dnl **** Check for FFmpeg's libavcodec **** ++if test "x$with_ffmpeg" != "xno" -a "x$ac_cv_lib_avutil_av_frame_alloc" = "xyes" ++then ++ WINE_PACKAGE_FLAGS(LIBAVCODEC,[libavcodec],[-llibavcodec],,, ++ [AC_CHECK_HEADERS([libavcodec/avcodec.h]) ++ if test "$ac_cv_header_libavcodec_avcodec_h" = "yes" ++ then ++ AC_CHECK_LIB(avcodec,avcodec_send_packet, ++ [AC_DEFINE(HAVE_FFMPEG, 1, [Define to 1 if you have libavutil and libavcodec from ffmpeg.])], ++ [LIBAVCODEC_LIBS=""], [$LIBAVUTIL_LIBS $LIBAVCODEC_LIBS]) ++ else ++ LIBAVCODEC_CFLAGS="" ++ LIBAVCODEC_LIBS="" ++ fi]) ++fi ++WINE_NOTICE_WITH(libavcodec,[test "x$ac_cv_lib_avcodec_avcodec_send_packet" != xyes], ++ [libavcodec ${notice_platform}development files not found (or too old), XAudio2 WMA conversion won't be supported.]) ++ + dnl **** Check for OpenAL 1.1 **** + if test "$ac_cv_header_AL_al_h" = "yes" + then +diff --git a/dlls/xaudio2_0/Makefile.in b/dlls/xaudio2_0/Makefile.in +index cf15c7b..d1127e5 100644 +--- a/dlls/xaudio2_0/Makefile.in ++++ b/dlls/xaudio2_0/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=0 + MODULE = xaudio2_0.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_1/Makefile.in b/dlls/xaudio2_1/Makefile.in +index 32a5a62..53d9c10 100644 +--- a/dlls/xaudio2_1/Makefile.in ++++ b/dlls/xaudio2_1/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=1 + MODULE = xaudio2_1.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_2/Makefile.in b/dlls/xaudio2_2/Makefile.in +index f20de2d..d1b4384 100644 +--- a/dlls/xaudio2_2/Makefile.in ++++ b/dlls/xaudio2_2/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=2 + MODULE = xaudio2_2.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_3/Makefile.in b/dlls/xaudio2_3/Makefile.in +index ca749f2..c431146 100644 +--- a/dlls/xaudio2_3/Makefile.in ++++ b/dlls/xaudio2_3/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=3 + MODULE = xaudio2_3.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_4/Makefile.in b/dlls/xaudio2_4/Makefile.in +index 0b74f68..69ffc69 100644 +--- a/dlls/xaudio2_4/Makefile.in ++++ b/dlls/xaudio2_4/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=4 + MODULE = xaudio2_4.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_5/Makefile.in b/dlls/xaudio2_5/Makefile.in +index 09356c9..011cc7a 100644 +--- a/dlls/xaudio2_5/Makefile.in ++++ b/dlls/xaudio2_5/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=5 + MODULE = xaudio2_5.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_6/Makefile.in b/dlls/xaudio2_6/Makefile.in +index e0ef588..455c6d7 100644 +--- a/dlls/xaudio2_6/Makefile.in ++++ b/dlls/xaudio2_6/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=6 + MODULE = xaudio2_6.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_7/Makefile.in b/dlls/xaudio2_7/Makefile.in +index 2f2e232..3e6d595 100644 +--- a/dlls/xaudio2_7/Makefile.in ++++ b/dlls/xaudio2_7/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=7 + MODULE = xaudio2_7.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + + C_SRCS = \ + compat.c \ +diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c +index e52d962..319c239 100644 +--- a/dlls/xaudio2_7/xaudio_dll.c ++++ b/dlls/xaudio2_7/xaudio_dll.c +@@ -82,6 +82,11 @@ __ASM_GLOBAL_FUNC( call_on_voice_processing_pass_start, + "ret" ) + #endif + ++#define IS_WMA(tag) (tag == WAVE_FORMAT_MSAUDIO1 || \ ++ tag == WAVE_FORMAT_WMAUDIO2 || \ ++ tag == WAVE_FORMAT_WMAUDIO3 || \ ++ tag == WAVE_FORMAT_WMAUDIO_LOSSLESS) ++ + static void dump_fmt(const WAVEFORMATEX *fmt) + { + TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); +@@ -90,6 +95,11 @@ static void dump_fmt(const WAVEFORMATEX *fmt) + DOCASE(WAVE_FORMAT_PCM) + DOCASE(WAVE_FORMAT_IEEE_FLOAT) + DOCASE(WAVE_FORMAT_EXTENSIBLE) ++ DOCASE(WAVE_FORMAT_ADPCM) ++ DOCASE(WAVE_FORMAT_MSAUDIO1) ++ DOCASE(WAVE_FORMAT_WMAUDIO2) ++ DOCASE(WAVE_FORMAT_WMAUDIO3) ++ DOCASE(WAVE_FORMAT_WMAUDIO_LOSSLESS) + #undef DOCASE + default: + TRACE("Unknown"); +@@ -462,6 +472,10 @@ static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface) + } + + HeapFree(GetProcessHeap(), 0, This->fmt); ++ HeapFree(GetProcessHeap(), 0, This->scratch_buf); ++ This->scratch_buf = NULL; ++ HeapFree(GetProcessHeap(), 0, This->convert_buf); ++ This->convert_buf = NULL; + + alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, This->al_bufs); + alDeleteSources(1, &This->al_src); +@@ -474,6 +488,17 @@ static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface) + This->cur_buf = 0; + This->abandoned_albufs = 0; + ++#if HAVE_FFMPEG ++ if(This->conv_ctx){ ++ HeapFree(GetProcessHeap(), 0, This->conv_ctx->extradata); ++ av_frame_free(&This->conv_frame); ++ This->conv_frame = NULL; ++ avcodec_close(This->conv_ctx); ++ av_free(This->conv_ctx); ++ This->conv_ctx = NULL; ++ } ++#endif ++ + LeaveCriticalSection(&This->lock); + } + +@@ -579,6 +604,97 @@ static ALenum get_al_format(const WAVEFORMATEX *fmt) + return 0; + } + ++#if HAVE_FFMPEG ++static enum AVCodecID get_ffmpeg_format(const WAVEFORMATEX *pSourceFormat) ++{ ++ switch(pSourceFormat->wFormatTag){ ++ case WAVE_FORMAT_MSAUDIO1: ++ return AV_CODEC_ID_WMAV1; ++ case WAVE_FORMAT_WMAUDIO2: ++ return AV_CODEC_ID_WMAV2; ++ case WAVE_FORMAT_WMAUDIO3: ++ return AV_CODEC_ID_WMAPRO; ++ case WAVE_FORMAT_WMAUDIO_LOSSLESS: ++ return AV_CODEC_ID_WMALOSSLESS; ++ case WAVE_FORMAT_ADPCM: ++ return AV_CODEC_ID_ADPCM_MS; ++ } ++ return 0; ++} ++ ++static ALenum ffmpeg_to_al_fmt(enum AVSampleFormat fmt, int channels) ++{ ++ switch(fmt){ ++ case AV_SAMPLE_FMT_U8: ++ case AV_SAMPLE_FMT_U8P: ++ switch(channels){ ++ case 1: ++ return AL_FORMAT_MONO8; ++ case 2: ++ return AL_FORMAT_STEREO8; ++ case 4: ++ return AL_FORMAT_QUAD8; ++ case 6: ++ return AL_FORMAT_51CHN8; ++ case 7: ++ return AL_FORMAT_61CHN8; ++ case 8: ++ return AL_FORMAT_71CHN8; ++ } ++ break; ++ case AV_SAMPLE_FMT_S16: ++ case AV_SAMPLE_FMT_S16P: ++ switch(channels){ ++ case 1: ++ return AL_FORMAT_MONO16; ++ case 2: ++ return AL_FORMAT_STEREO16; ++ case 4: ++ return AL_FORMAT_QUAD16; ++ case 6: ++ return AL_FORMAT_51CHN16; ++ case 7: ++ return AL_FORMAT_61CHN16; ++ case 8: ++ return AL_FORMAT_71CHN16; ++ } ++ break; ++ case AV_SAMPLE_FMT_S32: ++ case AV_SAMPLE_FMT_S32P: ++ switch(channels){ ++ /* TODO: mono/stereo? */ ++ case 4: ++ return AL_FORMAT_QUAD32; ++ case 6: ++ return AL_FORMAT_51CHN32; ++ case 7: ++ return AL_FORMAT_61CHN32; ++ case 8: ++ return AL_FORMAT_71CHN32; ++ } ++ case AV_SAMPLE_FMT_FLT: ++ case AV_SAMPLE_FMT_FLTP: ++ switch(channels){ ++ case 1: ++ return AL_FORMAT_MONO_FLOAT32; ++ case 2: ++ return AL_FORMAT_STEREO_FLOAT32; ++ } ++ case AV_SAMPLE_FMT_DBL: ++ case AV_SAMPLE_FMT_DBLP: ++ switch(channels){ ++ case 1: ++ return AL_FORMAT_MONO_DOUBLE_EXT; ++ case 2: ++ return AL_FORMAT_STEREO_DOUBLE_EXT; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++ + static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface, + const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA) + { +@@ -622,7 +738,10 @@ static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface, + #endif + + /* convert samples offsets to bytes */ +- if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){ ++ if(IS_WMA(This->fmt->wFormatTag)){ ++ /* Offsets for WMA appear to just be byte offsets, since it doesn't ++ * have the concept of "samples". */ ++ }else if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){ + /* ADPCM gives us a number of samples per block, so round down to + * nearest block and convert to bytes */ + buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign; +@@ -1513,19 +1632,119 @@ static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface, + + src->al_fmt = get_al_format(pSourceFormat); + if(!src->al_fmt){ +- src->in_use = FALSE; +- LeaveCriticalSection(&src->lock); +- WARN("OpenAL can't convert this format!\n"); +- return AUDCLNT_E_UNSUPPORTED_FORMAT; +- } ++#if HAVE_FFMPEG ++ enum AVCodecID cid; ++ AVCodec *codec; ++ ++ TRACE("OpenAL can't use this format, so using FFmpeg\n"); ++ ++ cid = get_ffmpeg_format(pSourceFormat); ++ if(!cid){ ++ WARN("Don't know how to convert this format to an FFmpeg codec\n"); ++ src->in_use = FALSE; ++ LeaveCriticalSection(&src->lock); ++ return AUDCLNT_E_UNSUPPORTED_FORMAT; ++ } ++ ++ codec = avcodec_find_decoder(cid); ++ if(!codec){ ++ WARN("FFmpeg can't convert this format (0x%x), so failing\n", cid); ++ src->in_use = FALSE; ++ LeaveCriticalSection(&src->lock); ++ return AUDCLNT_E_UNSUPPORTED_FORMAT; ++ } ++ ++ src->conv_ctx = avcodec_alloc_context3(codec); ++ if(!src->conv_ctx){ ++ WARN("avcodec_alloc_context3 failed\n"); ++ src->in_use = FALSE; ++ LeaveCriticalSection(&src->lock); ++ return AUDCLNT_E_UNSUPPORTED_FORMAT; ++ } ++ ++ src->conv_ctx->bit_rate = pSourceFormat->nAvgBytesPerSec * 8; ++ src->conv_ctx->channels = pSourceFormat->nChannels; ++ src->conv_ctx->sample_rate = pSourceFormat->nSamplesPerSec; ++ src->conv_ctx->block_align = pSourceFormat->nBlockAlign; ++ src->conv_ctx->bits_per_coded_sample = pSourceFormat->wBitsPerSample; ++ src->conv_ctx->extradata_size = pSourceFormat->cbSize; ++ if(pSourceFormat->cbSize){ ++ src->conv_ctx->extradata = HeapAlloc(GetProcessHeap(), 0, pSourceFormat->cbSize + AV_INPUT_BUFFER_PADDING_SIZE); ++ memcpy(src->conv_ctx->extradata, (&pSourceFormat->cbSize) + 1, pSourceFormat->cbSize); ++ }else if(IS_WMA(pSourceFormat->wFormatTag)){ ++ /* xWMA doesn't provide the extradata info that FFmpeg needs to ++ * decode WMA data, so we create some fake extradata. This is taken ++ * from . */ ++ TRACE("synthesizing extradata for xWMA\n"); ++ src->conv_ctx->extradata_size = 6; ++ src->conv_ctx->extradata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AV_INPUT_BUFFER_PADDING_SIZE); ++ src->conv_ctx->extradata[4] = 31; ++ } + +- src->submit_blocksize = pSourceFormat->nBlockAlign; ++ if(avcodec_open2(src->conv_ctx, codec, NULL) < 0){ ++ WARN("avcodec_open2 failed\n"); ++ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); ++ av_free(src->conv_ctx); ++ src->conv_ctx = NULL; ++ src->in_use = FALSE; ++ LeaveCriticalSection(&src->lock); ++ return AUDCLNT_E_UNSUPPORTED_FORMAT; ++ } ++ ++ src->conv_frame = av_frame_alloc(); ++ if(!src->conv_ctx){ ++ WARN("av_frame_alloc failed\n"); ++ avcodec_close(src->conv_ctx); ++ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); ++ av_free(src->conv_ctx); ++ src->conv_ctx = NULL; ++ src->in_use = FALSE; ++ LeaveCriticalSection(&src->lock); ++ return AUDCLNT_E_UNSUPPORTED_FORMAT; ++ } ++ ++ src->al_fmt = ffmpeg_to_al_fmt(src->conv_ctx->sample_fmt, pSourceFormat->nChannels); ++ if(!src->al_fmt){ ++ WARN("OpenAL can't use FFmpeg output format\n"); ++ av_frame_free(&src->conv_frame); ++ src->conv_frame = NULL; ++ avcodec_close(src->conv_ctx); ++ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); ++ av_free(src->conv_ctx); ++ src->conv_ctx = NULL; ++ src->in_use = FALSE; ++ LeaveCriticalSection(&src->lock); ++ return AUDCLNT_E_UNSUPPORTED_FORMAT; ++ } ++ ++ src->submit_blocksize = av_get_bytes_per_sample(src->conv_ctx->sample_fmt); ++ ++ src->scratch_bytes = This->period_frames * 1.5 * src->submit_blocksize; ++ src->scratch_buf = HeapAlloc(GetProcessHeap(), 0, src->scratch_bytes); ++ ++ src->convert_bytes = pSourceFormat->nBlockAlign + AV_INPUT_BUFFER_PADDING_SIZE; ++ src->convert_buf = HeapAlloc(GetProcessHeap(), 0, src->convert_bytes); ++#else ++ WARN("OpenAL can't use this format and no FFmpeg, so giving up\n"); ++#endif ++ }else ++ src->submit_blocksize = pSourceFormat->nBlockAlign; + + src->fmt = copy_waveformat(pSourceFormat); + + hr = XA2SRC_SetOutputVoices(&src->IXAudio2SourceVoice_iface, pSendList); + if(FAILED(hr)){ + HeapFree(GetProcessHeap(), 0, src->fmt); ++#if HAVE_FFMPEG ++ if(src->conv_ctx){ ++ av_frame_free(&src->conv_frame); ++ src->conv_frame = NULL; ++ avcodec_close(src->conv_ctx); ++ HeapFree(GetProcessHeap(), 0, src->conv_ctx->extradata); ++ av_free(src->conv_ctx); ++ src->conv_ctx = NULL; ++ } ++#endif + src->in_use = FALSE; + LeaveCriticalSection(&src->lock); + return hr; +@@ -2255,6 +2474,9 @@ HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR p + * buffer's data has all been queued */ + static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al_buf) + { ++#if HAVE_FFMPEG ++ int averr; ++#endif + UINT32 submit_bytes; + const BYTE *submit_buf = NULL; + +@@ -2263,9 +2485,133 @@ static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al + return FALSE; + } + +- submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes); +- submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes; +- buf->offs_bytes += submit_bytes; ++#if HAVE_FFMPEG ++ if(src->conv_ctx){ ++ DWORD scratch_offs_bytes = 0; ++ AVPacket avpkt = {0}; ++ ++ avpkt.size = src->fmt->nBlockAlign; ++ avpkt.data = (unsigned char*)buf->xa2buffer.pAudioData + buf->offs_bytes; ++ ++ /* convert at least a period into scratch_buf */ ++ while(scratch_offs_bytes < src->xa2->period_frames * src->submit_blocksize){ ++ DWORD to_copy_bytes; ++ ++ averr = avcodec_receive_frame(src->conv_ctx, src->conv_frame); ++ if(averr == AVERROR(EAGAIN)){ ++ /* ffmpeg needs more data to decode */ ++ avpkt.pts = avpkt.dts = AV_NOPTS_VALUE; ++ ++ if(buf->offs_bytes >= buf->cur_end_bytes) ++ /* no more data in this buffer */ ++ break; ++ ++ if(buf->offs_bytes + avpkt.size + AV_INPUT_BUFFER_PADDING_SIZE > buf->cur_end_bytes){ ++ UINT32 remain = buf->cur_end_bytes - buf->offs_bytes; ++ /* Unfortunately, the FFmpeg API requires that a number of ++ * extra bytes must be available past the end of the buffer. ++ * The xaudio2 client probably hasn't done this, so we have to ++ * perform a copy near the end of the buffer. */ ++ TRACE("hitting end of buffer. copying %u + %u bytes into %u buffer\n", ++ remain, AV_INPUT_BUFFER_PADDING_SIZE, src->convert_bytes); ++ if(src->convert_bytes < remain + AV_INPUT_BUFFER_PADDING_SIZE){ ++ src->convert_bytes = remain + AV_INPUT_BUFFER_PADDING_SIZE; ++ TRACE("buffer too small, expanding to %u\n", src->convert_bytes); ++ src->convert_buf = HeapReAlloc(GetProcessHeap(), 0, src->convert_buf, src->convert_bytes); ++ } ++ memcpy(src->convert_buf, buf->xa2buffer.pAudioData + buf->offs_bytes, remain); ++ memset(src->convert_buf + remain, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ avpkt.data = src->convert_buf; ++ } ++ ++ averr = avcodec_send_packet(src->conv_ctx, &avpkt); ++ if(averr){ ++ WARN("avcodec_send_packet failed: %s\n", av_err2str(averr)); ++ break; ++ } ++ ++ buf->offs_bytes += avpkt.size; ++ avpkt.data += avpkt.size; ++ ++ /* data sent, try receive again */ ++ continue; ++ } ++ ++ if(averr){ ++ WARN("avcodec_receive_frame failed: %s\n", av_err2str(averr)); ++ return TRUE; ++ } ++ ++ to_copy_bytes = src->conv_frame->nb_samples * src->conv_ctx->channels * src->submit_blocksize; ++ ++ while(scratch_offs_bytes + to_copy_bytes >= src->scratch_bytes){ ++ src->scratch_bytes *= 2; ++ src->scratch_buf = HeapReAlloc(GetProcessHeap(), 0, src->scratch_buf, src->scratch_bytes); ++ } ++ ++ if(av_sample_fmt_is_planar(src->conv_ctx->sample_fmt)){ ++ int s, c; ++ uint8_t **source, *dst; ++ uint16_t *dst16; ++ uint32_t *dst32; ++ uint64_t *dst64; ++ ++ /* one buffer per channel, but openal needs interleaved, so ++ * interleave samples into scratch buf */ ++ dst = src->scratch_buf + scratch_offs_bytes; ++ source = src->conv_frame->data; ++ ++ switch(src->submit_blocksize){ ++ case 1: ++ for(s = 0; s < src->conv_frame->nb_samples; ++s) ++ for(c = 0; c < src->conv_ctx->channels; ++c) ++ *(dst++) = source[c][s]; ++ break; ++ case 2: ++ dst16 = (uint16_t*)dst; ++ for(s = 0; s < src->conv_frame->nb_samples; ++s) ++ for(c = 0; c < src->conv_ctx->channels; ++c) ++ *(dst16++) = ((uint16_t*)(source[c]))[s]; ++ break; ++ case 4: ++ dst32 = (uint32_t*)dst; ++ for(s = 0; s < src->conv_frame->nb_samples; ++s) ++ for(c = 0; c < src->conv_ctx->channels; ++c) ++ *(dst32++) = ((uint32_t*)(source[c]))[s]; ++ break; ++ case 8: ++ dst64 = (uint64_t*)dst; ++ for(s = 0; s < src->conv_frame->nb_samples; ++s) ++ for(c = 0; c < src->conv_ctx->channels; ++c) ++ *(dst64++) = ((uint64_t*)(source[c]))[s]; ++ break; ++ default: ++ for(s = 0; s < src->conv_frame->nb_samples; ++s) ++ for(c = 0; c < src->conv_ctx->channels; ++c){ ++ memcpy(dst, &source[c][src->submit_blocksize * s], src->submit_blocksize); ++ dst += src->submit_blocksize; ++ } ++ break; ++ } ++ ++ scratch_offs_bytes += to_copy_bytes; ++ }else{ ++ /* copy into scratch buf */ ++ memcpy(src->scratch_buf + scratch_offs_bytes, src->conv_frame->data[0], to_copy_bytes); ++ scratch_offs_bytes += to_copy_bytes; ++ } ++ } ++ ++ submit_bytes = scratch_offs_bytes; ++ submit_buf = src->scratch_buf; ++ }else{ ++#endif ++ submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes); ++ submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes; ++ buf->offs_bytes += submit_bytes; ++#if HAVE_FFMPEG ++ } ++#endif + + alBufferData(al_buf, src->al_fmt, submit_buf, submit_bytes, + src->fmt->nSamplesPerSec); +@@ -2288,6 +2634,10 @@ static UINT32 get_underrun_warning(XA2SourceImpl *src) + UINT32 period_bytes = src->xa2->period_frames * src->submit_blocksize; + UINT32 total = 0, i; + ++ if(IS_WMA(src->fmt->wFormatTag)) ++ /* PCM only */ ++ return 0; ++ + for(i = 0; i < src->nbufs && total < IN_AL_PERIODS * period_bytes; ++i){ + XA2Buffer *buf = &src->buffers[(src->first_buf + i) % XAUDIO2_MAX_QUEUED_BUFFERS]; + total += buf->cur_end_bytes - buf->offs_bytes; +diff --git a/dlls/xaudio2_7/xaudio_private.h b/dlls/xaudio2_7/xaudio_private.h +index 5d3814f..9cf7f00 100644 +--- a/dlls/xaudio2_7/xaudio_private.h ++++ b/dlls/xaudio2_7/xaudio_private.h +@@ -29,6 +29,10 @@ + #include "mmdeviceapi.h" + #include "audioclient.h" + ++#if HAVE_FFMPEG ++#include ++#endif ++ + #include + #include + #include +@@ -83,6 +87,11 @@ typedef struct _XA2SourceImpl { + ALuint al_bufs[XAUDIO2_MAX_QUEUED_BUFFERS]; + DWORD first_al_buf, al_bufs_used, abandoned_albufs; + ++#if HAVE_FFMPEG ++ AVCodecContext *conv_ctx; ++ AVFrame *conv_frame; ++#endif ++ + struct list entry; + } XA2SourceImpl; + +diff --git a/dlls/xaudio2_8/Makefile.in b/dlls/xaudio2_8/Makefile.in +index d4efc41..017bff8 100644 +--- a/dlls/xaudio2_8/Makefile.in ++++ b/dlls/xaudio2_8/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=8 + MODULE = xaudio2_8.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/dlls/xaudio2_9/Makefile.in b/dlls/xaudio2_9/Makefile.in +index ceb2216..cf68947 100644 +--- a/dlls/xaudio2_9/Makefile.in ++++ b/dlls/xaudio2_9/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -DXAUDIO2_VER=9 + MODULE = xaudio2_9.dll + IMPORTS = advapi32 ole32 user32 uuid +-EXTRALIBS = $(OPENAL_LIBS) ++EXTRALIBS = $(OPENAL_LIBS) $(LIBAVCODEC_LIBS) $(LIBAVUTIL_LIBS) + PARENTSRC = ../xaudio2_7 + + C_SRCS = \ +diff --git a/include/config.h.in b/include/config.h.in +index c3247cb..7067a10 100644 +--- a/include/config.h.in ++++ b/include/config.h.in +@@ -408,6 +408,15 @@ + /* Define to 1 if you have the `lgammaf' function. */ + #undef HAVE_LGAMMAF + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_LIBAVCODEC_AVCODEC_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_LIBAVUTIL_AVUTIL_H ++ ++/* Define to 1 if you have libavutil and libavcodec from ffmpeg. */ ++#undef HAVE_FFMPEG ++ + /* Define to 1 if you have the `gettextpo' library (-lgettextpo). */ + #undef HAVE_LIBGETTEXTPO + +diff --git a/include/mmreg.h b/include/mmreg.h +index 8bb581d..1214dfa 100644 +--- a/include/mmreg.h ++++ b/include/mmreg.h +@@ -110,6 +110,11 @@ typedef struct _WAVEFORMATEX { + #define WAVE_FORMAT_MPEG 0x0050 /* Microsoft Corporation */ + #define WAVE_FORMAT_MPEGLAYER3 0x0055 + #define WAVE_FORMAT_MSRT24 0x0082 /* Microsoft Corporation */ ++#define WAVE_FORMAT_MSAUDIO1 0x0160 ++#define WAVE_FORMAT_WMAUDIO2 0x0161 ++#define WAVE_FORMAT_WMAUDIO3 0x0162 ++#define WAVE_FORMAT_WMAUDIO_LOSSLESS 0x0163 ++ + #define WAVE_FORMAT_CREATIVE_ADPCM 0x0200 /* Creative Labs, Inc */ + #define WAVE_FORMAT_CREATIVE_FASTSPEECH8 0x0202 /* Creative Labs, Inc */ + #define WAVE_FORMAT_CREATIVE_FASTSPEECH10 0x0203 /* Creative Labs, Inc */ +-- +1.9.1 + diff --git a/patches/xaudio2_7-WMA_support/definition b/patches/xaudio2_7-WMA_support/definition new file mode 100644 index 00000000..0d503654 --- /dev/null +++ b/patches/xaudio2_7-WMA_support/definition @@ -0,0 +1 @@ +Fixes: [39402] Use ffmpeg 4.x to convert WMA format