diff --git a/CMakeLists.txt b/CMakeLists.txt index 995cfe2..3dcb392 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -635,7 +635,7 @@ add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES}) # do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break target_link_libraries(spicetools_spice64 PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp mfuuid strmiids dxva2 - PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features mf mfplat mfreadwrite) + PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features) set_target_properties(spicetools_spice64 PROPERTIES PREFIX "") set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64") diff --git a/hooks/bmsbhook.cpp b/hooks/bmsbhook.cpp index ad40935..b67baf7 100644 --- a/hooks/bmsbhook.cpp +++ b/hooks/bmsbhook.cpp @@ -7,13 +7,6 @@ #include "avs/core.h" #include -//_BUG: manual symbol lookup, should not link against: mf, mfplat, mfreadwrite -#include -#include -#include -#include -#include - void dump_(const char *path, const uint8_t *src, size_t sz) { @@ -90,13 +83,22 @@ void deinit() } } -// This implementation replicates wine MF wma=>wav playback bug 1:1, follows https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/multimedia/mediafoundation/AudioClip/main.cpp +// Replicates wine MF wma=>wav playback bug 1:1, follows https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/multimedia/mediafoundation/AudioClip/main.cpp +#include +#include +#include +#include +#include namespace hooks::bmsb::mf_broken { - typedef HRESULT (*MFCreateMFByteStreamOnStream_t)(IStream *, IMFByteStream **); +typedef HRESULT (*MFCreateSourceReaderFromByteStream_t)(IMFByteStream *, IMFAttributes *, IMFSourceReader **); +typedef HRESULT (*MFStartup_t)(ULONG, DWORD); +typedef HRESULT (*MFShutdown_t)(); MFCreateMFByteStreamOnStream_t MFCreateMFByteStreamOnStream; - +MFCreateSourceReaderFromByteStream_t MFCreateSourceReaderFromByteStream; +MFStartup_t MFStartup; +MFShutdown_t MFShutdown; struct wav_hdr { char sig_riff[4] = {'R', 'I', 'F', 'F'}; @@ -180,7 +182,6 @@ HRESULT asf_unpack_pcm_s16le(BYTE *dst, IMFSourceReader *srcreader, uint32_t szm *sz = srcpos; return hr; } - HRESULT asf_to_wav(const BYTE *srcasf, uint32_t srcsz, BYTE **dstwav, uint32_t *dstsz) { HRESULT hr = S_OK; @@ -200,9 +201,15 @@ HRESULT asf_to_wav(const BYTE *srcasf, uint32_t srcsz, BYTE **dstwav, uint32_t * PROPVARIANT duration; srcreader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &mediatype); srcreader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &duration); + #ifdef _WIN64 mediatype->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &a); mediatype->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &b); mediatype->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &c); + #else + a = 2; + b = 44100; + c = 16; + #endif wav_hdr dsthdr = { .channels=static_cast(a), .samplerate=b, @@ -227,22 +234,23 @@ HRESULT asf_to_wav(const BYTE *srcasf, uint32_t srcsz, BYTE **dstwav, uint32_t * shstream->Release(); return hr; } - bool init() { - HMODULE mfdll = libutils::try_library("Mfplat.dll"); - if (!mfdll) return false; + HMODULE mf_ = libutils::try_library("mf.dll"); + HMODULE mfreadwrite_ = libutils::try_library("mfreadwrite.dll"); + HMODULE mfplat_ = libutils::try_library("mfplat.dll"); + if (!mf_ || !mfreadwrite_ || !mfplat_) return false; - // Missing in includes - MFCreateMFByteStreamOnStream = (MFCreateMFByteStreamOnStream_t) GetProcAddress(mfdll, "MFCreateMFByteStreamOnStream"); + // Required by linker + MFCreateMFByteStreamOnStream = (MFCreateMFByteStreamOnStream_t) GetProcAddress(mfplat_, "MFCreateMFByteStreamOnStream"); + MFStartup = (MFStartup_t) GetProcAddress(mfplat_, "MFStartup"); + MFShutdown = (MFShutdown_t) GetProcAddress(mfplat_, "MFShutdown"); + MFCreateSourceReaderFromByteStream = (MFCreateSourceReaderFromByteStream_t) GetProcAddress(mfreadwrite_, "MFCreateSourceReaderFromByteStream"); - // MF init checks - if (!MFCreateMFByteStreamOnStream || FAILED(MFStartup(MF_VERSION))) + if (!MFCreateMFByteStreamOnStream || !MFCreateSourceReaderFromByteStream || !MFStartup || !MFShutdown || FAILED(MFStartup(MF_VERSION, MFSTARTUP_FULL))) return false; - return true; } - void deinit() { MFShutdown(); @@ -777,20 +785,30 @@ void run_tests() size_t szs3p; BYTE *wav = nullptr; uint32_t wavsz = 0; - char sig[5]; - sig[4] = '\0'; - int id = 29095; + char avspath[AVSPATHMAX]; + avs::core::avs_file_t avsmnt = 0; + char sig[5] = " "; + int id = 25073; + if (!mf_broken::init()) + { + log_warning("hooks::bmsb", "MF initialization failed, skipping.."); + } - #if 0 - // s3p/2dx un/packing and wma=>wav transcoder - char sndpath[64]; - snprintf(sndpath, 64, "%05d/%05d", id, id); - char *bufs3p = soundbank::read_bank_any(sndpath, ".s3p", &szs3p); + // Filesystem tests, s3p unpacking + snprintf(avspath, sizeof(avspath), "data/sound/%05d", id); + if (soundbank::has_format(avspath, ".ifs")) avsmnt = soundbank::map_ifs(avspath); + snprintf(avspath + strlen(avspath), 7, "/%05d", id); + soundbank::has_format(avspath, ".s3p"); + soundbank::has_format(avspath, ".2dx"); + soundbank::has_format(avspath, "_pre.2dx"); + uint8_t *bufs3p = soundbank::read_bank_any(avspath, ".s3p", &szs3p); snd_s3p *snds3p = snd_s3p::unpack(bufs3p); + if (avsmnt) avs::core::avs_fs_umount(avsmnt); + + // S3P => WMA => WAV => 2DX pipeline if (snds3p) { - // S3P/S3V - log_info("hooks:bmsb", "s3p(25073/25006)? => ({}/{})", soundbank::has_format(sndpath, ".s3p"), soundbank::has_format("25006/25006", ".s3p")); + // S3P/S3V metadata memcpy(sig, snds3p->header()->sig, 4); log_info("hooks:bmsb", "{}::Bank[S3P]::Signature {}", id, sig); log_info("hooks:bmsb", "{}::Bank[S3P]::Size {}", id, szs3p); @@ -833,27 +851,15 @@ void run_tests() } // Valid 2DX (trim is not necessary) - log_info("hooks:bmsb", "25073::Bank[2DX]::Dumping"); + log_info("hooks:bmsb", "{}::Bank[2DX]::Dumping", id); snd_2dx::bank *buf2dx = snd2dx->serialize(false); - dump_("ac_25073.2dx", reinterpret_cast(buf2dx), buf2dx->sz()); + dump_("ac_soundbank.2dx", reinterpret_cast(buf2dx), buf2dx->sz()); } else { log_info("hooks:bmsb", "Tests failed"); } - #endif - - char avspath[AVSPATHMAX] = "data/sound/29095"; - soundbank::has_format(avspath, ".ifs"); - avs::core::avs_file_t mnt = soundbank::map_ifs(avspath); - strcat(avspath, "/29095"); - soundbank::has_format(avspath, ".s3p"); - soundbank::has_format(avspath, ".2dx"); - soundbank::has_format(avspath, "_pre.2dx"); - avs::core::avs_fs_umount(mnt); - - return; // Caching and intermediate 2dx storage detection BmsbEnumValidSoundbanks_t t = BmsbEnumValidSoundbanks; @@ -867,10 +873,11 @@ void run_tests() *(int32_t *) (tmp + 0x3b0) = it; on_enum_valid_soundbanks(tmp, 3, 0); } + free(tmp); BmsbEnumValidSoundbanks = t; soundbank::flush_cache(); - + mf_broken::deinit(); } void init(HINSTANCE hmodule, const char *ext) @@ -880,10 +887,6 @@ void init(HINSTANCE hmodule, const char *ext) log_warning("hooks::bmsb", "Debugger detected, skipping.."); return; } - if (!mf_broken::init()) - { - log_warning("hooks::bmsb", "MF initialization failed, skipping.."); - } if (!avcodec::init()) { log_warning("hooks::bmsb", "AVCodec initialization failed, skipping.."); @@ -945,9 +948,8 @@ void init(HINSTANCE hmodule, const char *ext) // Tests _REM: tests detour::trampoline(reinterpret_cast(avs::core::avs_fs_lstat), reinterpret_cast(on_avs_fs_lstat), reinterpret_cast(&avs_fs_lstat_)); detour::trampoline(reinterpret_cast(avs::core::avs_fs_mount), reinterpret_cast(on_avs_fs_mount), reinterpret_cast(&avs_fs_mount_)); - if (offset_t::by_ext(ext) == offset_t::by_ext("2023090500")) + if (getenv("SPICE_TESTING") && offset_t::by_ext(ext) == offset_t::by_ext("2023090500")) run_tests(); - } void deinit(HINSTANCE hmodule) @@ -956,7 +958,6 @@ void deinit(HINSTANCE hmodule) soundbank::flush_cache(); delete offset_.guard; - mf_broken::deinit(); } } \ No newline at end of file