mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Dynamically load Media Foundation
This commit is contained in:
		
							parent
							
								
									4efb9c6d99
								
							
						
					
					
						commit
						b395efe804
					
				
					 4 changed files with 166 additions and 5 deletions
				
			
		|  | @ -45,7 +45,9 @@ if(ENABLE_MF) | |||
|         hle/wmf_decoder_utils.cpp | ||||
|         hle/wmf_decoder_utils.h | ||||
|     ) | ||||
|     target_link_libraries(audio_core PRIVATE mf.lib mfplat.lib mfuuid.lib) | ||||
|     # We dynamically load the required symbols from mf.dll and mfplat.dll but mfuuid is not a dll | ||||
|     # just a static library of GUIDS so include that one directly. | ||||
|     target_link_libraries(audio_core PRIVATE mfuuid.lib) | ||||
|     target_compile_definitions(audio_core PUBLIC HAVE_MF) | ||||
| elseif(ENABLE_FFMPEG_AUDIO_DECODER) | ||||
|     target_sources(audio_core PRIVATE | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ | |||
| 
 | ||||
| namespace AudioCore::HLE { | ||||
| 
 | ||||
| using namespace MFDecoder; | ||||
| 
 | ||||
| class WMFDecoder::Impl { | ||||
| public: | ||||
|     explicit Impl(Memory::MemorySystem& memory); | ||||
|  | @ -31,6 +33,13 @@ private: | |||
| }; | ||||
| 
 | ||||
| WMFDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) { | ||||
|     // Attempt to load the symbols for mf.dll
 | ||||
|     if (!InitMFDLL()) { | ||||
|         LOG_CRITICAL(Audio_DSP, | ||||
|                      "Unable to load mf.dll. AAC audio through media foundation unavailable"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     HRESULT hr = S_OK; | ||||
|     hr = CoInitialize(NULL); | ||||
|     // S_FALSE will be returned when COM has already been initialized
 | ||||
|  | @ -39,7 +48,7 @@ WMFDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) { | |||
|     } | ||||
| 
 | ||||
|     // lite startup is faster and all what we need is included
 | ||||
|     hr = MFStartup(MF_VERSION, MFSTARTUP_LITE); | ||||
|     hr = MFDecoder::MFStartup(MF_VERSION, MFSTARTUP_LITE); | ||||
|     if (hr != S_OK) { | ||||
|         // Do you know you can't initialize MF in test mode or safe mode?
 | ||||
|         ReportError("Failed to initialize Media Foundation", hr); | ||||
|  | @ -73,7 +82,7 @@ WMFDecoder::Impl::~Impl() { | |||
|         // otherwise access violation will occur
 | ||||
|         transform.reset(); | ||||
|     } | ||||
|     MFShutdown(); | ||||
|     MFDecoder::MFShutdown(); | ||||
|     CoUninitialize(); | ||||
| } | ||||
| 
 | ||||
|  | @ -112,8 +121,8 @@ std::optional<BinaryResponse> WMFDecoder::Impl::Initalize(const BinaryRequest& r | |||
|     return response; | ||||
| } | ||||
| 
 | ||||
| MFOutputState WMFDecoder::Impl::DecodingLoop(ADTSData adts_header, | ||||
|                                              std::array<std::vector<u8>, 2>& out_streams) { | ||||
| MFDecoder::MFOutputState WMFDecoder::Impl::DecodingLoop( | ||||
|     ADTSData adts_header, std::array<std::vector<u8>, 2>& out_streams) { | ||||
|     MFOutputState output_status = MFOutputState::OK; | ||||
|     std::optional<std::vector<f32>> output_buffer; | ||||
|     unique_mfptr<IMFSample> output; | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ | |||
| #include "common/string_util.h" | ||||
| #include "wmf_decoder_utils.h" | ||||
| 
 | ||||
| namespace MFDecoder { | ||||
| 
 | ||||
| // utility functions
 | ||||
| void ReportError(std::string msg, HRESULT hr) { | ||||
|     if (SUCCEEDED(hr)) { | ||||
|  | @ -26,6 +28,7 @@ void ReportError(std::string msg, HRESULT hr) { | |||
| } | ||||
| 
 | ||||
| unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format) { | ||||
| 
 | ||||
|     HRESULT hr = S_OK; | ||||
|     MFT_REGISTER_TYPE_INFO reg = {0}; | ||||
|     GUID category = MFT_CATEGORY_AUDIO_DECODER; | ||||
|  | @ -347,3 +350,112 @@ std::optional<std::vector<f32>> CopySampleToBuffer(IMFSample* sample) { | |||
|     buffer->Unlock(); | ||||
|     return output; | ||||
| } | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| struct LibraryDeleter { | ||||
|     using pointer = HMODULE; | ||||
|     void operator()(HMODULE h) const { | ||||
|         if (h != nullptr) | ||||
|             FreeLibrary(h); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| std::unique_ptr<HMODULE, LibraryDeleter> mf_dll{nullptr}; | ||||
| std::unique_ptr<HMODULE, LibraryDeleter> mfplat_dll{nullptr}; | ||||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| bool InitMFDLL() { | ||||
| 
 | ||||
|     mf_dll.reset(LoadLibrary(TEXT("mf.dll"))); | ||||
|     if (!mf_dll) { | ||||
|         DWORD error_message_id = GetLastError(); | ||||
|         LPSTR message_buffer = nullptr; | ||||
|         size_t size = | ||||
|             FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | | ||||
|                                FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
|                            nullptr, error_message_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
|                            reinterpret_cast<LPSTR>(&message_buffer), 0, nullptr); | ||||
| 
 | ||||
|         std::string message(message_buffer, size); | ||||
| 
 | ||||
|         LocalFree(message_buffer); | ||||
|         LOG_ERROR(Audio_DSP, "Could not load mf.dll: {}", message); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     mfplat_dll.reset(LoadLibrary(TEXT("mfplat.dll"))); | ||||
|     if (!mfplat_dll) { | ||||
|         DWORD error_message_id = GetLastError(); | ||||
|         LPSTR message_buffer = nullptr; | ||||
|         size_t size = | ||||
|             FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | | ||||
|                                FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
|                            nullptr, error_message_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
|                            reinterpret_cast<LPSTR>(&message_buffer), 0, nullptr); | ||||
| 
 | ||||
|         std::string message(message_buffer, size); | ||||
| 
 | ||||
|         LocalFree(message_buffer); | ||||
|         LOG_ERROR(Audio_DSP, "Could not load mfplat.dll: {}", message); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     MFStartup = Symbol<HRESULT(ULONG, DWORD)>(mfplat_dll.get(), "MFStartup"); | ||||
|     if (!MFStartup) { | ||||
|         LOG_ERROR(Audio_DSP, "Cannot load function MFStartup"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     MFShutdown = Symbol<HRESULT(void)>(mfplat_dll.get(), "MFShutdown"); | ||||
|     if (!MFShutdown) { | ||||
|         LOG_ERROR(Audio_DSP, "Cannot load function MFShutdown"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     MFShutdownObject = Symbol<HRESULT(IUnknown*)>(mf_dll.get(), "MFShutdownObject"); | ||||
|     if (!MFShutdownObject) { | ||||
|         LOG_ERROR(Audio_DSP, "Cannot load function MFShutdownObject"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     MFCreateAlignedMemoryBuffer = Symbol<HRESULT(DWORD, DWORD, IMFMediaBuffer**)>( | ||||
|         mfplat_dll.get(), "MFCreateAlignedMemoryBuffer"); | ||||
|     if (!MFCreateAlignedMemoryBuffer) { | ||||
|         LOG_ERROR(Audio_DSP, "Cannot load function MFCreateAlignedMemoryBuffer"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     MFCreateSample = Symbol<HRESULT(IMFSample**)>(mfplat_dll.get(), "MFCreateSample"); | ||||
|     if (!MFCreateSample) { | ||||
|         LOG_ERROR(Audio_DSP, "Cannot load function MFCreateSample"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     MFTEnumEx = | ||||
|         Symbol<HRESULT(GUID, UINT32, const MFT_REGISTER_TYPE_INFO*, const MFT_REGISTER_TYPE_INFO*, | ||||
|                        IMFActivate***, UINT32*)>(mfplat_dll.get(), "MFTEnumEx"); | ||||
|     if (!MFTEnumEx) { | ||||
|         LOG_ERROR(Audio_DSP, "Cannot load function MFTEnumEx"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     MFCreateMediaType = Symbol<HRESULT(IMFMediaType**)>(mfplat_dll.get(), "MFCreateMediaType"); | ||||
|     if (!MFCreateMediaType) { | ||||
|         LOG_ERROR(Audio_DSP, "Cannot load function MFCreateMediaType"); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Symbol<HRESULT(ULONG, DWORD)> MFStartup; | ||||
| Symbol<HRESULT(void)> MFShutdown; | ||||
| Symbol<HRESULT(IUnknown*)> MFShutdownObject; | ||||
| Symbol<HRESULT(DWORD, DWORD, IMFMediaBuffer**)> MFCreateAlignedMemoryBuffer; | ||||
| Symbol<HRESULT(IMFSample**)> MFCreateSample; | ||||
| Symbol<HRESULT(GUID, UINT32, const MFT_REGISTER_TYPE_INFO*, const MFT_REGISTER_TYPE_INFO*, | ||||
|                IMFActivate***, UINT32*)> | ||||
|     MFTEnumEx; | ||||
| Symbol<HRESULT(IMFMediaType**)> MFCreateMediaType; | ||||
| 
 | ||||
| } // namespace MFDecoder
 | ||||
|  |  | |||
|  | @ -18,6 +18,39 @@ | |||
| 
 | ||||
| #include "adts.h" | ||||
| 
 | ||||
| namespace MFDecoder { | ||||
| 
 | ||||
| template <typename T> | ||||
| struct Symbol { | ||||
|     Symbol() = default; | ||||
|     Symbol(HMODULE dll, const char* name) { | ||||
|         if (dll) { | ||||
|             ptr_symbol = reinterpret_cast<T*>(GetProcAddress(dll, name)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     operator T*() const { | ||||
|         return ptr_symbol; | ||||
|     } | ||||
| 
 | ||||
|     explicit operator bool() const { | ||||
|         return ptr_symbol != nullptr; | ||||
|     } | ||||
| 
 | ||||
|     T* ptr_symbol = nullptr; | ||||
| }; | ||||
| 
 | ||||
| // Runtime load the MF symbols to prevent mf.dll not found errors on citra load
 | ||||
| extern Symbol<HRESULT(ULONG, DWORD)> MFStartup; | ||||
| extern Symbol<HRESULT(void)> MFShutdown; | ||||
| extern Symbol<HRESULT(IUnknown*)> MFShutdownObject; | ||||
| extern Symbol<HRESULT(DWORD, DWORD, IMFMediaBuffer**)> MFCreateAlignedMemoryBuffer; | ||||
| extern Symbol<HRESULT(IMFSample**)> MFCreateSample; | ||||
| extern Symbol<HRESULT(GUID, UINT32, const MFT_REGISTER_TYPE_INFO*, const MFT_REGISTER_TYPE_INFO*, | ||||
|                       IMFActivate***, UINT32*)> | ||||
|     MFTEnumEx; | ||||
| extern Symbol<HRESULT(IMFMediaType**)> MFCreateMediaType; | ||||
| 
 | ||||
| enum class MFOutputState { FatalError, OK, NeedMoreInput, NeedReconfig, HaveMoreData }; | ||||
| enum class MFInputState { FatalError, OK, NotAccepted }; | ||||
| 
 | ||||
|  | @ -73,6 +106,9 @@ struct ADTSMeta { | |||
| }; | ||||
| 
 | ||||
| // exported functions
 | ||||
| 
 | ||||
| /// Loads the symbols from mf.dll at runtime. Returns false if the symbols can't be loaded
 | ||||
| bool InitMFDLL(); | ||||
| unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format = MFAudioFormat_AAC); | ||||
| unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignment = 1, | ||||
|                                      LONGLONG duration = 0); | ||||
|  | @ -87,3 +123,5 @@ MFInputState SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* | |||
| std::tuple<MFOutputState, unique_mfptr<IMFSample>> ReceiveSample(IMFTransform* transform, | ||||
|                                                                  DWORD out_stream_id); | ||||
| std::optional<std::vector<f32>> CopySampleToBuffer(IMFSample* sample); | ||||
| 
 | ||||
| } // namespace MFDecoder
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue